在修改消息后合并冲突。无法拉动或推动

时间:2016-10-13 09:19:21

标签: git github merge-conflict-resolution

我提交但意识到信息中有错误。我跑了

git commit --amend -o -m "blah blah"

然后我删除了文件(故意),然后

git add .
git commit -m "blah blah"
git push origin master

并收到错误

! [拒绝]主人 - >主人(非快进)

我尝试用git pull origin master修复它并获得

CONFLICT (modify/delete): MyFile.java deleted in HEAD and modified in ad0c109

发生了什么,我该如何解决?我只想要有一个删除文件的历史记录。我打算用同一个名字创建一个新的。

更新 我跑了git push -f origin master并且有效。现在git status给出了

  

在分支主机上所有冲突都已修复,但您仍在合并。 (使用   " git commit"结束合并)

我跑了git commit并得到了

  

E325:注意找到一个名称的交换文件   " C:/Users/Dev3/Documents/NetBeansProjects/OctRecProj/src/OctRecProj/.git/.COMMIT_EDITMSG.swp"             拥有者:Dev3日期:2016年5月22日星期日03:27:31            文件名:~Dev3 / Documents / NetBeansProjects / OctRecProj / src / OctRecProj / .git / COMMIT_EDITMSG             修改:是的            用户名:Dev3主机名:Desktop-D           进程ID:2844打开文件" C:/ Users / Dev3 / Documents / NetBeansProjects / OctRecProj /   SRC / OctRecProj / git的/ COMMIT_EDITMSG"                日期:2016年10月13日星期四03:22:34         比交换文件更新!

     

(1)另一个程序可能正在编辑同一个文件。如果这是   案件,       注意不要以两个不同的实例结束       进行更改时提交文件。退出,或继续谨慎。 (2)此文件的编辑会话崩溃。       如果是这种情况,请使用":recover"或" vim -r C:/ Users / Dev3 / Documents / NetBe   ansProjects / OctRecProj / SRC / OctRecProj / git的/ COMMIT_EDITMSG"       恢复更改(请参阅":帮助恢复")。       如果您已经这样做,请删除交换文件" C:/ Users / Dev3 / Documents / NetBe   ansProjects / OctRecProj / SRC / OctRecProj / git的/ .COMMIT_EDITMSG.swp"    - 更多 -

4 个答案:

答案 0 :(得分:5)

