前一段时间我发生了一次合并冲突并且怀疑,这与我自己有关。现在我又遇到了同样的问题,这次我确定,我对这场冲突负有责任。
昨天我对我的分支commit
进行了一些更改,push
修改了它们。这是第一个也是迄今为止只对分支(本地和远程)的提交。
今天我做了一些更改(显然是在相同的文件中),添加了更改并将其提交给commit --amend
并尝试push
。
这是因为我发生了合并冲突:Updates were rejected because the tip of your current branch is behind
我修改了这些更改,添加,提交并推送它们。一切都很好。
但我想从错误中吸取教训。 错误是什么?(我认为它与使用git commit --amend
有关)
答案 0 :(得分:4)
amend
- 更改历史记录。
初始状态
Origin: A
Local: A
然后你提交并推送
Origin: A - B
Local: A - B
然后你提交修改
Origin: A - B
Local: A - C // local commit B replaced by new commit C
然后你试图推送并得到消息,你需要先拉。 Commit C包含来自B的更改,但它是一个不同的提交。拉扯之后就会有冲突。
答案 1 :(得分:1)
错误是什么? (我假设它与使用git commit --amend有关)
是的,它与使用git commit --amend
有关。通过修改提交,您已覆盖git history
(通过更改提交的SHA1)。只要你没有发布你的更改(推到某个远程分支),Amend
就可以了,但是一旦你这样做了,你真的不应该抄袭历史,因为如果有人已经得到你的更改,然后,当他们再次尝试拉动时,它可能会失败(提示:您应该只使用更改进行新的提交,而不是修改提交)。
现在,git将拒绝使用您的分支更新远程分支(具有修改公共提交),因为您的分支的头部提交不是您要推送的分支的当前头部提交的direct descendant
。 / p>
如果您想用(修改的)本地替换远程历史记录,则需要force push。 如果你不这样做,Git将拒绝推送,并要求你拉(在这种情况下,这是无用的,因为你将合并相同的内容,但不同的提交消息)。
然而,git push --force-with-lease更安全。跟进链接以了解更多信息。
如果你在检查它时强行或删除分支机构的'origin'处发生了某些事情,你最终可能会失去其他人的工作。
不知道倒带和重建分支的决定的人可能会尝试在您获取它的时间和您推迟用更改结果替换它的时间之间推送到分支。
我们可以通过选择性地允许用户告诉“git push”来使这些推动更安全:
我强制/删除,基于'branch'的值仍在此对象的假设。 如果这个假设不再成立,即自从我开始准备这个推动以来分支机构发生了什么事情,请不要继续这个推动。
答案 2 :(得分:1)
首先,这个:
Updates were rejected because the tip of your current branch is behind
不合并冲突。合并冲突更具体。当三向合并尝试组合两组不同的更改时会发生这种情况,但更改会重叠。您正在运行git push
,其中未合并任何内容。
与git push
相反的是不是 git pull
。 git pull
命令是一个便捷命令,它按顺序为您运行两个 Git命令。第一个命令是git fetch
- 与git push
相反,或者至少,尽可能接近git pull
。 git merge
运行的第二个命令通常是git rebase
,可以导致合并冲突。或者,您可以指示Git运行git rebase
秒;和face0ff
也可能导致合并冲突。
这可能会让人感到非常困惑,并且要好好使用Git,了解Git如何实际完成所有这些操作非常重要,因为Git倾向于让原始实现显示出来。因此,作为基本概述,请记住以下内容:
git cat-file -p HEAD
(但更长)。没有两个不同的提交具有相同的ID,ID完全由提交的内容决定。提交的内容有点详细,但不会太长 - 要完整地看一个,运行--amend
,只打印出来 - 但是要记住的重要一点是内容包括:
git add
似乎允许您编辑);和git commit --amend
- ed。
当您使用A
时,此似乎来更改提交,但它不会。它不能!提交的ID由其内容决定。如果您更改了内容,则会获得一个新的不同的提交。
因为提交在其中包含父ID,Git(和您)可以绘制提交的链,从较新的提交开始并向后工作。 Git向后运行一切:我们喜欢将分支视为前进。如果我们有提交的时间线,我们提交B
,然后C
,然后A -> B -> C
,依此类推,我们期望他们去提交#34;然后是B然后C":
A <- B <- C
但是Git让他们倒退,所以他们实际上是:
A--B--C <-- branch
因此,分支名称仅指向 tip-most 提交。这就是为什么Git一直在谈论&#34;你的分支的提示&#34;。
而且,这意味着我们想要绘制这样的图形:
branch
名称C
指向最新提交,C
。然后,Git会从B
转移到A
到A--B--C <-- branch
。大多数情况下,我们不必担心这一部分,但我们需要记住,名称只是指向提示提交。
分支名称指向分支提示。假设你有一个这样的链:
D
现在您进行新的提交D
。 Git做的是使C
的父级为branch
,然后将D
指向A--B--C--D <-- branch
。我们现在可以画出来了:
git commit --amend
D
所做的事现在很容易看到。将D
指向C
,而不是将D
添加到 end ,而不是B
指向C
(即,C
的父母)。然后将branch
指向D
,将 C
/
A--B--D <-- branch
推到一边:
git push
git push
做了什么当您运行A--B--C
时,您的Git会调用其他一些Git并进行一些对话。你的Git告诉他们的Git 你的提交。他们的Git告诉你的Git 他们的提交。然后你的Git向你的Git发送你的一些提交 - 无论你有哪些,他们都没有,你已经要求你的Git发送。
假设他们已经拥有A--B--D
并且您拥有git push branch
。通过询问你的Git D
,你会让你的Git向他们发送A
(它会发送你的B
和branch
,但他们已经拥有了这些;再次,这些都是由那些丑陋的哈希ID完成的,而不是简单的单字母名称,但这个想法是一样的。)
然后是最后一部分,这就是问题所在。您的Git要求他们的Git将他们的 branch
设置为指向与您branch
相同的提交。也就是说,您要求他们将他们的 D
设置为指向D
。
您的B
点回C
,而不是branch
。如果他们要将他们的 D
设置为指向新的共享C
,他们就会失去&#34;他们的amend
。
当然,由于您的C
,您希望他们失去&#34;失去&#34;他们的--force
就像你把Git推到一边时那样。所以你可以使用branch
。强制标志会更改您Git的礼貌请求 - &#34;如果您愿意,请将D
更改为指向branch
- 转换为命令:&#34;设置您的{ {1}}现在指向D
!&#34;他们仍然可以拒绝,但一般都会服从。
如果只输掉C
,那很好:那就是你想要的。但是,如果他们的Git是另一个人,也许是第三个人,使用第三个Git存储库,已经编写了一个提交E
并将其推送到他们的Git,以便他们实际拥有A--B--C--E
。如果您向D
发送指向B
的{{1}},并让他们将branch
设置为指向您的D
,则会失去C--E
} 链,而不仅仅是C
提交。
如果您修改了已经分享的提交,则可能是其他人已经建立了提交。如果您现在&#34;将其带走&#34;,您可能会为此人创造问题 -
另一方面,如果您从未共享过提交,或者其他Git是您自己的私有存储库,或者您和所有第三方提前同意这种& #34;带走&#34;这是正常的和预期的,你在这里不会遇到问题。
否则 - 如果&#34;带走&#34;是坏事 - 然后当其他Git提交时,你应该确保你推送的任何新提交只是添加到他们的提交。你可以通过合并或变基,以及git merge
或git rebase
进来的地方来做到这一点。不完全巧合的是,这两个命令是git pull
的后半部分 - 但是让我们暂时离开。