簡體   English   中英

Git:如何重新定位到特定的提交?

[英]Git: How to rebase to a specific commit?

我想重新定位到特定的提交,而不是另一個分支的 HEAD:

A --- B --- C          master
 \
  \-- D                topic

A --- B --- C          master
       \
        \-- D          topic

代替

A --- B --- C          master
             \
              \-- D    topic

我怎樣才能做到這一點?

您可以通過在您喜歡的提交上創建臨時分支來避免使用 --onto 參數,然后以簡單的形式使用 rebase:

git branch temp master^
git checkout topic
git rebase temp
git branch -d temp

你甚至可以采取直接的方法:

git checkout topic
git rebase <commitB>

使用“onto”選項:

git rebase --onto master^ D^ D

上面 jsz 的評論為我節省了大量的痛苦,所以這里有一個基於它的分步指南,我一直在使用它來重新定位/移動任何提交到任何其他提交之上:

  1. 找到要重新定位(移動)的分支的先前分支點 - 將其稱為舊父節點。 在上面的例子中是A
  2. 找到要將分支移動到的提交 - 將其稱為新父級。 B的例子中
  3. 你需要在你的分支上(你移動的那個):
  4. 應用你的變基: git rebase --onto <new parent> <old parent>

在上面的例子中,這很簡單:

   git checkout topic
   git rebase --onto B A

話題解決方案

回答已發布問題的正確命令可能是以下任何一個(假設分支topic已經簽出):

git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B

如果topic未簽出,您只需將topic附加到命令(最后一個除外),如下所示:

git rebase --onto B master topic

或者,首先檢查分支:

git checkout topic

將任何提交字符串變基為目標提交

我們需要的命令的基本形式,來自文檔,是:

git rebase --onto <Target> [<Upstream> [<Branch>]]

<Branch>是可選的,它所做的只是在執行命令的其余部分之前檢查指定的分支。 如果您已經簽出要變基的分支,那么您不需要這個。 請注意,您必須指定<Upstream>才能指定<Branch>否則 git 會認為您正在指定<Upstream>

<Target>是我們將提交的字符串附加到的提交。 提供分支名稱時,您只需指定該分支的頭部提交。 <Target>可以是任何不會包含在被移動的提交字符串中的提交。 例如:

A --- B --- C --- D         master
      \
       \-- X --- Y --- Z    feature

要移動整個功能分支,您不能選擇XYZfeature作為<Target>因為這些都是被移動的組內的提交。

<Upstream>很特別,因為它可能意味着兩個不同的東西。 如果提交是檢出分支的祖先,則它作為切點。 在我提供的示例中,這將是任何不是CDmaster <Upstream>之后的所有提交直到簽出分支的頭部都是將被移動的。

但是,如果<Upstream>不是祖先,則 git 會從指定的提交備份鏈,直到找到具有檢出分支的共同祖先(如果找不到則中止)。 在我們的例子中, BCDmaster<Upstream>都將導致提交B作為切點。 <Upstream>本身是一個可選命令,如果未指定,則 git 查看已檢出分支的父級,這相當於輸入master

現在 git 已經選擇了它將剪切和移動的提交,它將它們應用到<Target> ,跳過任何已經應用到目標的提交。

有趣的例子和結果

使用這個起點:

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature
  • git rebase --onto DA feature
    將提交BCXYZ提交D並最終跳過BC因為它們已經被應用。

  • git rebase --onto CX feature
    將提交YZ應用於提交C ,有效地刪除提交X

一個更簡單的解決方案是git rebase <SHA1 of B> topic 無論您的HEAD在哪里,這都有效。

我們可以從git rebase doc確認這種行為

<upstream>要比較的上游分支。 可能是任何有效的提交,而不僅僅是現有的分支名稱。 默認為當前分支配置的上游。


你可能會想,如果我在上面的命令中也提到了topic SHA1 會發生什么?

git rebase <SHA1 of B> <SHA1 of topic>

這也將起作用,但 rebase 然后不會使Topic指向如此創建的新分支,並且HEAD將處於分離狀態。 所以從這里你必須手動刪除舊的Topic並在 rebase 創建的新分支上創建一個新的分支引用。

由於變基是如此基礎,這是Nestor Milyaev 答案的擴展。 結合jszSimon SouthAdam Dymitruk 的回答中評論,產生了這個命令,該命令適用於topic分支,無論它是從master分支的提交A還是C分支:

git checkout topic
git rebase --onto <commit-B> <pre-rebase-A-or-post-rebase-C-or-base-branch-name>

請注意,最后一個參數是必需的(否則它會將您的分支倒帶以提交B )。

例子:

# if topic branches from master commit A:
git checkout topic
git rebase --onto <commit-B> <commit-A>
# if topic branches from master commit C:
git checkout topic
git rebase --onto <commit-B> <commit-C>
# regardless of whether topic branches from master commit A or C:
git checkout topic
git rebase --onto <commit-B> master

所以最后一個命令是我通常使用的命令。

我使用了上述解決方案的混合物:

$ git branch temp <specific sha1>
$ git rebase --onto temp master topic
$ git branch -d temp

我發現它更容易閱讀和理解。 接受的解決方案導致我發生合並沖突(懶得手動修復):

$ git rebase temp
First, rewinding head to replay your work on top of it...
Applying: <git comment>
Using index info to reconstruct a base tree...
M       pom.xml
.git/rebase-apply/patch:10: trailing whitespace.
    <some code>
.git/rebase-apply/patch:17: trailing whitespace.
        <some other code>
warning: 2 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
error: Failed to merge in the changes.
Patch failed at 0001 <git comment>
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

使用--onto添加答案:

我從來沒有背過它,所以我寫了這個小幫手腳本:
Git:將一個(子)分支從一個基礎重新設置到另一個基礎,留下另一個基礎的提交。

用法:

moveBranch <branch> from <previous-base> to <new-base>

簡而言之:

git rebase --onto "$3" "$2" "$1"

除此之外,另一種可用於類似目的的解決方案是cherry-pick一系列提交:

git co <new-base> 
git cherry-pick <previous-base>..<branch>
git branch -f branch

哪個有更多相同的效果。 請注意,此語法跳過了<previous-branch>本身的提交,因此它會挑選下一個和后續的提交,包括<branch>處的提交。

還有另一種方法可以做到,或者如果您希望回到不止一個提交。

這是一個返回到n次提交的示例:

git branch topic master~n

對於這個問題,也可以這樣做:

git branch topic master~1

該命令在git version 2.7.4上完美運行。 沒有在任何其他版本上測試過。

暫無
暫無

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

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