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

img

场景一、

将在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
posted @ 2023-02-12 20:26  菜阿  阅读(276)  评论(0编辑  收藏  举报