"git init"和"git init --bare"有什么区别?

196

git initgit init --bare有什么不同?我发现很多博客要求在Git服务器上使用--bare

手册页面中可以看到:

--bare

创建一个裸仓库。如果GIT_DIR环境变量未设置,则设置为当前工作目录。

但实际上它意味着什么?在Git服务器设置中是否需要使用--bare

6个回答

168

非空仓库

这个选项会创建一个带有工作目录的仓库,你可以在其中进行操作(git clone)。创建后,你会看到该目录下包含一个.git文件夹,其中存放着历史记录和所有的Git基础架构。你的操作都在.git所在的级别进行。

空仓库

而另一个选项则会创建一个没有工作目录的仓库(git clone --bare),你无法在其中进行操作。该目录中的所有内容都与上面情况下的.git文件夹中的内容相同。

为什么要使用哪种

需要不带工作目录的Git仓库是因为你可以将分支推送到其中,它不关心其他人正在干什么。你仍然可以向非空仓库推送,但可能会被拒绝,因为你可能会移动某些人正在工作的分支。

因此,在没有工作目录的项目中,你只能看到Git存储对象的方式。它们被压缩和序列化,并以其内容的SHA1哈希值来存储。要在空仓库中获取一个对象,你需要使用git show命令并指定你想要查看的对象的SHA1哈希值。你将无法看到像你的项目所显示的结构。

空仓库通常是中央仓库,所有人都将自己的工作推送到其中。不需要直接操作实际的工作内容。它是在多个人之间同步努力的一种方式。你将无法直接看到你的项目文件。

如果你是唯一在项目上工作的人,或者不需要“逻辑中央”仓库,则可能不需要任何空仓库。在这种情况下,可以从其他仓库中使用git pull命令进行更新。这可以避免Git在向非空仓库推送时产生的问题。


保留“the”,从这行中去掉“a” - One would prefer git pull from a the other... :-) - Arup Rakshit
13
我觉得这个答案非常不清晰且令人困惑。一些原因在这里:http://meta.stackoverflow.com/questions/339837/how-to-point-out-unclear-things-in-answer?noredirect=1#comment422679_339837 - Marko Avlijaš
裸仓库通常是大家都将自己的工作移到的中央仓库。您的意思是裸仓库是其他项目协作者可以克隆项目的源吗?也就是说,协作者将其视为“远程”? - Minh Tran
@MinhTran:通常是这样的。但请注意,当您从某个存储库获取提交时,其他存储库是否为裸存储库对您来说并不重要。当将您的提交推送到该存储库时,它的裸状态或缺乏状态可能会对您产生影响。 - torek
@torek 在我知道裸仓库可以用作远程仓库之前,我已经写好了我的评论。我的公司希望保持开发代码的内部性,因此我需要一种在文件服务器上共享我的代码的方法。解决方案是设置裸仓库并像远程仓库一样使用它。通常情况下,您会将代码推送到远程仓库URL,但我将其推送到文件系统上的裸仓库目录中。 - Minh Tran

122

简短回答

裸仓库是一个没有工作拷贝的git仓库,因此.git文件夹中的内容对于该目录来说是顶层的。

使用非裸仓库在本地工作,使用裸仓库作为中央服务器/中心集线器与他人共享变更。例如,当你在github.com上创建一个仓库时,它会被创建为一个裸仓库。

所以,在你的电脑上:

git init
touch README
git add README
git commit -m "initial commit"

在服务器上:

cd /srv/git/project
git init --bare

然后在客户端上,你执行推送操作:

git push username@server:/srv/git/project master

您可以通过将其作为远程仓库添加来避免输入该命令。

服务器端的存储库将通过 pull 和 push 获得提交,而不是您在服务器机器上编辑文件然后进行提交,因此它是一个裸库。

细节

您可以推送到非裸存储库,Git 会发现那里有一个 .git 存储库,但由于大多数“中心”存储库不需要工作副本,因此通常使用裸存储库,并且建议使用这种类型的存储库没有必要拥有工作副本。

但是,如果您向非裸存储库推送,则会使工作副本不一致,并且 Git 会发出警告:

remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error: 
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error: 
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

你可以忽略这个警告。但是推荐的设置是:使用非裸库在本地工作,并使用裸库作为中央服务器或中心服务器进行推送和拉取。

如果您想直接与其他开发人员的工作副本共享工作,可以从彼此的存储库中拉取而不是推送。


