识别强制推动的冲突和后果

时间:2014-08-30 22:31:26

标签: git github

我对回购有一个奇怪的问题。当我尝试推送我的最新提交时,我不能,即使我很确定我有最新的提交,我是唯一一个在过去几个小时内编辑回购的人。

此外,我的git log 逐行匹配 GitHub上的git log。

$git push
To git@github.com:me/repo_name
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:me/repo_name'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details

这让我想到了以下问题:

  1. 我怎样才能看到具体提交与我想要推送的内容相冲突?
  2. 我的 git日志如何逐行匹配GitHub 中的那个并且仍有这个问题?
  3. 我如何强行推动?
  4. 如果我强行推动会发生什么?完全? (历史会改写吗?)
  5. 注意:我尝试合并,但是我遇到了冲突,所以我因为没想到​​它们而中止了。我之前正在测试一个实验性的git编辑器,我中途取消了提交(我的回购可能处于某种不一致的状态吗?)。

    另外 - 我正在使用git 2.0.2

    更新

    按照Jubobs的回答,我做了:

    $ git log master ..origin/master 
    

    它会在git log中列出确实拥有一次提交。正如我上面所说,git日志与逐行匹配,我检查了我的源代码,并且我有完全相同的更改,有问题的提交说我没有。怎么会这样?

2 个答案:

答案 0 :(得分:5)

对于第1项和第2项,只需使用git fetch来获取最新的origin/master(这假设您的github仓库位于名为origin的远程位置下,并且您没有摆弄同时使用fetch =行,然后使用任何日志查看器(git loggitk等)向您显示提交内容"他们有"那个"你没有"。有很多方法可以做到这一点。对于完整视图,我个人更喜欢gitk --all,但git log --graph master origin/master也会显示一些说明性内容(见下文)。

对于第3项,您可以git push --forcegit push origin +master:master(同样,这假设origin是指向github的遥控器的名称。

对于第4项:这是提交图(如第1项所示)有用的地方。让我们说,无论出于何种原因,你将在第1项中看到的图形看起来像这样(除了我想在这里水平绘制它,而不是你在{{1}中得到的垂直图形}):

gitk

在这张特别的图纸中,你提前2&#34;并且&#34;落后于1&#34;。你有两个提交遥控器没有,它有一个你不会提交。或者说,你有&#34;他们的&#34;提交,但不是通过您的分支名称 --- o - o <-- master / ... - o - o \ o <-- origin/master 找到的提交历史记录。

如果你master,你的git会做什么就是联系他们的(github&#39; s)git和&#34;他们的&#34; repo(即你的repo的github副本),要求它接受你的新提交 - 你git push --force上不存在的两个 - 然后只是将它们master指向同样的提交。也就是说,他们的master现在将指向最右上角(在此图中)提交,这是您master点的位置。然后你的git会更新他们的git&#39; master的副本 - 这就是你的git保留在master中 - 所以你现在拥有的图形如下所示:

origin/master

那&#34;放弃&#34;提交可以从&#34;他们的&#34;回购(即你自己的回购的github副本)几乎立即。

如果其他人也在复制&#34;他们的&#34;回购和使用它的提交,他们可能仍然有被放弃的&#34;提交自己的副本。他们可能会依赖它开始,如果你告诉github忘记提交,他们会感到烦恼,因为现在他们不得不做额外的工作来重新同步,同时还要保留该提交的内容。但是如果没有其他人也在使用这个github副本,或者他们没有拿起那个特定的提交,那么他们永远不会知道那里的提交已经存在并且现在已经被遗弃 - 并且可能真的消失了。


您在编辑中提到您开始 --- o - o <-- master, origin/master / ... - o - o \ o [abandoned] 。你是否完成或中止了合并还不清楚。如果你是'#34;在中间&#34;在合并中,您还没有实际创建合并提交,但您应该先完成或中止合并。您可以使用git merge告诉您是否仍在合并中:

git status

如果你已经中止了合并,那么复制提交给新的(不同的SHA-1哈希,但效果相同)......好吧,让我们重温一下 - 稍微绘制这个图,并给那些提交节点识别字母:

$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)
[snip]

这里,&#34; prime&#34; --- D - C' <-- master / ... - A - B \ C <-- origin/master 中的单引号表示此提交是提交C'副本:它具有相同的消息和相同的效果,甚至可能是相同的时间戳;但它有点不同,因为,如果没有别的,它有不同的父提交ID:它指向提交C,而不是提交D

如果强行将其推送到repo的github副本,则会像以前一样放弃提交B。因为C已经存在重要的一切,所以没有损失。但它仍然可以为已经克隆了github repo并在C'之上构建新提交的其他人工作:他们必须改变他们的工作,以便它现在位于C之上。实际移动应该非常简单(仅C'),但它仍然有用。

你可以继续强制推动,或者,如果你对这些其他人感到慷慨,你可以尝试重新安排你的自己的工作,这样它就可以了。线性延伸,快速前进&#34;正如git所说的那样。在这种特殊情况下,只需要将提交git rebase复制到位于D之上的D',然后放弃C序列以支持新序列:

D - C'

为此,您可以 --- D - C' <-- your old master, to be abandoned / ... - A - B \ C <-- origin/master \ D' <-- this becomes your new master git rebase master改为origin/master(有或没有-i)。 Rebase通常足够聪明,可以注意到复制的提交(C')并简单地删除它;或者您可以使用git rebase -i并自行明确删除它:

$ git checkout master
Already on branch 'master'
$ git rebase origin/master

(或-i,如上所述)。一旦完成所有工作,您应该可以在没有git push的情况下--force:您现在严格地&#34;在#34;之前origin/master,就是git(以及使用git的人)所期望的。

答案 1 :(得分:4)

  

1 - 我如何才能看到具体提交的内容与我想要推送的内容相冲突?

执行fetch,然后假设您的本地仓库知道名为origin的远程仓库,运行

git log master..origin/master

这将显示可以从origin/master访问的所有提交,但不会显示在您的本地master分支中。

  

2 - 我的git log怎么能逐行排列GitHub中的那个并且仍有这个问题?

要查看主分支与origin / master之间的更改,请运行

git diff master origin/master

如果没有输出,请比较两个头的时间戳(masterorigin/master)。由于SHA-1哈希值不同,必须不同。

  

3 - 如何强行推动?

运行

git push -f origin master

但等等!

  

4 - 如果我强行推动会发生什么? (历史会改写吗?)

如果强制将本地master分支推送到远程,则会强制生成在远程存储库中的master分支与该本地存储库中的分支完全相同。最近由你的同事推送到远程回购的master分支上的提交将会消失&#34;从该存储库的历史。这是一个危险的领域。

例如,如果您执行fetch并且您的本地存储库如下所示,

enter image description here

如果你再运行

git push -f origin master

两个存储库中的master分支都将指向提交D

enter image description here

提交EF将失去&#34;。所以,在强行推动之前三思而后行 ...