2017-04-06 71 views
3

我有3個分支:師傅,功能,修正錯誤......而提交如下:Git的改變衍合

4-5-6(feature) 
    | 
1-2-3(master) 
    | 
    7(bugfix) 

我「git的變基漏洞修復功能」來測試我的特點與缺陷修復

1-2-3(master) 
     | 
     7(bugfix)-4-5-6(feature) 

現在我需要重訂創建無缺陷修復我的特性分支拉的要求,所以我做了「混帳重訂主功能」,並期望:

1-2-3(master)-4-5-6(feature) 
    | 
    7(bugfix) 

相反,它表示功能是最新的與主。這是真的,但我不想在那裏合併提交7。 我可以做rebase互動和刪除提交,但我想知道是否有更好的方式來做到這一點。 我認爲rebase只會將1分支提交到另一個分支,但看起來不是。

回答

2

需要認識到的一點是,rebase不會重寫歷史記錄或移動提交,在Git中的提交無法更改。相反,它創造了新的歷史,並一直這樣說。例如,當你開始:

4-5-6(feature) 
    | 
1-2-3(master) 
    | 
    7(bugfix) 

然後git rebase bugfix feature到底發生了什麼是這樣的:

4-5-6 
    | 
1-2-3(master) 
    | 
    7(bugfix)-4A-5A-6A(feature) 

三個新提交製成,4A,5A和6A。原始提交仍然存在,但沒有指向它們。他們最終會被清理乾淨,但他們會在那裏待上好幾天。

這意味着你可以撤銷rebase,這就是你正在做的。你需要找到feature就在rebase之前。這可以通過git reflog完成,每次跟蹤HEAD移動。這發生在checkout,commit,resetrebasegit reflog可能是這樣的:

65e93ca (HEAD -> feature) [email protected]{0}: rebase finished: returning to refs/heads/feature 
65e93ca (HEAD -> feature) [email protected]{1}: rebase: 3 feature 
6d539a3 [email protected]{2}: rebase: 2 feature 
3cd634f [email protected]{3}: rebase: 1 feature 
b84924b (bugfix) [email protected]{4}: rebase: checkout bugfix 
a9fd2f1 [email protected]{5}: commit: 3 feature 
29136bc [email protected]{6}: commit: 2 feature 
60543b0 [email protected]{7}: commit: 1 feature 
c487530 (master) [email protected]{8}: checkout: moving from master to feature 

這告訴我a9fd2f1是在要素最後提交它被重訂了。我可以將特徵恢復,而不是重做rebase。

git checkout feature 
git reset --hard a9fd2f1 

在未來,如果你做底墊之前git tag功能的原始位置這樣的事情是由一個容易得多。然後,您可以將git reset返回到該標籤,而無需搜索reflog。


至於你的具體問題,問題是,重訂後你的資料庫,現在看起來是這樣的:

6A [feature] 
| 
5A 
| 
4A 
| 
7 [bugfix] 
| 
3 [master] 
| 
2 
| 
1 

當你問git rebase master feature GIT中指出,主已經是功能的祖先和不沒有。錯誤修正是介於兩者之間並不重要。

取而代之,您需要告訴Git您要重新綁定4A,5A和6A並忽略7.這是使用--onto語法完成的。

git rebase --onto master bugfix feature 

這就是說要從基礎上修補,但不包括修補功能到母版上。

我會推薦使用git reset而不是試圖重做rebase。不能保證第二次兌換會出現相同的情況,尤其是在發生衝突的情況下。與git reset相反,您正在顯式地回到存儲庫的舊狀態。

+0

謝謝! git rebase --onto正是我所需要的。 git reflog會工作,如果我沒有做任何修改後修復bugfix。 – chohocvo

2

我以爲rebase只會將1分支提交到另一個分支,但看起來不是。

這是關鍵:你的承諾7您的圖表中是分支feature。它也在分支bugfix。提交1-2-3都在全部三個分支。

Git的分支與大多數其他版本控制系統非常不同。分支「僅包含」一個提交,因爲它能夠「觸及」從分支名稱指向的提交提交的內容。分支名稱如master,bugfixfeature僅指向一個特定的提交,其中Git將該分支稱爲提示。通過讓每個承諾「回頭」到它的前任,這就是承諾本身形成一個鏈條。

正因爲如此,git rebase實際上副本提交:你去從:

 4--5--6 <-- feature 
    /
1--2--3  <-- master 
     \ 
     7  <-- bugfix 

到:

 4--5--6 [abandoned - used to be feature] 
    /
1--2--3  <-- master 
     \ 
     7  <-- bugfix 
     \ 
      D--E--F <-- feature 

其中D是原始4副本E5F的副本是6(我們的副本在這裏編輯第4,5和6個字母,所以我們可以複製7到G例如,如果我們想要的話,但這種技術即將用盡)。

雖然你仍然可以得到你想要的東西。您只需要副本D-E-F再次,或者 - 對於這種特殊情況,這可能更好 - 回到廢棄的原始4-5-6

當您使用git rebase來複制提交時,原稿會一直存在。有兩個名稱可供您查找:ORIG_HEADreflog名稱。該名ORIG_HEAD被各種其他命令重寫,但你可以檢查,看它是否仍然指向承諾6

git log ORIG_HEAD 

,你可能會認識到你的原稿。

reflog名稱的格式爲name@{number},例如[email protected]{1}。每次更改提交時間number部分增量將name部分點,Git的簡單節省的name電流值在引用日誌,推動其餘全部上升了一個檔次。

因此:

git log [email protected]{1} 

應該告訴你相同的人員犯git log ORIG_HEAD,唯獨身邊不再是那個[email protected]{1}棒(也許成爲[email protected]{2}[email protected]{3},等等,隨着時間的推移)。默認情況下,每個名稱的以前值至少保存30天,因此應該有足夠的時間將其恢復。

把它找回來,用git reflog feature看哪個號碼雲在@{...}部分,然後同時featuregit checkout feature),運行:

git reset --hard [email protected]{1} 

或任何號碼是(雖然驗證還再用git log先是個好主意)。

(這裏假設你沒有什麼檢查中,即,git status說的一切是乾淨的,因爲git reset --hard打掉還未簽入索引和工作樹的變化。)

+0

如果我在第一次rebase之後進行了更改,這是行不通的? 例如D - E - F - 8 < - 特徵。撤消這不會採取承諾8,我將不得不櫻桃挑選 – chohocvo

+0

右 - 或者你可以再次rebase,使用'git rebase --onto',它可以讓你分開rebase的* target *,即「在哪裏放置副本「,從*提交到複製*。 (通常這些由單個分支名稱指定。) – torek