2013-10-25 52 views
2

強烈推薦的做法是不要改變別人推遲推送的提交歷史。儘管如此,不明白這一點的人無論如何也不可避免地會這樣做。從「其他用戶」的角度看,不是自己改變歷史的人,從這個方面恢復的最好方法是什麼?Git:如何從已更改的歷史中恢復?

下面是一個具體的例子。

瑞安創建一些提交和推動:

ryan $ git init 
ryan $ echo "initial stuff" > file.txt 
ryan $ git add file.txt 
ryan $ git commit -m "Initial commit" 
ryan $ echo "more stuff" >> file.txt 
ryan $ git add file.txt 
ryan $ git commit -m "More stuff" 
ryan $ git remote add origin [some url] 
ryan $ git push origin 

喬克隆GitHub的回購

joe $ git clone [some url] 

在這一點上,一切都很好,那麼......

Ryan更改最後一次提交:

ryan $ vi file.txt 
ryan $ git add file.txt 
ryan $ git commit --amend -m "More stuff" 
ryan $ git push origin 
     [Fails] 
ryan $ git push -f origin master 

請注意,Ryan在失敗後做了強制推送,否則就會失敗。如果他是唯一一個從起源中拉出來的話,那就沒有問題了,但在這種情況下,他只是搞砸了Joe。

喬試圖拉:

joe $ git pull origin 
     [Conflict!] 

現在,這是一個很簡單的例子,但它很可能是喬不熟悉file.txt並即將很難合併的變化。

我再次明白,問題的根源在於瑞安做了一件壞事。但是,儘管如此,我正在尋找喬和他的隊友可以從中恢復而不必進行合併提交的方式。

我知道一個技巧就是刪除遠程分支的本地副本,然後從原點重新檢查它。但是,當然這隻有在你沒有變化的情況下才有效。喬很可能會對自己想要做的一些新的改變。

想法?

+1

如何拒絕強制推送,至少對於像master這樣的分支? –

+0

@FrankOsterfeld不是一個壞主意,我沒有想到這一點。 – Marplesoft

回答

1

繪製提交圖。這裏是瑞安的原:

A - B 

A是「初始提交」和B第一「更多的東西」。

喬得到這個並開始工作。比方說,他補充提交C,也只是讓我們在喬的圖表有更多的東西:

A - B - C 

同時瑞恩去和它的修改和力量推動。這產生:

A - B 
    \ 
    B' 

其中B'是「修改」提交。

如果喬現在不取回(或拉,這當然不取回),這裏是他得到什麼:

A - B - C  <-- HEAD=master 
    \ 
    B'   <-- origin/master 

基本上,他仍然保留了原來B

要恢復,喬需要將他的提交(在這種情況下,只是C)重新綁定到新的origin/master提交,B'

如果喬使用git pull --rebase,混帳做了巧妙的:它可以告訴大家,提交B曾經是尖端提交的origin/master,因此,只有承諾C需要被重建基礎。

如果喬使用git fetch(或git pull--rebase),git會更新origin/master指向B',並使其更難弄清楚,B'對應B。 (在這些簡化的手繪圖表中很容易看到,但在實際的git中事後很難看到DAG)。但是,如果Joe能夠識別「他的」和「他們的」,儘管Ryan的殘酷的把戲:-),他可以做同樣的rebase。

(我找到一個簡單的rebase -i通常就足夠了,因爲我通常可以說「我」,從「他們」承諾,並刪除相應的pick線。)

(編輯:見Andreas Wederbrand's answer什麼pull --rebase內部做:它的使用rebase --onto upstreamstart_afterbranch。它得到upstream和任何拉力通常的方式branch,它知道start_after SHA-1從什麼是origin/branchpull --rebase步驟之前。)

2

您需要保存離開原籍提交它被重寫之前(或者你可以事後找到它,但以前變得更加容易)

git branch save_point origin/master (before fetch) 

然後做取,這改變不了什麼

git fetch 

現在,所有在Joe的存儲庫中尚未提交的提交信息都需要重寫/重新包裝到來自原始提交的重寫提交中

git rebase --onto origin/master save_point master 

如果不同分支上的變化不相關,這應該工作得很好。

你可以在manual中看到這個,但這不是微不足道的理解。

相關問題