Git命令列表--git-rebase
Git Rebase
名称
git-rebase - 在另一个基本提示之上重新应用提交(Reapply commits on top of another base tip)
语法(概要)
git rebase [-i | --interactive] [<options>] [--exec <cmd>]
[--onto <newbase> | --keep-base] [<upstream> [<branch>]]
git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
--root [<branch>]
git rebase (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)
如果指定了 <branch>,git rebase将在执行任何其他操作之前执行自动 git switch <branch>。否则它将保留在当前分支上。如果命令行未指定<upstream>,则将使用分支中配置的<upstream>配置。 并使用--fork-point选项。如果您当前不在任何分支上,或者如果当前分支没有配置的上游,rebase将中止。
当前分支中提交但不在<upstream>中的所有更改都保存到临时区域
准备
## 初始化仓库,然后添加一些提交历史
$ git init
$ echo 'add file A in master ' > fileA
$ git add . && git commit -m 'add file A in master'
$ echo 'edit file A in master ' > fileA
$ git add . && git commit -m 'edit file A in master'
$ git log --graph --pretty=oneline master
* d096df35b3835d89fdcc7cbc23d5d5db8852e86e (HEAD -> master) edit file A in master
* dfa4b1c7f405594a74acb9d2cbb5358e4f5bb907 add file A in master
## 在master的基础上创建dev分支,并添加一些提交历史
$ git checkout -b dev
$ echo 'add file B in dev ' > fileB
$ git add . && git commit -m 'add file B in dev'
$ echo 'edit file A in dev ' > fileA
$ git log --graph --pretty=oneline master dev
$ git add . && git commit -m 'edit file A in dev '
* b8f111c1b8845ce908b93fcf20a6e51d02c84b01 (HEAD -> dev) edit file A in dev
* f926972a602583099611cb1e0bd6cfbc218b5c29 add file B in dev
* d096df35b3835d89fdcc7cbc23d5d5db8852e86e (master) edit file A in master
* dfa4b1c7f405594a74acb9d2cbb5358e4f5bb907 add file A in master
## 切换回master分支,并添加一些提交历史
$ git checkout master
$ echo 'edit file A in master agin' > fileA
$ git add . && git commit -m 'edit file A in master agin'
## 提交历史
$ git log --graph --pretty=reference master dev
* 410a3c8 (edit file A in master agin, 2022-11-18)
| * b8f111c (edit file A in dev, 2022-11-18)
| * f926972 (add file B in dev, 2022-11-18)
|/
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
场景一、master变基到dev
git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase> | --keep-base] [<upstream> [<branch>]]
## 简单变基1 把master变基到dev上
user@name MINGW64 /d/VSCode/testrebase (master)
$ git rebase dev
Auto-merging fileA
CONFLICT (content): Merge conflict in fileA
Could not apply 410a3c8... edit file A in master agin
## fileA有冲突,410a3c8提交不能在dev上重演(Reapply),可以根据提示进行下一步操作
# 使用git add/rm 和 git rebase --continue 解决并继续变基(rebase)
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
# 使用 git rebase --skip 路过这个冲突的提交
hint: You can instead skip this commit: run "git rebase --skip".
# 使用 git rebase --abort 停止整个变基(rebase)
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
##
$ git rebase --abort
user@name MINGW64 /d/VSCode/testrebase (master)
$ git log --graph --pretty=reference master dev
* 410a3c8 (edit file A in master agin, 2022-11-18)
| * b8f111c (edit file A in dev, 2022-11-18)
| * f926972 (add file B in dev, 2022-11-18)
|/
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
停止变基 --abort
## 使用 git rebase --abort 停止整个变基(rebase),提交历史恢复原样
$ git rebase --abort
user@name MINGW64 /d/VSCode/testrebase (master)
$ git log --graph --pretty=reference master dev
* 410a3c8 (edit file A in master agin, 2022-11-18)
| * b8f111c (edit file A in dev, 2022-11-18)
| * f926972 (add file B in dev, 2022-11-18)
|/
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
跳过冲突提交 --skip
## # 使用 git rebase --skip 路过这个冲突的提交
user@name MINGW64 /d/VSCode/testrebase (master|REBASE 1/1)
$ git rebase dev
$ git rebase --skip
Successfully rebased and updated refs/heads/master.
user@name MINGW64 /d/VSCode/testrebase (master)
$ git log --graph --pretty=reference master dev
* b8f111c (edit file A in dev, 2022-11-18)
* f926972 (add file B in dev, 2022-11-18)
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
## 410a3c8 (edit file A in master agin, 2022-11-18) 提交不见了
解决冲突后继续 --continue
## 恢复到原来的提交,找加跳过的提交(因为是刚刚丢弃,Git还没有压缩,所以被丢弃的提交410a3c8可以直接找回)
user@name MINGW64 /d/VSCode/testrebase (master)
$ git reset --hard 410a3c8
HEAD is now at 410a3c8 edit file A in master agin
user@name MINGW64 /d/VSCode/testrebase (master)
$ git log --graph --pretty=reference master dev
* 410a3c8 (edit file A in master agin, 2022-11-18)
| * b8f111c (edit file A in dev, 2022-11-18)
| * f926972 (add file B in dev, 2022-11-18)
|/
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
$ git rebase dev
## 解决冲突(add&commit),并继续变基(--continue)
$ git add . && git commit -m 'resolved conflict on master rebase dev' && git rebase --continue
[detached HEAD a1cc8a3] resolved conflict on master rebase dev
1 file changed, 4 insertions(+)
Successfully rebased and updated refs/heads/master.
user@name MINGW64 /d/VSCode/testrebase (master)
$ git log --graph --pretty=reference master dev
* a1cc8a3 (resolved conflict on master rebase dev, 2022-11-18)
* b8f111c (edit file A in dev, 2022-11-18)
* f926972 (add file B in dev, 2022-11-18)
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
## 冲突解决后,出现冲突的提交在dev上重演(Reapply)失败,被冲突解决的提交取代
场景二、 dev变基到master
## 恢复提交历史,并切换到dev
$ git reset --hard 410a3c8
$ git checkout dev
Switched to branch 'dev'
user@name MINGW64 /d/VSCode/testrebase (dev)
$ git log --graph --pretty=reference master dev
* 410a3c8 (edit file A in master agin, 2022-11-18)
| * b8f111c (edit file A in dev, 2022-11-18)
| * f926972 (add file B in dev, 2022-11-18)
|/
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
## 变基开始,同样会出现冲突
$ git rebase master
Auto-merging fileA
CONFLICT (content): Merge conflict in fileA
Could not apply b8f111c... edit file A in dev
停止变基 --abort
## 使用 git rebase --abort 停止整个变基(rebase),提交历史恢复原样
$ git rebase --abort
路过冲突提交 --skip
## # 使用 git rebase --skip 路过这个冲突的提交
$ git rebase dev
## 提交 b8f111c 出现冲突
Could not apply b8f111c... edit file A in dev
$ git rebase --skip
Successfully rebased and updated refs/heads/dev.
user@name MINGW64 /d/VSCode/testrebase (dev)
$ git log --graph --pretty=reference master dev
* 92c9d76 (add file B in dev, 2022-11-18)
* 410a3c8 (edit file A in master agin, 2022-11-18)
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
## 冲突的提交b8f111c被跳过(丢弃),没胡冲突的提交92c9d76被正常保留下来
## 所以要慎用--skip
## 回退到原样,并且再次添加一个提交历史
user@name MINGW64 /d/VSCode/testrebase (dev)
$ git reset --hard b8f111c
HEAD is now at b8f111c edit file A in dev
$ echo 'edit file A in dev one more time' > fileA
$ git add . && git commit -m 'edit file A in dev one more time'
[dev 423553f] edit file A in dev one more time
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --graph --pretty=reference master dev
* 423553f (edit file A in dev one more time, 2022-11-18)
* b8f111c (edit file A in dev, 2022-11-18)
* f926972 (add file B in dev, 2022-11-18)
| * 410a3c8 (edit file A in master agin, 2022-11-18)
|/
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
解决冲突后继续 --continue
## 解决冲突(add&commit),并继续变基(--continue)
$ git rebase master
Auto-merging fileA
CONFLICT (content): Merge conflict in fileA
error: could not apply b8f111c... edit file A in dev
Could not apply b8f111c... edit file A in dev
user@name MINGW64 /d/VSCode/testrebase (dev|REBASE 2/3
## 解决冲突一
$ git add . && git commit -m 'resolved conflict 1 ' && git rebase --continue
[detached HEAD 975c926] resolved conflict 1
1 file changed, 4 insertions(+)
Auto-merging fileA
CONFLICT (content): Merge conflict in fileA
Could not apply 423553f... edit file A in dev one more time
## 再次出现冲突
user@name MINGW64 /d/VSCode/testrebase (dev|REBASE 3/3)
$ git add . && git commit -m 'resolved conflict 2' && git rebase --continue
[detached HEAD 8473022] resolved conflict 2
1 file changed, 4 insertions(+)
Successfully rebased and updated refs/heads/dev.
## 因为是重演(Reapply),所以修改fileA文件的再次都会出现冲突
$ git log --graph --pretty=reference master dev
* 8473022 (resolved conflict 2, 2022-11-18)
* 975c926 (resolved conflict 1, 2022-11-18)
* fd7c2ad (add file B in dev, 2022-11-18)
* 410a3c8 (edit file A in master agin, 2022-11-18)
* d096df3 (edit file A in master, 2022-11-18)
* dfa4b1c (add file A in master, 2022-11-18)
选项
--onto 官方示例
将分支特定范围的提交历史在指定的分支上重放
## 先看看当前分支的状态
xuyuansheng@XUYUANSHENG MINGW64 /d/VSCode/testrebase (onto)
$ git log --graph --pretty=oneline master onto dev
* 08339fcb20a71259422e9bb9e2ae3c05e4ae42a7 (HEAD -> onto) edit file C in onto branch
* 496c40e842375a3dc72a1a88dc4a7dbc05cdff16 add file C in onto branch
| * 410a3c8912c17de76f516a578b911a0e66169921 (master) edit file A in master agin
| | * b8f111c1b8845ce908b93fcf20a6e51d02c84b01 (dev) edit file A in dev
| |/
|/|
* | f926972a602583099611cb1e0bd6cfbc218b5c29 add file B in dev
|/
* d096df35b3835d89fdcc7cbc23d5d5db8852e86e edit file A in master
* dfa4b1c7f405594a74acb9d2cbb5358e4f5bb907 add file A in master
场景一、
将在onto分支但是不在dev分支上的提交在master上重放上,即将496c40e842,08339fcb20a这两个提交合并到master
## 变基
xuyuansheng@XUYUANSHENG MINGW64 /d/VSCode/testrebase (onto)
$ git rebase --onto=master dev onto
Successfully rebased and updated refs/heads/onto.
##此时onto分支的基已经变化 b8f111c1b8 --> 410a3c8912c1 ,原来的onto分支的两个提交已经在master上重放 了
* 299232d413 (HEAD -> onto) edit file C in onto branch ##这是重放后新生成的提交
* f653f070d add file C in onto branch ##这是重放后新生成的提交
* 410a3c8912c (master) edit file A in master agin
| * 08339fcb20 edit file C in onto branch ## 这里是原来的onto分支
| * 496c40e842375 add file C in onto branch ## 这里是原来的onto分支
| | * b8f111c1b8 (dev) edit file A in dev
| |/
| * f926972a60258 add file B in dev
|/
* d096df35b38 edit file A in master
* dfa4b1c7f40 add file A in master
理解:
从上面的命令和运行结果,可以理解上面的命令的作用是将提交 (dev(HEAD),onto(HEAD)] 在master(HEAD)上重放,那如果将命令换为 git rebase --onto=410a3c8912c b8f111c1b88 08339fcb2
效果应该是一模一样的。
验证:
## 变基,结果变成了分离头指针
$ git rebase --onto=410a3c8912c b8f111c1b88 08339fcb2
Successfully rebased and updated detached HEAD.
xuyuansheng@XUYUANSHENG MINGW64 /d/VSCode/testrebase ((e139a5e...))
## 将分离的头指针新建为一个新分支 onto_new
$ git checkout -b onto_new
Switched to a new branch 'onto_new'
## 看结果发现,分支onto和onto_new,08339fcb2(分离的头指针) 都有相同的提交历史
# 3575cda1227,f653f070,496c40e842 这三个提交虽然hash值不同,但是实际是同一个提交在经过再次变基后的结果
# e139a5e9966,299232d41,08339fcb2 这个三个同理
$ git log --graph --pretty=oneline master onto onto_new dev 08339fcb20a71
* e139a5e9966 (HEAD -> onto_new) edit file C in onto branch ## 第二次变基后
* 3575cda1227 add file C in onto branch
| * 299232d41 (onto) edit file C in onto branch ## 第一次变基后
| * f653f070 add file C in onto branch
|/
* 410a3c8912 (master) edit file A in master agin
| * 08339fcb2 edit file C in onto branch # 最早的onto分支提交
| * 496c40e842 add file C in onto branch
| | * b8f111c (dev) edit file A in dev
| |/
| * f926972a add file B in dev
|/
* d096df35b edit file A in master
* dfa4b1c7f add file A in master
进阶:
## 先把08339fcb2保存到分支中,这样更方便查看理解
$ git checkout -b old_onto 08339fcb20a71
Switched to a new branch 'old_onto'
$ git log --graph --pretty=oneline master onto onto_new dev old_onto
* e139a5e9966fbcb727709d11bbde7bade2a0e60e (onto_new) edit file C in onto branch
* 3575cda12270933a682a0416a237dd52e57efea3 add file C in onto branch
| * 299232d4137bffc98cb747f75b0f8415bb08a556 (onto) edit file C in onto branch
| * f653f070d83d0693af7761eecfa720bfe72b59ca add file C in onto branch
|/
* 410a3c8912c17de76f516a578b911a0e66169921 (master) edit file A in master agin
| * 08339fcb20a71259422e9bb9e2ae3c05e4ae42a7 (HEAD -> old_onto) edit file C in onto branch
| * 496c40e842375a3dc72a1a88dc4a7dbc05cdff16 add file C in onto branch
| | * b8f111c1b8845ce908b93fcf20a6e51d02c84b01 (dev) edit file A in dev
| |/
| * f926972a602583099611cb1e0bd6cfbc218b5c29 add file B in dev
|/
* d096df35b3835d89fdcc7cbc23d5d5db8852e86e edit file A in master
* dfa4b1c7f405594a74acb9d2cbb5358e4f5bb907 add file A in master
## 以上为当前的分支状态
目标: 将分支old_onto的倒数第二个提交在master上重放,然后将基保存为新的分支onto_3
## 理解命令:目标分支master ,起点old_onto倒数第二个提交的父提交 终点 old_onto分支的倒数第二个提交,其中起点提交是不包含在重放操作中的 (f926972a6,496c40e842375] ,因为是要新建分支,所以用分离头指针,然后新建再分支的方式
$ git rebase --onto=master f926972a6 496c40e842375
Successfully rebased and updated detached HEAD.
xuyuansheng@XUYUANSHENG MINGW64 /d/VSCode/testrebase ((53287a8...))
$ git checkout -b onto_3
Switched to a new branch 'onto_3'
## 结果
$ git log --graph --pretty=oneline master old_onto onto onto_new onto_3
* 53287a85349f(HEAD -> onto_3) add file C in onto branch
| * e139a5e9966f (onto_new) edit file C in onto branch
| * 3575cda12270 add file C in onto branch
|/
| * 299232d4137b (onto) edit file C in onto branch
| * f653f070d83d add file C in onto branch
|/
* 410a3c8912c17de (master) edit file A in master agin
| * 08339fcb20a7 (old_onto) edit file C in onto branch
| * 496c40e84237 add file C in onto branch
| * f926972a6025 add file B in dev
|/
* d096df35b3835d edit file A in master
* dfa4b1c7f40559 add file A in master
-i / --interactive
交互式的rebase,可以修改提交信息,合并提交等。
pick 410a3c8 edit file A in master agin
pick f653f07 add file C in onto branch
pick 299232d edit file C in onto branch
# Rebase b8f111c..299232d onto b8f111c (3 commands)
#
# Commands:
# p, pick <commit> = use commit 使用提交
# r, reword <commit> = use commit, but edit the commit message 使用提交且编辑提交信息
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit 使用提交且融合到前面提交中去
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified); use -c <commit> to reword the commit message
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
--show-current-patch
在交互式rebase中或在rebase因冲突而停止时显示当前补丁(修改)
## rebase变基冲突后
xuyuansheng@XUYUANSHENG MINGW64 /d/VSCode/testrebase (detached HEAD|REBASE 1/1)
$ git rebase --show-current-patch
commit 08339fcb20a71259422e9bb9e2ae3c05e4ae42a7 (old_onto)
Author: yuansheng.xu <804288658@qq.com>
Date: Sat Nov 26 09:43:00 2022 +0800
edit file C in onto branch
diff --git a/fileC b/fileC
index a26e898..1e2894b 100644
--- a/fileC
+++ b/fileC
@@ -1 +1 @@
-add file C in onto branch
+edit file C in onto branch