2014-08-30 112 views
2

我在回購時遇到了一個奇怪的問題。當我嘗試推動我的最新承諾時,我無法做到,儘管我非常肯定自己有最新的提交,而且我是唯一一位在過去幾個小時內一直在編輯回購的人。識別強制推送的衝突和後果

另外我的git日誌逐行匹配 git登錄GitHub。

$git push 
To [email protected]:me/repo_name 
! [rejected]  master -> master (non-fast-forward) 
error: failed to push some refs to '[email protected]: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. 會發生什麼究竟是如果我強迫推? (歷史將被改寫?)

注:我試圖合併,但我遇到衝突,所以我放棄,因爲我沒想到他們。我之前測試過一個實驗性的git編輯器,並且中途取消了提交(我的回購可能處於某種不一致的狀態?)。

而且 - 我使用git 2.0.2

更新:

繼Jubobs答案,我所做的:

$ git log master ..origin/master 

並列出一個承諾確實有git log。正如我上面所說,git日誌匹配一行一行,我檢查了我的源代碼和我有完全相同的變化,提交問題說我沒有。怎麼會這樣?

+0

只要給予 - 力量,我會推動力推。 – 2014-08-30 22:35:05

+2

如果您強制推送,您將完全覆蓋遠程回購圖表。這幾乎是*從來沒有*你真正想要的。 – 2014-08-30 22:38:53

+0

要知道什麼是碰撞,請執行git fetch(而不是拉),然後查看圖形(使用例如Tig)。 – 2014-08-30 22:40:42

回答

4

1 - 我如何看到具體碰撞的是什麼提交與我試圖推動?

做一個fetch然後,假設你的本地回購知道名字origin下遠程回購,運行

git log master..origin/master 

這將顯示所有從origin/master到達的提交,但不會從當地master分支。

2 - 我的git log如何從GitHub中逐行匹配並仍然存在這個問題?

要查看您的主分支和起源/主站之間發生了什麼變化,運行

git diff master origin/master 

如果你沒有輸出,比較兩個頭(masterorigin/master)的時間戳。由於SHA-1哈希值不同,因此必須與不同。

3 - 如何強制推送?

通過運行

git push -f origin master 

但等待!

4 - 如果我強行推動會發生什麼? (歷史將被改寫?)

如果強行推動當地master分支機構到遠程,你將迫使遠端倉庫master分支活準確反映的是其生活在你的本地倉庫。您的同事最近將其提交給遠程倉庫的master分支的提交將從該倉庫的歷史記錄中「消失」。這是危險的領域。

舉例來說,如果你做一個fetch和本地資源庫如下所示,

enter image description here

,如果你再運行

git push -f origin master 

master分支在這兩個倉庫將指向犯D

enter image description here

提交EF將「丟失」。所以,三思而後行力推前...

+0

感謝---我已經運行'git log master ..origin/master'並且感到驚訝,它列出了我在'git log'中所做的一個提交! (並且從昨天開始)。怎麼可能? (看我更新的Q2) – 2014-08-30 22:42:09

+0

@ user815423426不確定你的意思是2.?你能澄清嗎? – Jubobs 2014-08-30 22:50:52

+0

有趣。我只是做了'git log --graph --all',我看到兩次提交不同的哈希,但是同一個確切的時間戳和消息(從昨天開始)。我的推動是否昨天出了問題? – 2014-08-30 22:51:22

5

對於項目1和2,簡單地使用git fetch拿起最新origin/master(假設你的github回購協議下的遠程命名origin,那你有沒有撥弄與fetch =行一樣),然後使用任何日誌查看器(git log,gitk等)向您顯示提交「他們有」,「你不」。有很多方法可以做到這一點。對於完整的視圖,我個人更喜歡gitk --all這裏,但git log --graph master origin/master也會顯示一些說明(見下文)。

對於第3項,您可以git push --forcegit push origin +master:master(同樣假定origin是指向github的遠程名稱)。

