首先,我建议您阅读the Pro Git book,因为 git 附带的大多数文档都非常糟糕,尤其是对于新手而言。 (它比 5 多年前有所改进,但仍有许多不足之处。)
也就是说,让我在这里快速介绍一下“您需要了解的内容”。
介绍性的东西
- 与其他人(包括这里算作“其他人”的 github)一起工作时,您的 git 会通过互联网电话调用他们的 git 并交换工作。这些其他人是peers,也就是说,他们拥有与你做新工作的完全相同的能力,至少在一般情况下是这样(github 本身不会独自完成新工作)。这意味着在交换期间,您可能拥有“他们”(无论他们是谁)没有的东西,但他们也可能拥有您没有的东西。
- Git 交换与单个提交一起工作。1哪些 提交以及如何提交变得有点复杂,所以让我们暂时搁置一下。李>
-
git push 的反义词不是git pull,实际上是git fetch。我认为你得到的错误信息不应该直接引用git pull;稍后我们也会对此进行详细介绍。
- Git 通过其“真实名称”SHA-1 ID 在内部跟踪提交,例如,您在
git log 输出中看到的长 40 个字符的十六进制内容。每个提交都有一组“父”提交,由 SHA-1 ID 标识。您可以自己使用 SHA-1 ID,但它们对人类非常不友好,您永远不会记得是否应该以 f13c9ab 或 0e1d227 或其他开头(这些是 缩写 ID !)。
- 因此,git 为您(用户)提供了类似
master 的分支名称。分支名称只是您告诉 git 用于跟踪您在该分支上所做的 最新 提交的名称。
- 最新的提交具有“曾经是最新”的提交作为其父提交,该提交具有更旧的“最新”作为其父提交,依此类推。 (git 实现这一点的方式非常简单:当您进行新提交时,其父提交是“当前提交”,一旦提交安全地存储在存储库中,git 将存储在分支中的 ID 替换为刚刚进行了新的提交。)
给定最后三个项目,让我们绘制一个提交图片段:
... <- 1f3a33c <- 98ab102 <-- branch
这里,分支的尖端是提交98ab102,其父级是1f3a33c。我们可以说名称branch“指向”98ab102,它指向它的父级,依此类推。
当你创建一个新的存储库(git init,假设这实际上是一个2)它完全没有提交,所以第一个提交有 no 父级。它是第二次和第三次等提交,指向之前的提交。
当你进行“合并”时,你告诉 git 接受两个(或更多,3 但我们现在只说两个)现有提交并进行一个具有 的新提交通过结合来自某个共同点的所有变化,作为父母的两者。合并并没有那么复杂,但在有意将工作划分为不同的开发线之后,您通常应该这样做。
现在,回到获取、推送和拉取
您已经创建了一个新的存储库 (git init),至少进行了一次提交 (git commit),并添加了一个“远程”(git remote add origin ...)。最后一步说“我有一个对等 git,我想调用 origin,所以请记住该名称下的 URL。”
然后,您要求您的 git 调用“origin”(git push ... origin)并在您的分支名称“master”(git push ... master)下找到您的提交。这是它变得有点棘手的地方。当你的 git 和他的 git 对话时,他的 git 应该使用什么名字?这里的简短回答是 他的 git 也将使用名称 master。这是可以改变的,但在这里改变它不是你想要的。
(您还通过-u 标志要求在您的 git 配置中让您的 git 记录此交换。我们暂时将其放在一边。)
当你的 git 调用他的 git 时,你的 git 说“在这里,看看这些闪亮的新提交”(他确实做到了),然后你的 git 说:“为什么不按原样添加这些新提交 到您的存储库,4 并让您的 master 指向这些提交的最尖端?”他的回答是:“好吧,我可以这样做,但是我会失去一些提交我有而你没有。”这是您看到rejected 消息的地方。
也许你希望他们忘记他们迄今为止的东西。如果是这样,您可以要求“强制推送”,让您的 git 告诉他们设置他们的master,即使这“丢失”了一些提交。是否这样做仍然取决于他们,但通常这不是您想要的。
也许您想拿起他们拥有的东西并将其添加到您的收藏中,或者拿起他们拥有的东西并扔掉您迄今为止的作品。这是你想要的git fetch。
git fetch 所做的事情,尽可能地简化,5 是通过互联网电话呼叫对等方并找出 他们 有什么 你没有。它带来了所有这些提交(请记住,交换是通过提交进行的)并将它们像 Borg 一样添加到您的存储库中。然后——这是关键部分——它改变了他们的分支名称,这样他们就不会干扰你的分支名称。
git fetch 用来与您的对等点同步的名称称为“远程跟踪分支”或有时称为“远程分支”。关于“远程分支”的一件奇怪的事情是它们实际上不是在遥控器上!它们保存在您自己的 存储库中。原因很简单:它们是遥控器上的快照,最后一次你的 git 与那个遥控器交谈。两个 git 挂断网络电话后,遥控器可能会变。 (当然,远程实际上变化的速度取决于远程 git 的繁忙程度。)
这里的重命名模式很简单:取远程的分支名称(如master)并在前面添加远程的名称(origin):您的origin/master“轨道”origin的@ 987654355@。 (例如,如果您不小心将自己的一个纯本地、非远程跟踪分支命名为 origin/oops,则可以使用全名形式,但最好的选择是一开始就不要这样做。 )
等等,git pull 是从哪里进来的?
请注意,到目前为止,都是git push 和git fetch。但是假设您已经完成了git fetch 并接受了他们的工作?现在你有一个问题:你有你的工作,你有他们的工作,这两者已经分道扬镳了。
如果你们都从一个共同的基础开始,我们可以像这样绘制你们的提交图:
... base <- yours <-- HEAD -> master
\
theirs <-- origin/master
这次我输入了HEAD ->,以显示您在哪个分支上(运行git status,您应该会在其输出中看到“on branch master”)。
将这两个不同的工作结合在一起的一种简单方法是使用git merge。如果你想这样做,你只需运行git merge origin/master(注意斜线:你希望你的 git 找到 your origin/master,它在 git fetch 期间拾取,并将其合并到你的master,在您的 master 上进行新的提交)。结果如下所示:
... base <- yours <- merge <-- HEAD -> master
\ /
theirs <-- origin/master
处理这个问题的另一种方法——实际上通常是更好的方法——是使用git rebase,我不会在这里详细介绍;有很多关于使用 rebase 的 StackOverflow 答案。但是,如果你这样做了,你会得到:
... base <- theirs <- yours <-- HEAD -> master
\
.......... <-- origin/master
(请注意,在所有情况下,origin/master 仍然指向最尖端的“他们的”提交。)
现在要记住的要点是,无论你做什么,如果你想让他们的 git 接受你的提交而不必强制推送,你需要让你的工作成为他们的附加组件,以便您的新提交“指向”他们的。对于push 流程,您的工作是否将其作为合并提交的“第二个父级”,或者只是直接构建在他们的提交之上;它只需要通过他们的提交 ID 指向他们的提交。 (但同样,rebase 通常比合并更好!)
那么,git pull(终于!)...
git pull 所做的简化,只是运行git fetch,然后运行git merge。简而言之,它是一个方便的脚本:你总是在获取然后合并,所以我们会给你一个获取然后合并的脚本。
当然,git merge 通常是错误的。它确实应该默认使用git rebase。
您可以制作 git pull 使用 git rebase,6 但我认为至少(或特别是?)对于新手来说,使用两个独立的步骤 — 部分原因是如果出现问题,对于这两种不同的操作,您从中恢复的方式是不同的。要摆脱失败的合并,请使用git merge --abort。要摆脱失败的变基,请使用git rebase --abort。 (这些曾经更加不同,现在只是“中止失败的事情”,这是一个很大的改进。但你需要知道该做什么,如果你从git merge或git rebase开始,那就更清楚了.)
底线
最后,你需要在这里采取的行动取决于你想要发生的事情,和遥控器将允许你做什么。如果您想放弃他们的 东西,请使用git push -f(强制),注意您正在以这种方式给他们(无论他们是谁)带来痛苦,并且他们可能会完全禁止这样做。如果您想保留他们的东西,请先使用git fetch,然后按您喜欢的方式保留他们的东西(合并、变基、返工等)。
1或带有补丁,您可以通过电子邮件与同行交流。也可以“捆绑”提交并通过其他方法传输它们。但在这种情况下,我们通过网络电话进行基于提交的交换。
2您可以在现有存储库中安全地运行git init。它的影响很小,但就我们的目的而言,它基本上什么都不做,因此有必要说“假设它确实产生了影响”。
3Git 将此称为“章鱼”合并,即使只有 3 或 4 个父级而不是 8 个。
4Git 大多只添加“更多内容”。我喜欢将此称为"Git Borg",在这里 git 将您的技术独特性添加到其现有集合中。
5git 中的一个常见主题是“这不是你想要的?好的,我们会保留现有的东西,但是让它变得更复杂所以你你也可以做你想做的事!”
6见脚注 5。