git rebase 用法

随着工程量的提升.git文件夹会变得越来越大。特别是我们只在master一个分支上进行提交,由于里面有很多没用的中间提交,所以希望能够将这些提交删除或者合并,这就用到git rebase这个命令。

有的时候我们有若干个branch,对一个branch进行rebase会影响到其他的branch么?这里做了个实验

rebase对branch的影响

新建git仓库

1
2
3
4
5
6
7
8
9
10
11
git init
echo "1" > test.txt
git add .
git commit -m"1"
echo "2" > test.txt
git add .
git commit -m"2"
echo "3" > test.txt
git add .
git commit -m"3"
git branch 0.1


查看此时log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git log
commit d299f0788909111c0a9d13dfb756f901092c85ce
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:41 2016 +0800
3
commit b601f3c9e5b4b814eefb5889d5110076ec234304
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:27 2016 +0800
2
commit b6a00666d366a77ab03bac5f79b035a705a9d64c
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:07 2016 +0800
1

rebase master

将master分支的3号commit合并到2号commit上


1
2
3
4
$ git rebase -i --root
[detached HEAD 00d6d06] 2
1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/master.

这里选项-i表示使用交互式的修改方法,你可以使用vim等编辑器来进行修改。
选项--root表示从头开始,如果只想对最近的n个提交进行修改,可以使用HEAD~n
rebase命令如果不跟分支,默认为当前分支。
再次查看master的git log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ git log
commit 00d6d06ef697290483cbab5f5e6324491abb5f85
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:27 2016 +0800
2
3
commit 55cb8ae13c8cef61c3bf7b89ce3001eac29de630
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:07 2016 +0800
1

发现已经成功合并。
这里额外说明一下,提交2和提交3的备注信息”2”和”3”被合并到了一起作为一个新提交,这是由于squash选项造成的,如果我们选择fixup选项,那么提交2和提交3会直接消失

1
2
3
4
5
$ git log
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Fri Sep 22 19:01:48 2017 +0800
1

回到我们刚才squash得到的结果,查看0.1分支的git log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ git checkout 0.1
$ git log
commit d299f0788909111c0a9d13dfb756f901092c85ce
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:41 2016 +0800
3
commit b601f3c9e5b4b814eefb5889d5110076ec234304
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:27 2016 +0800
2
commit b6a00666d366a77ab03bac5f79b035a705a9d64c
Author: unknown <calvinneo1995@gmail.com>
Date: Sat Nov 19 18:12:07 2016 +0800
1

发现并没有变化
于是结论很显然,git rebase只会影响当前分支。rebase会导致git生成一系列全新的提交,但内容包括时间是保留的。

rebase对annotation tag的影响

新建tag

按照上面的步骤重新构建了一个git仓库,下面对提交2(a8ede39f9ff56c4a43ee89e80ba30c0aad8f2f26)打tag

1
$ git tag -a v0.1 a8ede3

切换到v0.1的tag

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git checkout v0.1
Note: checking out 'v0.1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at a8ede39... 2

注意到这里说明现在在一个’detached HEAD’ state,这是因为tag 相当于是一个快照,是不能更改它的代码的,如果要在 tag 代码的基础上做修改,新建一个分支。
下面看一下这个detached HEAD的提交历史

1
2
3
4
5
6
7
8
9
10
11
12
$ git log
commit ed4c38d8247a454b49a97962006ccaa659cae32c
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Sun Jan 22 14:49:32 2017 +0800
2
commit 2b84833dd18c6802893029c7c0dfaa781ec20aa8
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Sun Jan 22 14:49:32 2017 +0800
1

发现提交1还在
下面回到master分支,并将master分支压缩成一个分支

1
2
3
4
$ git rebase -i --root
pick fea1e3c 1
s a8ede39 2
s 9b9a18c 3

再次查看log

1
2
3
4
5
6
7
8
9
10
11
12
$ git log
commit a8ede39f9ff56c4a43ee89e80ba30c0aad8f2f26
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Sun Jan 22 14:49:32 2017 +0800
2
commit fea1e3cf0a1939544ae01f1160d2c87c2960e661
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Sun Jan 22 14:49:32 2017 +0800
1

发现tag的log并没有改变

git rebase的合并冲突解决

这常发生在试图将一个分支整体与另一个分支合并的情况下
首先使用git status查看冲突的文件,解决冲突后git add .,然后git rebase --continue
在任何时候如果发现之前的冲突解决错误,可以通过git rebase --abort回滚到rebase前的状态

其他的修改提交的方法

amend

git commit --amend指令能够修改最近的一次提交。不过commit id会变
amend前

1
2
3
4
5
6
$ git log
commit 544c674ff6ad80b87d871a1db1fe01a37536804c
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Fri Sep 22 19:01:48 2017 +0800
1

amend后

1
2
3
4
5
6
$ git log
commit 32158167b057faacc5c91c1e63451e28612c13f6
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Fri Sep 22 19:01:48 2017 +0800
1

不过如果在amend之前将原commit push到远程仓库了的话,那会引起冲突,最省事的办法就是很不优雅地git push origin --force。对于gitlab这样的代码仓库,可能还要将Branch Protect去掉才能强行push。

hard reset