git 裸仓库有什么用?

Rom*_*man 1 git git-bare

在远程机器上,我使用以下命令创建一个裸存储库:

git init --bare $HOME/bare/My-Repo
Run Code Online (Sandbox Code Playgroud)

在我的本地机器上,我克隆了一个 repo(但不是我在远程机器上创建的那个):

git clone ssh://something.com/My-Repo
Run Code Online (Sandbox Code Playgroud)

在我的本地机器上,在我刚刚克隆的存储库中,我创建了一个对位于远程机器上的上述裸存储库的“引用”:

git remote add my_remote ssh://remote.com/${USER}/bare/My-Repo
Run Code Online (Sandbox Code Playgroud)

我不知道它是否与我的问题有关,但我还在本地存储库中执行以下操作:

git config remote.my_remote /some/path/git-receive-pack
git config remote.my_remote /some/path/git-upload-pack
Run Code Online (Sandbox Code Playgroud)

现在,我可以从本地存储库推送到远程机器上的裸存储库:

git push my_remote master
Run Code Online (Sandbox Code Playgroud)

现在,我们的想法是我们在远程机器上创建另一个存储库,它应该从裸存储库中获取一些内容。我通过在远程机器上执行这样的事情来创建这个 repo:

some_script.sh $HOME/bare/My-Repo $HOME/My-Repo
Run Code Online (Sandbox Code Playgroud)

现在,我做的一些改变$HOME/My-Repo在远程机器上(请注意,它不是仓库),然后我git addgit commit之后,我推:

git push origin my-dev-branch
Run Code Online (Sandbox Code Playgroud)

结果我推送到裸存储库(位于同一台远程机器上)。之后,我转到我的本地机器并从远程机器(从裸存储库)“获取”更改:

git fetch my_remote
git checkout -b my-dev-branch my_remote/my-dev-branch
git fetch origin
git rebase origin/master
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:为什么我们需要这个裸存储库?为什么我们不能只有一个远程存储库,直接在本地和远程存储库之间交换内容?或者,为什么我们不能只是rsync (或scp)本地存储库往返于远程机器?

添加

这就是为什么我问这个问题而不是谷歌搜索。我用谷歌搜索了我的问题,第一个链接在这里:http : //www.saintsjd.com/2011/01/what-is-a-bare-git-repository/

我在那里读到:

使用 git init 命令创建的存储库称为工作目录。在存储库的顶级文件夹中,您将找到两件事: 一个 .git 子文件夹,其中包含您的存储库的所有 git 相关修订历史记录 一个工作树,或检出您的项目文件的副本。使用 git init --bare 创建的存储库称为裸存储库。它们的结构与工作目录略有不同。首先,它们不包含源文件的工作或检出副本。其次,裸仓库将仓库的 git 修订历史存储在仓库的根文件夹中,而不是在 .git 子文件夹中。注意……裸仓库通常有一个 .git 扩展名。

所以,现在要明白我需要知道:

  1. 什么是“修订历史”?
  2. 什么是“工作树”?
  3. 什么是“签出副本”?

这只是第一部分。我知道,响应将是:去阅读 git 教程或 git 介绍。嗯,我做到了。它的第一个问题是术语的使用是“循环的”。A 词通过 B 词表达,B 词通过 A 词表达。第二,我没有时间读一本书来寻找我的问题的答案。第三,我 100% 确定我的问题的答案可以用简单的术语表达。这实际上是微不足道的。

Sto*_*ica 7

如果我理解正确,您的主要问题归结为:为什么我们需要一个中间裸存储库来在两个 Git 存储库之间同步?

在您的具体示例中,您有一个本地 Git 存储库,我们称之为 X,还有两个远程存储库,一个裸的我们称之为 B,一个非裸的,我们称之为 Y。

在这一点上,我希望你看到 X 和 Y 可以在任何地方。它们可以是本地的,也可以是远程的,与 B 在同一台服务器上。它们在哪里并不重要,重要的是您想要在它们之间同步,为此您需要 B,在某处,任何地方. 你的问题是为什么

首先,中间不需要B。这是推荐的,默认行为将引导您朝这个方向发展。

为什么建议在存储库之间使用裸存储库?答案与工作树有关。工作树是您处理文件的地方。工作树的 Git 存储库位于.git子目录中。您在工作树中执行的 Git 命令与 Git 存储库通信,查询其内容,并与您在工作树中的内容进行比较。一个裸仓库就像一个.git单独的目录,没有工作树。

要揭开裸存储库的神秘面纱,请尝试以下操作以查看裸存储库和非裸存储库之间的区别:

$ cd /tmp/
$ git init --bare bare.git
Initialized empty Git repository in /private/tmp/bare.git/
$ git init regular
Initialized empty Git repository in /private/tmp/regular/.git/
$ diff -r bare.git/ regular/.git/
diff -r bare.git/config regular/.git/config
4c4,5
<   bare = true
---
>   bare = false
>   logallrefupdates = true
Run Code Online (Sandbox Code Playgroud)

从技术上讲,区别在于几个配置标志。我可以将bare.git目录移动到文件系统中的任何目录,将其重命名为.git,编辑config文件,瞧,我会将一个裸存储库转换为常规存储库。

回到问题:为什么建议在两个想要相互同步的非裸存储库之间有一个裸存储库?默认情况下,Git 禁止推送到非裸仓库。如果没有呢?如果git push会更新.gitremote的内容,对应的工作树会发生什么?很多问题会随之而来:

  • 工作树的当前分支是什么?如果推送没有改变那个分支,那么一切都很好。
  • 如果推送影响了工作树的当前分支,会发生什么?Git 应该更新工作树吗?
    • 如果工作树不干净,则无法安全更新。未提交的更改可能会丢失。
    • 即使工作树是干净的,如果对 进行了更改.gitignore,或者如果使用强制推送重写了分支的历史记录,也可能会发生冲突。
    • 如果我们不更新工作树,它将与存储库不同步,因此git status会报告不应提交的修改。

这听起来是否复杂和令人困惑?那是因为它是。这就是默认情况下不允许推送到非裸存储库的原因。如果您真的愿意,您可以这样做,如果您始终保持推送到的存储库的工作树的清洁,它可以相当安全,但这很容易出错(您可能会忘记),并且没有人需要这种不确定性和精神负担. 最好只在两者之间使用一个裸存储库。