让我们做一些笔记,然后绘制一些提交图,因为git merge的操作主要依赖于提交图附加到的树这三个有趣的"提交。

  1. git commit --amend不会修改提交(因为这是不可能的)。相反,它做了一个新的提交并将旧的提交推到一边为新的提供空间,而不是做通常的"最后添加新的"。

  2. git commit -o(或--only)省略当前索引(暂存区域),而是从上一次提交开始创建临时索引。在修改时这是一个合理的事情,尽管如果你没有上演任何东西,这没有任何效果。所以这"修改" (真的,复制)提交将具有与原始提交相同的,即使您已经上演了某些内容。 (这仅适用于注释3。)

  3. 最后,后续的git commit(在删除文件并暂存删除后)将进行新的提交,删除文件,以及已经上传的任何 else (如注2)所述。

  4. 现在,我们不知道您在此处修改的提交是否是合并提交本身,但我们只是假设它不是。 (如果是,图片会变得更复杂,但结果是相同的。)我们也不确定,但可以合理地假设,你提交的内容是修正已经被推 - 因为这正是导致这个问题的原因。所以,我们可以像这样绘制图形。

    首先,我们在"之前绘制"情况:在你修改任何东西之前。该图非常简单:

    ...--o--*--A   <-- master, origin/master
    

    也就是说,您的分支master指向提交A(我们即将提交的#34;修改&#34;)和origin/master - 您的副本如在另一个Git存储库中看到的master,在机器上origin - 也指向提交A。提交*A之前的提交;这个将在以后重要。还有其他早期的提交。

    现在让我们在修改之后绘制图形,但在进行任何新提交之前:

              A    <-- origin/master
             /
    ...--o--*
             \
              A'   <-- master
    

    提交A'是修改后的提交,消息略有不同。它与提交A具有相同的 - 相同的源代码 - 但是不同的消息,因此具有不同的SHA-1 ID。

    让我们添加删除文件的提交,并为D elete调用此D

              A      <-- origin/master
             /
    ...--o--*
             \
              A'-D   <-- master
    

    您现在尝试git push origin master并收到错误消息。该错误是因为,在origin上,他们的 master指向提交A,或者甚至是A之后的某些提交没有。 1 让我们继续理论origin不是一个超级活跃的存储库,每秒获得10次新提交或者其他任何东西,并且希望它和#39; s只是A。 : - )

    他们的Git在origin上抱怨的是,如果他们让你这样做git push,他们将会失去&#34;提交A。你的Git要求他们的Git设置他们的 master以指向你的提交D(当然,之后,移交你的A'和你的{{1 }})。如果他们这样做,他们将不再有一个指向提交D的名称:将忘记提交A

    当然,这正是您在修改A时对自己的存储库所做的操作。你告诉你的Git:&#34;忘了A,把它推到一边,其中唯一的名字是A,并给我一个origin/master副本,上面写着不同的消息&#34;

    好的,到目前为止一切都很好,除了推送失败。所以你跑了A'

    1 虽然你可以现在看到你现在拥有的东西,但它们不能准确地说出它们的含义当你跑git pull origin master时他们有什么权利。当然,你的git pull至少在几秒钟前完成了,谁知道那段时间发生了多大变化!说真的,有一个同步问题,因为无论你在Git中做什么,其他人现在可能正在其他Gits做其他事情。这对您来说有多大问题取决于git pull的活跃程度。

    origin git pull

    相反

    事实上,git push并没有完全相反的情况。最接近的是git push,它告诉你的Git调用他们的Git,就像推送一样,而不是发送你的提交并询问他们要移动他们的分支机构,您将获得他们的提交,并让您的Git移动您的&#34;远程跟踪分支机构&#34;:您的git fetch

    origin/master首先运行的是git pull,然后运行git fetch

    git merge

    git fetch的第一部分是Git运行git pull origin master

    这个git fetch origin master步骤调用了他们的Git并带来了他们的新提交。我们假设没有:他们的fetch仍然指向他们的master,这也是您的A。因此,您的Git更新了您的A以继续指向您的origin/master(没有太多更新:没有任何更改):

    A

    (如果他们确实有一些提交 - 让他们称呼他们 A <-- origin/master / ...--o--* \ A'-D <-- master B - 那么您的Git会获得这些提交并更新您的C

    origin/master

    但可能没有这样的提交。让它们在没有它们的情况下继续进行。)

    A--B--C <-- origin/master / ...--o--* \ A'-D <-- master

    git merge的第二部分是运行git pull origin master,其中一些额外的参数太复杂,无法准确再现,但或多或​​少等于git merge 2 < / sup>让我们假装它真的是origin/master,因为它更容易使用。

    git merge origin/master做的是首先找到合并基础,这是您当前分支之间相同的第一个提交 - <#>你的git merge - 以及你告诉它要合并的提交。你(或master,真的)告诉你Git合并的提交是git pull的提示,即,提交origin/master

    现在我们回到我们正在绘制并找到合并基础的图表。那个提交A。我们还找到*的提示,即提交origin/master,以及我们当前分支的提示:commit A

    接下来,我们制作(或Git制作)两个D列表:

    git diff

    据推测,在提交git diff <id-of-*> <id-of-A> # "what they changed" git diff <id-of-*> <id-of-D> # "what we changed" 和提交*之间,&#34;他们&#34; (无论他们是谁,也许是我们)更改了您在A中删除的文件。

    同时,在提交D和提交*之间,&#34;我们&#34;删除了文件。请注意,Git在提交D处甚至无法查看:它只是比较A'*。我们在D*之间以相同的方式更改文件并不重要,唯一重要的是我们在整体更改中删除了文件。

    这是合并冲突的根源。介于&#34;他们做了什么&#34;和#34;我们做了什么&#34;,Git不知道是否将更改保留到文件中,或者保留文件的删除

    如果您希望进行合并 - 您可能不会 - 您可以通过运行A'然后git rm <file>来提交合并来解决此问题。结果将是一个新的合并提交:

    git commit

    新合并的树将与提交 A <-- origin/master / \ ...--o--* \__ \ \ A'-D--M <-- master 的树匹配,但现在您将同时拥有原始提交D 修改后的副本(使用相同的树但是你历史上不同的提交信息。

    您可以将其推送到A,因为现在如果您向他们发送提交origin并要求他们将M设置为指向master,不会失去承诺M

    2 差异主要表现在默认的合并提交消息中,大约是,&#34;合并名为master的分支来自远程命名的来源&#34;而不是&#34;合并我们自己的远程跟踪分支origin / master&#34;。此外,如果您有一个古老版本的Git,早于1.8.4,还有一些额外的技术难题,阻止A在这里工作。希望您不会遇到Git 1.7.x版。

    该怎么办

    首先,您可以中止正在进行的合并:

    origin/master

    现在你回到原来的地方了:

    git merge --abort
    

    在您的存储库中。

    这里的一个大问题是他们,无论他们是谁,在 A <-- origin/master / ...--o--* \ A'-D <-- master 上,都提交origin。你也许可以使用强制推动让他们放弃它:

    A

    这告诉他们的Git&#34;继续并失去提交git push --force origin master ,只需将A设置为master。缺点是,如果他们现在已经获得了一些提交D和/或B,那么您也将丢失这些提交。此外,如果其他任何人已获得提交C的副本,那些其他用户必须执行某些操作才能从重置A恢复到放弃origin赞成A

    您可以使用A'告诉他们,实际上&#34;我相信您的--force-with-lease点要提交master;如果是这样,请改为A指向master。&#34; (这要求你的Git和他们的Git都足够新,以便拥有D选项。)

    或者,您可以放弃修改提交消息的想法。只需放弃并移植您的提交--force-with-lease,使其在D之后,而不是在A之后。完全放弃修改后的A',为您提供此图表:

    A'

    您现在可以推送此内容,因为原始 A <-- origin/master / \ ...--o--* D' <-- master \ A'-D [abandoned] 的新副本D'只会添加到其现有提交D。如果,在这样做之后,我们完全忘记了被遗弃的提交并且更好地绘制了这个,我们得到:

    A

    这是一段很好的直接历史,也是你所希望的。

    摘要

    使用...--o--*--A--D <-- master, origin 来逃避正在进行的合并后,您的三个选项是:

    1. force push;
    2. 力与租赁;
    3. 放弃修改:樱桃挑选git merge --abortD,或重复删除以创建D',重置自己的D'指向同一个地方为master
    4. (如果origin/master足够私有,那么选项1是安全且容易的。[另外,在正在进行的合并中进行推送在很大程度上是无害的,因为推送仅推送完成的提交。))< / p>

答案 1 :(得分:1)

我认为这就是发生的事情:

  1. 您更改了MyFile.java并将更改提交为提交 A
  2. 您推送了更改,因此远程存储库包含提交 A
  3. 您修改了提交,因此创建了提交 B (实际上是一个新提交,其更改与 A 相同)。
  4. 您删除了该文件并提交了更改创建提交 C
  5. 要检查这是否是您所处的情况,您可以执行git loggit log origin/{branchname}(假设您的远程仓库被称为原产地,并且您将{branchname}替换为分支的名称推到)。远程分支应包含带有旧消息的分支,而本地分支包含新消息。

    现在,您在本地提交 B C ,而远程存储库包含提交 A 。执行git pull时,git会尝试从远程存储库中获取提交 A 。此提交包含对文件MyFile.java的更改。当git尝试将该更改应用于您的本地存储库时,它会识别该文件在此期间已被删除。

    更多解释: git根据哈希值识别提交。哈希是基于许多信息计算的,其中包括由该提交完成的差异,先前的提交,消息以及提交的时间。因此,如果您修改提交,则哈希值会更改。在将来,git会将更改前后的提交识别为不同的提交。

    您有多种方法可以处理该问题。正如您在此期间评论说回购没有共享但只有您正在使用它,选项2很可能是首选。

    1. 决定删除文件,解决合并提交问题。但是,这会导致您的历史记录中存在提交 A B ,其中包含相同的更改但不同的消息。
    2. 使用git push -f强制推送您的更改。这将从远程存储库中删除commit A 并推送您的提交 B C 。如果其他人已经从远程存储库中获取了您的更改,这将导致问题,因为他们将遇到您之前遇到的相同问题。
    3. 不要修改提交并将其保留在旧状态。要恢复该状态,您可以先将提交的提交哈希值存储在任何位置,以便稍后使用它。比做一个git reset --hard A(注意:如果你还有任何打开的更改,这将删除它们,所以先将它们藏起来)以及之后git cherry-pick C其中 C 是哈希提交删除文件。如果你做了比那个提交更多的提交,请相应地进行提交(记住它们的哈希值,然后再选择它们)。

答案 2 :(得分:0)

您是否在更改提交消息后推送? 在git ammend之后,推动这一变化。然后运行命令删除文件 P.S - 当我按照你提到的步骤

时,我没有遇到这个问题

答案 3 :(得分:0)

如果您在修改之前没有推动分支,则意味着其他人在远程主分支上进行了一些更改,并且与修改提交无关。

当你执行pull时,git获取了分支的远程修改,然后尝试将其合并到本地分支中,这个失败导致你删除的文件在其他提交中被修改,所以我猜你需要同步另一个人,看看为什么他们改变了这个文件。

您需要手动解决此冲突。

另一种选择是在远程分支上重新绑定本地分支主服务器,您仍然会遇到冲突,但是您将避免在历史记录中进行合并提交。