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

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

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

您可能感兴趣的与本文相关的镜像

Kotaemon

Kotaemon

AI应用

Kotaemon 是由Cinnamon 开发的开源项目,是一个RAG UI页面,主要面向DocQA的终端用户和构建自己RAG pipeline

<think>我们遇到了一个Git错误,提示有未暂存的更改,因此无法进行rebase操作。解决方案是:要么提交(commit)这些更改,要么储藏(stash)这些更改。 具体步骤如下: 1. 选择处理方式:提交或储藏更改。 - 如果这些更改是临时的或者不完整的,建议使用储藏(stash)。 - 如果这些更改是完整的,可以提交(commit)到当前分支。 2. 根据选择执行操作: a) 储藏更改: 命令:`git stash` 或者 `git stash push -m "保存的消息"` 然后执行rebase:`git rebase feature/0.5.0` 恢复储藏的内容:`git stash pop` b) 提交更改: 命令:`git add .` 然后 `git commit -m "临时的提交"` 然后执行rebase:`git rebase feature/0.5.0` 3.rebase完成后,如果之前是提交的更改,可以考虑使用`git reset HEAD~`来撤销临时提交(如果需要的话),但要注意这会让更改回到未暂存状态。 注意:如果选择提交,那么这些更改会作为rebase的一部分被重新应用(可能会产生冲突)。如果选择储藏,则rebase过程中不会包含这些更改,rebase后再应用储藏,此时可能需要解决冲突。 具体步骤示例(储藏方式): 步骤1:储藏当前工作目录的修改 git stash 步骤2:执行rebase git rebase feature/0.5.0 步骤3:恢复储藏的内容 git stash pop 如果在恢复储藏内容时出现冲突,需要手动解决冲突。 示例(提交方式): 步骤1:提交更改 git add . git commit -m "临时提交" 步骤2:rebase git rebase feature/0.5.0 步骤3:如果不想保留这个临时提交,可以使用交互式rebase合并提交(在rebase过程中)或者之后用`git reset`撤销这个提交(但要注意,如果已经rebase,可能需要重置到rebase前的状态再撤销提交,这样比较复杂)。通常,如果临时提交只是为了rebase,可以在rebase完成后,使用`git reset HEAD~`来撤销这个提交,同时保留更改(这时更改处于未暂存状态)。 但是,如果rebase过程中有冲突,那么临时提交已经包含在rebase中,所以不能简单地撤销。因此,更推荐使用储藏的方式。 因此,通常建议使用储藏来处理未提交的更改,这样rebase过程中不会引入额外的提交,并且处理起来更清晰。 所以,推荐步骤: git stash git rebase feature/0.5.0 git stash pop 然后,如果有冲突,解决冲突并提交(如果冲突出现在储藏的内容中)。 </think>### 解决 Git Rebase 报错方案 #### 错误原因分析 您遇到的错误信息: ```bash error: cannot rebase: You have unstaged changes. error: Please commit or stash them. ``` 表明: 1. 存在未跟踪的文件修改(unstaged changes) 2. 这些修改尚未被提交(commit)或储藏(stash) 3. Git 拒绝执行 rebase 操作以防止丢失工作成果 --- ### 解决方案(任选其一) #### 方案一:储藏更改(推荐) ```bash # 1. 储藏当前所有修改 git stash save "暂存修改" # 2. 执行rebase操作 git rebase feature/0.5.0 # 3. 恢复储藏的修改 git stash pop ``` **适用场景**:修改尚未完成,需要临时保存 --- #### 方案二:提交更改 ```bash # 1. 添加所有修改到暂存区 git add . # 2. 创建临时提交 git commit -m "临时提交:rebase前保存" # 3. 执行rebase git rebase feature/0.5.0 # 4. 合并临时提交(可选) git reset HEAD~1 --soft ``` **适用场景**:修改已完成,但不想作为独立提交 --- #### 方案三:丢弃更改(慎用) ```bash # 1. 丢弃所有未提交修改 git checkout -- . # 2. 执行rebase git rebase feature/0.5.0 ``` **适用场景**:确认当前修改可以丢失 --- ### 操作流程图解 ```mermaid graph TD A[检测到未提交修改] --> B{选择处理方式} B -->|临时保存| C[git stash] B -->|创建提交| D[git commit] B -->|放弃修改| E[git checkout -- .] C --> F[git rebase] D --> F E --> F F --> G[git stash pop 恢复修改] ``` ### 注意事项 1. 使用 `git stash pop` 时可能产生冲突,需手动解决 2. 执行 rebase 前建议备份分支:`git checkout -b backup-branch` 3. 复杂场景可使用交互式 rebase:`git rebase -i feature/0.5.0` 4. 完成后验证代码:`git status` 和 `git log --oneline`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值