Git 将历史记录移植到*当前*分支

Git 将历史记录移植到*当前*分支,git,Git,我知道如何使用git-rebase--on移植历史。然而,我经常发现自己想要把历史从一个不同的分支移植到我现在的分支上,而不需要中间分离的头部状态 换言之: git checkout foo git rebase --onto foo A^ B # results in a detached HEAD # how to avoid this last step? git checkout -B foo TL;博士 根据需要使用git cherry pick,以及(稍后),git reset或g

我知道如何使用
git-rebase--on
移植历史。然而,我经常发现自己想要把历史从一个不同的分支移植到我现在的分支上,而不需要中间分离的头部状态

换言之:

git checkout foo
git rebase --onto foo A^ B
# results in a detached HEAD
# how to avoid this last step?
git checkout -B foo
TL;博士 根据需要使用
git cherry pick
,以及(稍后),
git reset
git branch-f

长的 在我回顾你已经知道的事情时,请容忍我一点,因为它们会让答案更清楚

重基通过复制提交来工作。也就是说,给定以下形式的提交图:

...--o--*--I   <-- mainline
         \
          F--G--H   <-- branch (HEAD)
正如您已经知道的,我们可以使用
git-rebase--to
将要复制的提交集从它们应该到达的点分离出来。例如,与其复制所有的
F-G-H
,我们可能希望将
F
留在后面,只复制
G
H

             G'-H'  <-- branch (HEAD)
            /
...--o--*--I   <-- mainline
         \
          F   <-- ???
           \
            G--H   [abandoned, sort of]
其中,
$stop
是,例如,commit
F

rebase如何在内部工作 rebase实现这一点的方法非常简单:

  • 它会记住当前的分支(或者对于分离的头,散列ID):
    saved\u branch=$(git symbolic ref-q——short HEAD)
    ,或多或少

  • 它列出了要复制的提交的哈希ID。它使用了
    git rev list
    和许多新奇的选项来处理所有困难的情况,但对于简单的情况,我们可以使用
    $stop..HEAD

  • 它运行
    git checkout——将$detach分离到
    (或类似的东西)

  • 它运行
    git cherry pick
    ,即
    git cherry pick$stop..$saved_分支

  • 一旦完成所有的cherry pick(包括解决冲突的任何停止),它将运行
    git branch-f$saved_branch HEAD
    (或类似的东西),使保存的分支名称指向上次复制的提交。(还有一个特殊的名字
    ORIG_HEAD
    )也有点混乱。)

  • 你想要什么 在您的情况下,您已经处于
    --on
    部分。也就是说,第1步是不相关的,第2步不可能以完全相同的方式发生。第3步根本不应该发生,我们希望新的提交能够扩展当前分支

    这就给我们留下了实现目标的第4步和第5步

    步骤4在任何现代Git中都特别容易,其中
    Git cherry pick
    可以处理一个序列:我们只需运行:

    git cherry-pick $stop..$branch
    
    其中,
    $stop
    是提交时的停止(我们不希望复制的提交),而
    $branch
    是指向我们确实希望复制的最后一次提交的分支。如果我们现在在
    mainline
    上,那就是
    git cherry pick..branch
    git cherry pick branch~2..branch
    ,复制提交
    G
    H

    为了实现第5步——使
    $branch
    指向提交
    F
    ——我们将在复制完成后将此留待以后。完成这些复制后,我们可以运行:

    git checkout $branch && git reset --hard $stop
    
    或:

    当我们在
    主线上时

    TL;博士 根据需要使用
    git cherry pick
    ,以及(稍后),
    git reset
    git branch-f

    长的 在我回顾你已经知道的事情时,请容忍我一点,因为它们会让答案更清楚

    重基通过复制提交来工作。也就是说,给定以下形式的提交图:

    ...--o--*--I   <-- mainline
             \
              F--G--H   <-- branch (HEAD)
    
    正如您已经知道的,我们可以使用
    git-rebase--to
    将要复制的提交集从它们应该到达的点分离出来。例如,与其复制所有的
    F-G-H
    ,我们可能希望将
    F
    留在后面,只复制
    G
    H

                 G'-H'  <-- branch (HEAD)
                /
    ...--o--*--I   <-- mainline
             \
              F   <-- ???
               \
                G--H   [abandoned, sort of]
    
    其中,
    $stop
    是,例如,commit
    F

    rebase如何在内部工作 rebase实现这一点的方法非常简单:

  • 它会记住当前的分支(或者对于分离的头,散列ID):
    saved\u branch=$(git symbolic ref-q——short HEAD)
    ,或多或少

  • 它列出了要复制的提交的哈希ID。它使用了
    git rev list
    和许多新奇的选项来处理所有困难的情况,但对于简单的情况,我们可以使用
    $stop..HEAD

  • 它运行
    git checkout——将$detach分离到
    (或类似的东西)

  • 它运行
    git cherry pick
    ,即
    git cherry pick$stop..$saved_分支

  • 一旦完成所有的cherry pick(包括解决冲突的任何停止),它将运行
    git branch-f$saved_branch HEAD
    (或类似的东西),使保存的分支名称指向上次复制的提交。(还有一个特殊的名字
    ORIG_HEAD
    )也有点混乱。)

  • 你想要什么 在您的情况下,您已经处于
    --on
    部分。也就是说,第1步是不相关的,第2步不可能以完全相同的方式发生。第3步根本不应该发生,我们希望新的提交能够扩展当前分支

    这就给我们留下了实现目标的第4步和第5步

    步骤4在任何现代Git中都特别容易,其中
    Git cherry pick
    可以处理一个序列:我们只需运行:

    git cherry-pick $stop..$branch
    
    其中,
    $stop
    是提交时的停止(我们不希望复制的提交),而
    $branch
    是指向我们确实希望复制的最后一次提交的分支。如果我们现在在
    mainline
    上,那就是
    git cherry pick..branch
    git cherry pick branch~2..branch
    ,复制提交
    G
    H

    为了实现第5步——使
    $branch
    指向提交
    F
    ——我们将在复制完成后将此留待以后。完成这些复制后,我们可以运行:

    git checkout $branch && git reset --hard $stop
    
    或:


    当我们在
    主线上时

    @torek的回答非常好,但是