簡體   English   中英

Github 變基 & 合並 VS Git 變基 & 合並

[英]Github rebase & merge VS Git rebase & merge

I saw on the GitHub's docs here that the GitHub merge & rebase behaviour differs slightly from the git rebase because the rebase and merge on GitHub will always update the committer information and create new commit SHAs, whereas git rebase outside of GitHub does not change the committer當 rebase 發生在祖先提交之上時的信息。

那么誰能解釋一下這背后的機制? 提交者的哪些信息被更改?

謝謝

在您自己的計算機上本地完成的常規git rebase嘗試對事物進行一些優化。 GitHub rebase,在 GitHub 的計算機上遠程完成,努力確保沒有得到優化。

我認為,一個具體的例子在這里很有幫助。 假設我們在本地有這些提交:

          I--J--K   <-- feature (HEAD)
         /
...--F--G--H   <-- main

如果您運行git rebase main ,而在這樣的feature上,您的 Git必須將提交I復制到新的提交I' I提交的原始文件和新提交I' I'包含不同的快照(所有文件的集合),並且I'肯定有不同的parent I'的父提交是H (與GI )。 如果H中的快照與G中的不同,則快照是不同的,因為變基的目的是將G -vs- I更改H -vs- I'中的相同更改

          I--J--K   [abandoned]
         /
...--F--G--H   <-- main
            \
             I'-J'-K'  <-- feature (HEAD)

類似的規則適用於J' -vs- JK' -vs- K 新的和改進的提交不同的; 他們必須不同。

但是,如果你有這個:

             I--J--K   <-- feature (HEAD)
            /
...--F--G--H   <-- main

然后你運行git rebase main ,你的 Git 可以查看HI的相對位置並對自己說:嘿......如果我將I復制到一個新的I' ,其父級是H ,結果將匹配I . HI的差異,以及從H到新副本I'的差異,將是相同的 父母將是相同的 那么......為什么還要復制呢? 讓我重新使用現有的I

您的 Git 也會對JK重復此推理。 因此,當 rebase 完成時,您將在您的存儲庫中擁有它:

             I--J--K   <-- feature (HEAD)
            /
...--F--G--H   <-- main

從字面上看,什么都沒有改變。 三個 commit 的實際 hash ID 相同; 提交者是相同的; 一切都是逐位相同的,提交 hash ID 仍然匹配。

但是,您可以強制Git 無論如何都要復制提交,並輸入新的提交者時間戳。 如果你強迫你的 Git 這樣做,你最終會得到:

             I--J--K   [abandoned]
            /
...--F--G--H   <-- main
            \
             I'-J'-K'  <-- feature (HEAD)

其中三個新提交具有相同的快照,但提交者行中的時間戳不同,因此與原始三個提交不同的 hash ID。

要強制像這樣進行本地變基,您可以使用git rebase -f 這在有或沒有-i的情況下都有效。 但是,如果您在這里使用-f--force選項,那么您的 Git 何時以及是否真正設法在本地進行此優化取決於您特定的 Git 版本。 所以不是每個 rebase 都像這樣優化。 但它很常見,並且出於某些特定目的, 1 force-new-commits 選項已經存在了很長時間。

當您使用 GitHub rebase-and-merge 選項時,GitHub 有效地打開了 force 選項。 無論是字面上的情況,還是只是 GitHub 實現他們的變基代碼的方式的副作用——他們必須稍微修改 Git 以使他們與分叉的一些特殊共享魔法更好地工作,例如,這可能在這里發揮作用; 他們使用裸存儲庫,無論如何rebase通常是不可能的——我不知道。 但他們最終每次都在復制。 這會在每次提交中生成新的committer者信息,這意味着新提交具有新的、唯一的 hash ID,與原始 ID 不匹配。

(在公司環境中工作時,這實際上是相當煩人的。至少,我發現是這樣。即使不使用分叉也會發生這種情況,所以裸回購的事情可能是真正的罪魁禍首。)


1至少據我所知,強制復制變基的主要用途是重新進行已恢復的合並。 假設我們有這個:

             I--J--K   <-- feature
            /       \
...--F--G--H------L--M--W   <-- main

其中feature被合並到main但后來有人發現存在錯誤,因此使用提交W恢復了提交M (M 倒置,從 Linus 竊取)。 然后修復了該錯誤:

             I--J--K--N   <-- feature
            /       \
...--F--G--H------L--M--W   <-- main

但是如果我們現在按原樣將feature合並到main中,我們將遇到合並沖突和/或不會從提交IJK中獲得任何影響,因為 revert W會撤消它們所做的事情。 發生這種情況是因為 Git 使用 hash ID 來了解發生了什么。

那么,假設我們欺騙Git復制IJK ,即使它是“不必要的”:

             I--J--K
            /       \
...--F--G--H------L--M--W   <-- main
            \
             I'--J'--K'--N   <-- feature (HEAD)

我們現在可以git switch main && git merge feature

             I--J--K
            /       \
...--F--G--H------L--M--W--M2   <-- main (HEAD)
            \             /
             I'--J'--K'--N   <-- feature

其中M2的快照基本上是M -plus-the-bug-fix-in- N

當然還有其他方法可以得到想要的結果,但這是Linus 多年前概述的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM