git rebase: 合并/截取commit及分支间的commit拼接

本文详细介绍了如何使用git rebase进行commit合并与删除,包括在单一分支上的操作和涉及多个分支的复杂操作,如合并commit、删除某段commit、分支间commit的拼接,以及忽略中间的支线。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

git rebase: 合并/截取commit 及 分支间的commit拼接

一. 只涉及单独分支的操作

1. 合并commit

当前分支状态:

A--------B-------C--------D 
        |--想要合并的commit--|

预计合并之后的状态:

A--------B'(包含C, D)

使用命令:
git rebase -i [start] [end]

startend遵循左开右闭原则
1. -i:启用交互,只有加了这个,才会有下面一步步的操作提示
2. [start]: 如果想要合并B----C----D,则[start]B 的前一个commit, 即A
3. [end]: 如果想要合并B----C----D,则[end]D ; 如果缺省的话,默认为当前head 指向的commit

Note:[start][end]均为commit-ish,有如下表示方法

----------------------------------------------------------------------
|    Commit-ish             |                Examples
----------------------------------------------------------------------
|  1. <sha1>                | dae86e1950b1277e545cee180551750029cfe735
|  2. <describeOutput>      | v1.7.4.2-679-g3bee7fb
|  3. <refname>             | master, heads/master, refs/heads/master
|  4. <refname>@{<date>}    | master@{yesterday}, HEAD@{5 minutes ago}
|  5. <refname>@{<n>}       | master@{1}
|  6. @{<n>}                | @{1}
|  7. @{-<n>}               | @{-1}
|  8. <refname>@{upstream}  | master@{upstream}, @{u}
|  9. <rev>^                | HEAD^, v1.5.1^0
| 10. <rev>~<n>             | master~3
| 11. <rev>^{<type>}        | v0.99.8^{commit}
| 12. <rev>^{}              | v0.99.8^{}
| 13. <rev>^{/<text>}       | HEAD^{/fix nasty bug}
| 14. :/<text>              | :/fix nasty bug

上表整理自StackOverFlow, 更多commit-ish理解可点这里

示例
1. 当前状态:

commit
file

2. 输入命令:

git rebase -i 869af45 9728be5

869af459728be5hashID的简写形式,git会查找以其开头的hashID

此时会以编辑器(vim)形式进入第一个交互:

pick f9a2daa add 1.txt
pick dd0326f add 2.txt
pick 9728be5 add 3.txt

# Rebase 869af45..9728be5 onto 869af45 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
~                                                                                                                                                                                                   
~                                                                                                                                                                                                   
~                                                                                                                                                                                                   
~                                                                                                                                                                                                   
~                                          

#开头的都是帮助信息,真正要修改的是开头的三行

命令默认为pick,即使用当前commit, 因为我们想合并这三个commit,所以将前三行修改为

pick f9a2daa add 1.txt
s dd0326f add 2.txt
s 9728be5 add 3.txt

表示采用第一个commit,并将后续的commit合并到第一个commit.

然后用vim的保存操作保存后,若没有conflict将再次以编辑器形式进入下一个交互

Note: 若存在conflict, 则解决冲突后,输入 git rebase --continue 继续操作,每次出现冲突,皆如此

# This is a combination of 3 commits.
# This is the 1st commit message:

add 1.txt

# This is the commit message #2:

add 2.txt

# This is the commit message #3:

add 3.txt

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Wed Jul 25 16:57:09 2018 +0800
#
# interactive rebase in progress; onto 869af45
# Last commands done (3 commands done):
#    s dd0326f add 2.txt
#    s 9728be5 add 3.txt
# No commands remaining.
# You are currently rebasing.
#
# Changes to be committed:
#       new file:   1.txt
#       new file:   2.txt
#       new file:   3.txt
#
# Untracked files:
#       core/file.js
#
~                                                                                                                                                                                                   
~                     

表明这三段commitmessage将合并。如果要更改信息,可以在这里修改,不修改的话可以直接进行保存操作。这里我们直接保存,然后git会做如下提示 :
这里写图片描述
我们发现操作成功了,但是当前的head还处于游离状态,此时我们处于一个7fc1b94的临时分支上,所以,接下来,将分支切换到之前的分支, 输入命令git reset --hard 7fc1b94:
这里写图片描述
此时用git log查看,会发现commit已经如我们所愿地合并了。
这里写图片描述

2. 删除某段commit

当前分支状态:

A--------B-------C--------D-------E--------F  
    |--想要删除的commit--|

预计删除之后的状态:

A--------D'-------E'--------F'
示例:

还是用之前的示例:
commit

1. 方法一:

在之前合并commit的基础上,将如下

pick f9a2daa add 1.txt
s dd0326f add 2.txt
s 9728be5 add 3.txt

改为

pick f9a2daa add 1.txt
d dd0326f add 2.txt
s 9728be5 add 3.txt

ddrop, 弃用本行的commit

之后的操作和之前一样即可,然后我们发现:
删除成功后的commit
删除成功后的文件列表

PS: 当然如果你只想删除第二个commit而不想合并第一个和第二个,那么就写成

pick f9a2daa add 1.txt
d dd0326f add 2.txt
p 9728be5 add 3.txt
2. 方法二:

使用命令:
git rebase [start] [end] --onto <newbase>

[start], [end] 都和之前一样;
--onto <newbase> 表示为rebase操作指定的基础点
以如下commit树为例:

A--------B-------C--------D-------E--------F  
    |--想要删除的commit--|

分析如下:

                     (因为左开右闭原则,实际start为C)
--newbase--|                    start             end
--------A--------B-------C--------D-------E--------F  
           |--想要删除的commit--|
示例:

仍然用之前的例子
操作前的commit
则执行命令如下:
git rebase 5806b3 08676a5 --onto dff15b

PS:
1. 将--onto <newbase>的位置调换这样写也是可以的:
git rebase --onto dff15b 5806b3 08676a5
2. 或者,你可以用其他commit-ish表示法,例如:
git rebase 分支名~1 分支名 --onto 分支名~2

执行后,如果head为游离态,则还是用老方法处理。操作成功后,我们可以看到:
操作后commit
操作后file

二. 涉及多个分支间的操作

以下只提及操作命令,就不一一示例操作了(才不是因为我偷懒)

1. 拼接到头部

当前分支状态:

A--------B-------C--------D    分支A
          \
           E-------F--------G  分支B
          |--想要拼接的commit--|

预计合并之后的状态:

A--------B-------C--------D    分支A
                           \
                            --------E'-------F'--------G'  分支B

可以直接在分支B上运行:
git rebase A B

git rebase A

2. 忽略中间的支线

当前分支状态:

A--------B-------C--------D    分支A
          \
           E-------F--------G  分支B
             |-忽略的commit-| \
                              H-------I--------J  分支c
                             |--想要拼接的commit--|

预计合并之后的状态:

A--------B-------C--------D    分支A
                           \
                            --------H'-------I'--------J'  分支c

使用命令:
在分支C上运行git rebase B C --onto A

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值