如何将代码拉取到一个空白的代码仓库?

47

我有一个“主”裸仓库和一个“个人”裸仓库。我想将“主”仓库中的更改更新到“个人”仓库,所以我运行:

$ git pull
fatal: /home/gimenero/applib/git/libexec/git-core/git-pull cannot be used without a working tree.

我该如何拉取推送到"main"的更改?

2个回答

65
< p > git pull 做的是一个 fetch 后跟一个 merge ,而你不能在没有工作树的情况下合并。(如果出现冲突,就无处解决它们。)< /p > < p > 相反,你可以只 fetch。假设你的主仓库在个人仓库上配置为名为 origin 的远程仓库:< /p >
$ git fetch origin master:master

请注意,只有您个人仓库的主分支正在镜像主仓库的主分支时,此操作才会成功。否则,Git将拒绝非快进式拉取。


我认为你的意思是 git fetch origin master:master。 - Dipstick
1
是的,我也以为fetch会这样做,但当我输入“git fetch”时,它显示:“From /home/rater/gitRepo/src * branch HEAD -> FETCH_HEAD”。那个“HEAD->FETCH_HEAD”让我感到困惑。它是什么意思?(看起来好像它会将其提取到FETCH_HEAD以供稍后合并,就像在非裸库中一样)。 - chila
1
当我输入命令:"git fetch origin master:master"时,它没有任何提示信息。 - chila
我不明白。如果我获取我的本地主分支指针,它不会指向远程主分支指针的相同提交。它如何快进,这不是只在拉取期间发生的吗? - Roberto
我以为 git fetch --all 可以解决问题,但它并没有给出期望的结果(即如果在裸的“个人”仓库中执行 git fetch --all,然后进入非裸的“个人”仓库并执行 git pull,则不会拉取来自主仓库的任何更改)。 - Trevor Boyd Smith
谢谢,它可以工作。我想在此之后执行几个命令,是否有可用的钩子或其他选项? - Shankar Prakash G

49

更新方式:

$ git fetch origin +refs/heads/*:refs/heads/* --prune

这是做什么用的?

首先一个旁白:当我们提到一个名为“xyz”的分支时,Git 实际上会将其称为 refs/heads/xyz。但是你可以使用 "xyz" 作为简称,否则这将是一件疯狂的事情。(顺便说一下,标签是 refs/tags/xyz。) 简单的 xyz 是有歧义的,因为它可能是一个分支,一个标签或提交哈希的前 N 个字母。另一方面,refs/heads/xyz 明确表示一个分支。

因此,即使你可以输入 git fetch origin foo:bar 来获取他们在你的存储库中命名为 barfoo 分支,但你可以更明确地输入 git fetch origin refs/heads/foo:refs/heads/bar 来完成相同的操作。(虽然如果 foo 实际上是一个标签而不是分支,则后者将失败,因为他们的 refs/heads/foo 不存在。显式性胜过隐式性.)

git fetch origin refs/heads/*:refs/heads/* 表示所有他们的分支都属于我们。该命令运行时,就像将 * 部分替换为每个分支的分支名称一样。即 git fetch origin refs/heads/abc:refs/heads/abc refs/heads/def:refs/heads/def ...(假设他们有名为 abcdef 的分支)。

--prune选项表示我们在存储库中拥有但不存在于他们存储库中的与refs/heads/*匹配的任何分支都会被删除。

最后,+ 前缀允许非快进式获取。如果没有它,对需要强制更新的分支进行的任何更新都将被拒绝。

综上所述,最终结果是你的存储库中的分支看起来与他们的完全相同。

这是一个输出示例:

 - [deleted]               (none)     -> bar
 * [new branch]            foo        -> foo
   4812558a5f..a6aeec6517  abc        -> abc
 + a1b2c3d4e5...1a2b3c4d5e def        -> def  (forced update)
  • 这个示例告诉我们它们有分支fooabcdef,而我们多了一个:bar
  • 请注意,通过--prune删除bar和使用+前缀强制更新def是被允许的。

如果没有使用+--prune,将会发生以下情况:

 * [new branch]            foo        -> foo
   4812558a5f..a6aeec6517  abc        -> abc
 ! [rejected]              def        -> def  (non-fast-forward)

最后一件事:

将顶部的命令与以下内容进行比较:

$ git fetch origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/* [--prune]

当我们键入git fetch origin [--prune]时,实际上就是这样发生的!


1
上面的答案可能比其他答案更强大和灵活,但它并不可见。通过一点解释,这个答案可以变得更有趣。我的理解是,这个命令是 git push --mirror 的反向操作,后者是危险的(即使存在冲突也会替换,删除目标端上不存在于发送端的任何内容)。 - Stéphane Gourichon

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