對於第4項:這是提交圖(見第1項)的用處。比方說,不管什麼原因,你會在第1項見圖表看起來是這樣的(除了我想水平在這裏畫它,而不是垂直圖紙,你會在gitk獲得):

   --- o - o <-- master 
      /
... - o - o 
      \ 
       o <-- origin/master 

在這個特定的繪圖中,你是「前進2」和「後面1」。你有兩個提交遠程沒有,並且它有一個你沒有提交的提交。或者說,你有「他們」的承諾,但沒有通過您的分支名稱master發現的提交歷史。

如果你git push --force,你的git會做的是聯繫他們的(github的)git和「他們的」回購(即你的回購的github副本),請求它採取你的新提交 - 兩個您的master不在其上 - 然後只是將它們的master指向相同的提交。也就是說,他們的master現在將指向右上角(在此圖中)提交,這是您的master指向的地方。使用Git然後將更新其自己的Git的master - 這個副本是你的Git是保持在origin/master - 所以,你現在有圖形看起來是這樣的:

   --- o - o <-- master, origin/master 
      /
... - o - o 
      \ 
       o [abandoned] 

那「拋棄」的提交可以刪除「他們的「回購(即你自己的回購的github副本)幾乎立即。

如果其他人也在複製他們的「回購」並使用它的提交,他們可能仍然會在他們自己的副本中進行「已放棄」提交。他們可能會開始取決於它,並且如果你告訴github忘記了這個提交就會感到惱火,因爲現在他們將不得不做額外的工作來重新同步並且還保留提交的內容。但是如果沒有其他人也在使用這個github副本,或者如果他們沒有拿起那個特定的提交,他們將永遠不會知道提交曾經在那裏,現在被放棄,並且可能真的沒有了。


您在編輯中提到您開始了git merge。目前還不清楚你是否完成或終止了合併。如果您處於合併的「中間」,您尚未實際創建合併提交,但您應該先完成或中止合併。您可以使用git status來告訴你,如果你仍然在合併:

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

如果你已經做了中止合併,然後也複製是致力於一個新的(不同的SHA-1散列,但同樣的效果)......好吧,讓我們重新繪製此圖了一下,並給那些犯下節點識別字母:

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

這裏,「地王」單引號中C'表明,該提交的是一個複製承諾C:它有相同的消息和相同的效果,甚至可能是相同的時間戳;但它有點不同,因爲如果沒有別的,它有不同的父提交ID:它指向提交D,而不是提交B

如果您強制將其推送到回購的github副本,則承諾C會像以前一樣被放棄。這不是什麼大問題,因爲一切都很重要,C'已經在那裏了。但它仍然可以爲克隆github回購並在C之上建立新提交的其他人工作:他們將不得不改變他們的工作,使其現在位於C'之上。實際的移動應該很容易(只是git rebase),但它仍然有效。

您可以繼續前進並強制推送,或者,如果您對這些其他人感到慷慨,您可以嘗試重新安排自己的作業,使其成爲線性擴展,「快進」因爲git稱之爲。在這種特殊情況下,這將只需要複製承諾DD'那上面坐C,則有利於新序列的放棄你D - C'序列:

   --- D - C' <-- your old master, to be abandoned 
      /
... - A - B 
      \ 
       C  <-- origin/master 
       \ 
        D' <-- this becomes your new master 

要做到這一點,你可以簡單地git rebasemasterorigin/master(有或沒有-i)。 Rebase通常足夠聰明,可以注意到一個複製的提交(C')並簡單地刪除它;或者您可以使用git rebase -i並明確自己砸:

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

(或-i,如上)。一旦所有的工作,你應該能夠git push沒有--force:你現在嚴格「超越」origin/master,這是git(以及使用git的人)期望的情況。

+0

嘆息,直接編號的問題:-) – torek 2014-08-30 23:07:51

+0

雖然我會爲失去15個重點而感到難過,但你應該得到複選標記:) – Jubobs 2014-08-30 23:22:46

+0

@Jubobs:我不知道這一點,你的圖形非常漂亮......: ) – torek 2014-08-31 00:49:32