场景

在开发过程中,将完整的一个功能拆分成几个部分进行开发commit,完成功能开发后,需要将这些commit整合成完整的一个commit。

实践

可以看到,下面的b390c28、58b4bfd、1d40e3a、1580123分支其实都是干了同一件事,即创建了一个index页面,其中包括页面的一些元素渲染、js等。这里将这些分支整合成一个。

1
2
3
4
5
6
7
8
9
10
 G:\mygitea\GitLearn\learn01   master 
$ git log --oneline --graph master
* 5bc7fdf (HEAD -> master) rename test
* 012ae46 e1
* b390c28 (origin/master) add modified html css
* 58b4bfd add js
* 1d40e3a add css
* 1580123 add html images file
* 3cd7fd8 add readme
* df647fe Initial commit

变更以前的commit:

1
git rebase -i 3cd7fd8

在合并commit时,必须选一个commit作为“基”(该commit前面得是pick),将其他commit与其合并。这里我们选择1580123这个commit作为“基”。使用squash命令进行合并。

squash:变更的文件都保留,并将这些文件合并到前面的commit中去

保存改动之后就会跳转到下面的页面:

保存后退出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
[detached HEAD 87118bd] create complete web page by merge 4 commit
Author: GitHub Whiteco-okie <GitHub 1961663351@qq.com>
Date: Thu May 5 09:19:20 2022 +0800
4 files changed, 135 insertions(+)
create mode 100644 images/git-logo.png
create mode 100644 index.html
create mode 100644 js/script.js
create mode 100644 styles/style.css
error: Your local changes to the following files would be overwritten by merge:
README.md
Please commit your changes or stash them before you merge.
Aborting
hint: Could not execute the todo command
hint:
hint: pick 012ae4631218bd877eb609f99f9d78c27dc49bdb e1
hint:
hint: It has been rescheduled; To edit the command before continuing, please
hint: edit the todo list first:
hint:
hint: git rebase --edit-todo
hint: git rebase --continue
Could not apply 012ae46... e1

G:\mygitea\GitLearn\learn01   HEAD detached at 87118bd ± 
$ git log --oneline
87118bd (HEAD) create complete web page by merge 4 commit
3cd7fd8 add readme
df647fe Initial commit

G:\mygitea\GitLearn\learn01   HEAD detached at 87118bd ± 
$ git branch -av
* (no branch, rebasing master) 87118bd create complete web page by merge 4 commit
fix_css 9fa98d6 change background color
master 5bc7fdf [ahead 2] rename test
temp e1514cf test1
remotes/origin/master b390c28 add modified html css

G:\mygitea\GitLearn\learn01   HEAD detached at 87118bd ± 
$ git branch merge_web 87118bd

G:\mygitea\GitLearn\learn01   HEAD detached at 87118bd ± 
$ git log --oneline --all -graph
fatal: unrecognized argument: -graph

G:\mygitea\GitLearn\learn01   HEAD detached at 87118bd ± 
$ git log --oneline --all --graph
* 87118bd (HEAD, merge_web) create complete web page by merge 4 commit
| * 9fa98d6 (fix_css) change background color
| | * e1514cf (temp) test1
| | * a1909d9 add 5bc7fdf file
| | * 5bc7fdf (master) rename test
| |/
| * 012ae46 e1
| * b390c28 (origin/master) add modified html css
| * 58b4bfd add js
| * 1d40e3a add css
| * 1580123 add html images file
|/
* 3cd7fd8 add readme

可以看到,上面的保存出现了问题,但是git通过分离头指针的方式帮我们保存了这次的变更,这里我们给HEAD所在commit分配一个分支,并命名为”merge_web”。从效果上看,完成了四个commit的合并。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 G:\mygitea\GitLearn\learn01   master 
$ git branch web_merge 87118bd

G:\mygitea\GitLearn\learn01   master 
$ git log --oneline --all --graph
* 87118bd (merge_web) create complete web page by merge 4 commit
| * 9fa98d6 (fix_css) change background color
| | * e1514cf (temp) test1
| | * a1909d9 add 5bc7fdf file
| | * 5bc7fdf (HEAD -> master) rename test
| |/
| * 012ae46 e1
| * b390c28 (origin/master) add modified html css
| * 58b4bfd add js
| * 1d40e3a add css
| * 1580123 add html images file
|/
* 3cd7fd8 add readme
* df647fe Initial commit

总结

git rebase -i 开始commit [结束commit], 在执行这个命令时, 如果没有指定 结束commit,那么结束commit 默认为当前分支最新的 commit,那么rebase 结束后会自动更新当前分支指向的 commit, 如果指定了结束 commit,而且结束 commit不是当前分支最新的 commit,那么rebase 后会有生成一个 游离的 head,,而且当前分支指向的commit 不会更新。

Q1:如果想撤销这次合并,应该怎么做呢?

你指不想要本地刚merge出来的commit,对吗?如果工作区、暂存区和HEAD一起回答merge前,执行 git reset —hard HEAD^ 就行啦

Q2:合并commit时,常规语法是:git rebase -i 父节点commitID,如果前面没有父节点怎么写呢?

命令行没法写出来(因为自己本身已经是最根的那个commit了),当交互命令回车后,会出现设置界面,我们不妨自己手工把最根部的那个commit添加进来,并配置好对应的策略。

Q3:演示了将4个commit合并成了一个,那如果有一个分支是从其中的一个commit分出去的,合并完成后,之前的分支会怎么样呢?

好问题,可以实践一下。我估摸着从那个有分叉的commit及之前的commit都会保留的,即使其他分支做了合并。