如果我想在git服务器上工作我的项目,那么不必要使用--bare选项,是吗? - TheOneTeam
你使用 bare 来作为远程仓库,而非本地仓库。 - duncan
有一个问题需要解决。如果我们有一个裸的远程仓库,任何开发者都可以推送和拉取代码,这个仓库是“中央”仓库。但是如果我们没有裸仓库,开发者只能从彼此那里拉取代码,而不能推送。只有在仅有两个工作副本(即本地仓库)的情况下,最后一种方案才是可行的。这样说对吗? - Asturio

80
当我之前阅读这个问题时,所有的东西对我来说都很困惑。我刚开始使用Git,并不知道工作副本的含义。我将尝试从一个对术语一无所知的人的角度来解释。
一个很好的例子可以用以下方式描述:
--bare 只是一个存储位置(您不能在其中开发)。没有 --bare 它允许你在里面开发(并有一个存储位置)。
git init 从当前目录创建一个Git存储库。它在其中添加了 .git 文件夹,并使您可以开始进行版本控制。
git init --bare 也会创建一个存储库,但它没有工作目录。这意味着您不能在该存储库中编辑文件、提交更改或添加新文件。
当 --bare 有什么帮助?你和几个其他人正在使用 Git 工作在项目上。你把项目托管在某个服务器(Amazon EC2)上。你们每个人都有自己的机器,并将代码推送到EC2上。实际上你们都没有在EC2上开发任何内容(你们使用自己的计算机) - 你只是推送了你的代码。因此,你的EC2只是用来存储所有代码的地方,应该创建为 --bare,并且所有其他计算机不用 --bare(最可能只有一个计算机,其他计算机只需克隆所有内容)。工作流程如下所示:

1
那么,我们可以说通过使用“裸”存储库,我们可以创建一种类似于Subversion的客户端-服务器架构吗? - Emiliano Sangoi
1
@EmilianoSangoi 注意你说什么,否则你会被指控为异端!笑 - JohnK

15

默认的 Git 存储库假定您将使用它作为工作目录。通常,在服务器上,您不需要工作目录,只需要存储库。在这种情况下,您应该使用 --bare 选项。


在使用 --bare 选项的仓库中,我们无法看到所有项目文件吗? 好像我使用了 --bare 选项后丢失了所有项目文件。 - TheOneTeam

12
一个非裸库是默认的。当你运行git init时创建的就是非裸库,或者当你从服务器克隆(没有使用bare选项)时得到的也是非裸库。
当你使用这样的库时,你可以看到和编辑库中的所有文件。当你与库交互——例如提交更改——Git会将你的更改存储在一个名为 .git 的隐藏目录中。
当你有一个Git服务器时,不需要有文件的工作副本。你只需要存储在 .git 中的Git数据。 裸库恰好是.git目录,没有用于修改和提交文件的工作区域。
当你从服务器克隆时,Git在 .git 目录中拥有所需的所有信息来创建你的工作副本。

4
另一个--bare和工作树存储库之间的区别在于,在第一种情况下,仅存储属于分支跟踪的提交,而不存储任何丢失的提交。另一方面,工作树永久保留所有提交记录。请参见下文...
我使用git init --bare创建了第一个存储库(名称:git-bare)。它是服务器。它在左侧,没有远程分支,因为这是远程存储库本身。
我使用git clone从第一个存储库创建了第二个存储库(名称:git-working-tree)。它在右侧。它具有与远程分支链接的本地分支。
(文本“first”、“second”、“third”、“fourth”、“alpha”、“beta”和“delta”是提交注释。“master”和“greek”是分支名称。)

Local and remote repositories

现在我将删除名为'greek'的分支,包括在git-bare中(命令:git push --delete origin greek)和在git-working-tree本地(命令: git branch -D greek)。 树的外观如下:

The git-bare repository deletes what is no longer referenced

< p > git-bare 仓库会删除分支和所有引用的提交。在图片中,我们可以看到由于这个原因,它的树被减少了。

另一方面, git-working-tree 仓库相当于一个常用的本地仓库,不会删除提交,现在只能通过哈希直接引用,使用 git checkout 7fa897b7 命令。这就是为什么它的树没有修改后的结构。

简而言之:在工作树仓库中永远不会丢弃提交,在bare仓库中会删除提交。

在实际操作中,如果服务器上存在本地仓库,则只能从本地仓库恢复已删除的分支。

但很奇怪的是,bare 仓库在删除远程分支后,磁盘大小并不会减小。也就是说,文件还在某种程度上存在。要通过删除不再引用或永远无法引用的内容(后一种情况)来卸载仓库,请使用 git gc --prune 命令。


尝试测试git命令,请访问:https://github.com/sergiocabral/App.GitPlayground - Sergio Cabral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接