如何将裸 git 存储库转换为普通存储库(就地)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10637378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 13:43:03  来源:igfitidea点击:

How do I convert a bare git repository into a normal one (in-place)?

gitgit-bare

提问by nyi

I have a bare git repository, but need to access and browse its contents over ssh (in a file manager like user experience).

我有一个裸 git 存储库,但需要通过 ssh 访问和浏览其内容(在用户体验等文件管理器中)。

I assume I could clone it:

我想我可以克隆它:

git clone -l <path_to_bare_repo> <new_normal_repo>

However, my repository is about 20GB in size and I don't have the space to duplicate it. Is there a way to convert the bare repository in-place to end up with a working copy in it?

但是,我的存储库大小约为 20GB,我没有空间来复制它。有没有办法就地转换裸存储库以在其中生成工作副本?

回答by simont

Note: I tested this on a very simple1-commit repository. Double-check this, read the man pages, and always be happy you've backed up before following advice you found on StackOverflow. (You do back up, right?)

注意:我在一个非常简单的1-commit 存储库上对此进行了测试。仔细检查这一点,阅读手册页,并在遵循您在 StackOverflow 上找到的建议之前始终为您已备份感到高兴。(你确实备份,对吧?)

To convert a --barerepository to a non-bare:

要将--bare存储库转换为非裸存储库:

  1. Make a .gitfolder in the top-level of your repository.
  2. Move the repository management things (HEAD branches config description hooks info objects refsetc.) into the .gityou just created.
  3. Run git config --local --bool core.bare falseto convert the local git-repository to non-bare.
  4. (via comment by Tamás Pap)After step #3 you will see that you are on branch master(or whichever your main branch is) and all your files are deleted and the deletion is staged. That's normal. Just manually checkout master, or do a git reset --hard, and you are done.
  5. (to resolve issue reported by Royi)Edit .git/configfile adding line fetch = +refs/heads/*:refs/remotes/origin/*after url = <...>in [remote "origin"]section. Otherwise git fetchwill not see origin/masterand other origin's branches.
  1. .git在存储库的顶层创建一个文件夹。
  2. 将存储库管理的东西(HEAD branches config description hooks info objects refs等等)移动到.git你刚刚创建的。
  3. 运行git config --local --bool core.bare false以将本地 git-repository 转换为非裸。
  4. (通过Tamás Pap 的评论)在第 3 步之后,您将看到您在分支上master(或您的主分支所在的任何一个),并且您的所有文件都被删除并进行了删除。这是正常的。只需手动 checkout master,或者做一个git reset --hard,你就完成了。
  5. (解决Royi报告的问题)编辑.git/config文件fetch = +refs/heads/*:refs/remotes/origin/*url = <...>in[remote "origin"]部分后添加行。否则git fetch将看不到origin/master和其他起源的分支。

These steps are in the opposite direction of this question, "git-convert normal to bare repository" - in particular note this answer, which states that the above steps (in, I presume, either direction) is differentfrom doing a git-clone. Not sure if that's relevant to you, though, but you mentioned git clonein the question.

这些步骤与这个问题的方向相反,“git-convert normal to bare repository” - 特别注意这个答案,它指出上述步骤(我认为,任一方向)与执行.gitignore不同git-clone。不过,不确定这是否与您相关,但您git clone在问题中提到了。

回答by VonC

I had a slightly different scenario:

我有一个稍微不同的场景:

Solution:

解决方案:

  • clone a bare repo in that content, in a .gitdir:
    git clone --bare https://github.com/user/project .git
  • Mark it as a non-bare repo:
    git config --local --bool core.bare false
  • reset the index (otherwise, it believes everything has been deleted, since a .gitbarerepo doesn't include a file 'index'.)
    git reset HEAD -- .
    That restores the .git/index.
  • .git目录中克隆该内容中的裸仓库:
    git clone --bare https://github.com/user/project .git
  • 将其标记为非裸仓库:
    git config --local --bool core.bare false
  • 重置索引(否则,它认为所有内容都已删除,因为.git裸存储库不包含文件“ index”。)
    git reset HEAD -- .
    这会恢复.git/index.

I have effectively transformed a bare repo into a non-bare one, while preserving the content I had previously got.
The full scriptI have been using for years involves the steps:

我已经有效地将一个裸存储库转换为非裸存储库,同时保留了我之前获得的内容。我多年来一直使用
完整脚本包括以下步骤:

cd /path/to/current/worktree

# That creates a .git directly at the right place
git clone --bare /url/of/repo .git

# restore the link between the local repo and its upstream remote repo
git config --local --bool core.bare false
git config --local remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
git fetch origin
git branch -u origin/master master

# reset the index (not the working tree)
git reset HEAD -- .

But I do recon the accepted solution(with the helpful git resetstep addedby ADTC) is simpler.

但我确实认为接受的解决方案(通过ADTC添加有用git reset步骤)更简单。

回答by fuzzyTew

To simplify and combine the information in the answers:

为了简化和组合答案中的信息:

There are three differences that make a bare repo different from a normal .git folder:

裸仓库与普通 .git 文件夹的三个不同之处在于:

  • core.bare is set to true in config file
  • index file and working tree do not in exist
  • a default refspec for the "origin" remote is not generated
  • core.bare 在配置文件中设置为 true
  • 索引文件和工作树不存在
  • 未生成“原点”遥控器的默认 refspec

So, you can simply move your bare repo to be the .git subfolder of a new folder,

因此,您可以简单地将您的裸仓库移动到新文件夹的 .git 子文件夹中,

mkdir clone
mv bare.git clone/.git

Change core.bare:

更改 core.bare:

cd clone
git config --local --bool core.bare false

Add a default origin refspec to make git fetchand git pushpick the same defaults as usual:

添加一个默认的 origin refspec 来制作git fetchgit push选择与往常相同的默认值:

git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'

And generate the index file and working tree:

并生成索引文件和工作树:

git checkout master

I recommend git checkoutrather than git resetto generate the files, in case it is accidentally typed into the wrong place.

我建议git checkout不要git reset生成文件,以防不小心将其输入到错误的位置。

回答by sarnold

The original poster's question is about not having enough space to do things the simple way. For those that do have enough space, the answer is far simpler:

原始海报的问题是没有足够的空间以简单的方式做事。对于那些确实有足够空间的人,答案要简单得多:

git clone foo.git foo

回答by William Pursell

If you are low on diskspace, expanding the working tree by converting to a normal repository will be an issue, but you can browse the contents of a bare repo without converting it. Use git cat-file -p <commit-sha>on any commit to see the tree to which it refers. Use git cat-file -p <blob-sha>to see the contents of the file referenced by the blob. Use git show <sha>:pathwhere sha is either a commit or a tree to see the contents of the blob at path.

如果您的磁盘空间不足,通过转换为普通存储库来扩展工作树将是一个问题,但您可以浏览裸存储库的内容而无需转换它。git cat-file -p <commit-sha>在任何提交上使用以查看它所引用的树。使用git cat-file -p <blob-sha>查看由BLOB引用的文件的内容。使用git show <sha>:pathwhere sha 是提交或树来查看路径中 blob 的内容。

回答by nPcomp

cdinto bare repo and do

cd进入裸回购并做

  1. Either:
  1. 任何一个:
git config core.bare false
git reset --hard
  1. or
  1. 或者
git clone X.git X

(will give you regular git repo that named X)

(会给你一个名为 X 的常规 git repo)

回答by Boaz Nahum

If you don't mind working on different worktree , then

如果你不介意在不同的工作树上工作,那么

git worktree add ../repo2
cd ..
git status # now works fine

Please note, this is not a clone.

请注意,这不是克隆。

回答by Isaac Brown

Push-to-Deploy

一键部署

Rather than convert the bare remote into a standard repository, you can use the post-receive script in the hooks directory to expand the repository into a deployment directory.

您可以使用 hooks 目录中的 post-receive 脚本将存储库扩展为部署目录,而不是将裸远程转换为标准存储库。

Here is a good example of setting up Push-to-Deploy

这是设置 Push-to-Deploy 的一个很好的例子

For ease of reference, this is the script contents example from the above link. It will deploy only pushes from "master" branch to a directory named "deploy" that is on the same level as the parent directory of the repository:

为便于参考,这是上述链接中的脚本内容示例。它只会将推送从“master”分支部署到名为“deploy”的目录,该目录与存储库的父目录处于同一级别:

#!/usr/bin/env ruby
# post-receive

# 1. Read STDIN (Format: "from_commit to_commit branch_name")
from, to, branch = ARGF.read.split " "

# 2. Only deploy if master branch was pushed
if (branch =~ /master$/) == nil
    puts "Received branch #{branch}, not deploying."
    exit
end

# 3. Copy files to deploy directory
deploy_to_dir = File.expand_path('../deploy')
`GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master`
puts "DEPLOY: master(#{to}) copied to '#{deploy_to_dir}'"