這是我本地倉庫的狀態。我在 AAAAA 并提交了 CCCCC。我做了一個git pull,它拉動了提交,并將 BBBBB 自動(ish)合并到 CCCCC 并制作了 DDDDD。我不想那樣,所以我用 git reset 殺死了 DDDDD。
$ git 樹 --all
CCCCC (HEAD, main) foobar issue 666
| * BBBBB (tag: fubar, origin/main, origin/HEAD) fubar issue #69
|/
* AAAAA foo
我想將 CCCCC 移至 BBBBB,而不是合并。我如何重新設定這個?我需要先切換或結帳到 BBBBB 嗎?
* CCCCC (HEAD, main) foobar issue 666
* BBBBB (tag: fubar, origin/main, origin/HEAD) fubar issue #69
* AAAAA foo
uj5u.com熱心網友回復:
Rebase 是正確的:
git fetch
git switch main
git rebase origin/main
你可能只是說git pull --rebase,但我不是一個冒險的人。
uj5u.com熱心網友回復:
從技術上講,您實際上并沒有移動提交。相反,您將其復制到一個新的和改進的提交(具有不同的哈希 ID)。在 Mercurial 中也是如此。然而,Mercurialhg histedit的變基(“嫁接”)和歷史編輯()界面對于Mercurial 新手來說往往比 Git 的變基對 Git 新手更清晰。(這是 Mercurial-vs-Git 中的一個普遍主題。)
在 Git 中,提交實際上從未系結到任何特定分支。相反,Git通過從某個分支名稱開始查找提交——這實際上更像是一個 Mercurial“書簽”——然后向后作業。這個向后作業的部分達到的提交集被稱為“在分支上”。
因此,當兩個或多個分支名稱標識同一個最終提交時——就好像你有兩個或多個書簽指向 Mercurial 中的同一個提交——這些提交都在同一個分支上,但是只要你移動一個或兩個在 Git 中的那些分支名稱中,相同的兩個提交,完全沒有改變,可能不在同一個分支上。
該git rebase命令通過以下方式作業:
- 將當前分支名稱保存在某處。
- 列舉要復制的提交的原始哈希 ID。
- 使用 Git 的分離 HEAD模式來選擇一些特定的目標 (
--onto) 提交。這是新副本的去向。 - 一次一個地復制提交,就像通過
git cherry-pick(等同于 Mercurial,hg graft只是分支名稱無關緊要:提交永遠不會系結到任何分支)。 - 最后,拉取在步驟 1 中保存的分支名稱以指向上次復制的提交,并退出“分離的 HEAD”模式以回傳您在步驟 1 中所在的分支。
為了處理第 2 步和第 3 步——“哪個提交到復制”串列和“目標”提交——Git 通常使用單個引數。該單個引數通常是目標分支名稱。因此,要復制的提交的來源是當前分支(按照步驟 1)。這就是我們開始的原因:
git switch main
或同等學歷。
為了列出要復制的提交,Git 然后使用粗略的等效項:
git log target..HEAD
這意味著找到可從HEAD但不能從target. (Mercurial 也有這個,使用target::.,除了 Mercurial 的::圖形運算子包括區間的兩端,而 Git 是半開區間:它總是排除最左邊的提交。)
detached-HEAD-checkout 目標實際上就是target這種形式的引數。
在某些情況下,這是不可能產生的提交正確的串列這種方式,所以git rebase有--onto語法,這是一種奇怪的:
git rebase --onto target upstream
步驟 2 中的提交串列現在upstream..HEAD不是target..HEAD. 步驟 3 中的結帳仍然是target。
鑒于:
CCCCC (HEAD -> main) foobar issue 666
| * BBBBB (tag: fubar, origin/main, origin/HEAD) fubar issue #69
|/
* AAAAA foo
the list of commit hash IDs that you'd like copied is just one element long, listing CCCCC. The place you want the copies to go after is commit BBBBB. So if needed—the HEAD -> main says it isn't—we git checkout main or git switch main to make commit CCCCC current (it's OK to do even if not needed, it's just a no-op then). Then we run git rebase origin/main.
Git now lists all the hash IDs from here (HEAD or CCCCC) backwards: that's CCCCC, then AAAAA, then anything under there. From this list, Git strips BBBBB (it's not there but that just makes the stripping-out go fast!), then AAAAA, then anything under there—leaving only CCCCC.
Now Git does a detached-HEAD checkout of BBBBB. It then issues cherry-picks for all the commits in the saved list, in the right order. There's just the one commit in that list: CCCCC. So Git makes a new commit, CCCCD perhaps, that's like CCCCC, doing the same sort of thing, but that comes after BBBBB:
CCCCC (main) foobar issue 666
| * CCCCD (HEAD) foobar issue 666
| * BBBBB (tag: fubar, origin/main, origin/HEAD) fubar issue #69
|/
* AAAAA foo
Now that all the copies are done, Git yanks the name main to here—to CCCCD—and re-attaches HEAD so that we have:
CCCCC foobar issue 666
| * CCCCD (HEAD -> main) foobar issue 666
| * BBBBB (tag: fubar, origin/main, origin/HEAD) fubar issue #69
|/
* AAAAA foo
Commit CCCCC can't be found, though, so git log doesn't show it:
* CCCCD (HEAD -> main) foobar issue 666
* BBBBB (tag: fubar, origin/main, origin/HEAD) fubar issue #69
* AAAAA foo
and there's no longer any reason for the blank line either, so that goes away.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/335827.html
標籤:混帐 github git-rebase
