0%

Mosh的Git课程笔记(4)--Branching

Mosh的课程网址

What are Branches?

  • master分支一般存着stable的commit版本,另一个分支如feature存着还不stable的版本,等到改到完善了,才将feature分支merge到master中。
  • MASTER指针指向master分支中最近commit的版本,其他分支同理。
  • HEAD指针可以指向master,也可以指向feature,用于方便地调整working branch。

4_01

Working with Branches

创建分支:

1
$ git branch bugfix

查看现有分支,其中标*的表示当前working branch:

1
2
3
$ git branch
bugfix
* master

也可以这样查看当前working branch:

1
2
3
$ git status
On branch master
nothing to commit, working tree clean

切换到bugfix branch:

1
2
$ git switch bugfix
Switched to branch 'bugfix'

Shortcut:创建并切换分支

1
$ git switch -C bugfix

-C表示creating


重命名分支:

1
2
3
(bugfix)$ git branch -m bugfix bugfix-signup-form

(bugfix-signup-form)$

假如在创建这个bugfix-signup-form分支之前,在master创建了一个audience.txt文件,内容如下:

1
2
3
4
AUDIENCE

This course is for anyone who wants to learn Git.
No prior experience is required.

创建并切换当前分支为bugfix-signup-form分支之后将该文件的内容改为:

1
2
3
WHO THIS COURSE IS FOR 
======================
This course is for anyone who wants to learn Git.

并提交更改:

1
2
3
4
5
6
7
(bugfix-signup-form)$ code audience.txt

(bugfix-signup-form)$ git add .

(bugfix-signup-form)$ git commit -m "fix the bug that prevented the users from signing up"
[bugfix-signup-form 7a5cdb3] fix the bug that prevented the users from signing up
1 file changed, 3 insertions(+), 4 deletions(-)

查看一下,HEAD指向当前分支:

1
2
3
(bugfix-signup-form)$ git log --oneline
7a5cdb3 (HEAD -> bugfix-signup-form) fix the bug that prevented the users from signing up
82ca774 (master) add audience.txt

切换回master分支并查看audience.txt内容:

1
2
3
4
(bugfix-signup-form)$ git switch master
Switched to branch 'master‘

(master)$ code audience.txt

发现audience.txt内容依然是旧版的:

1
2
3
4
AUDIENCE

This course is for anyone who wants to learn Git.
No prior experience is required.

查看修改log,会发现看不到bugfix-signup-form分支的更改log:

1
2
(master)$ git log --oneline
82ca774 (HEAD -> master) add audience.txt

除非用—all:

1
2
3
(master)$ git log --oneline --all
7a5cdb3 (bugfix-signup-form) fix the bug that prevented the users from signing up
82ca774 (HEAD -> master) add audience.txt

如果想删除bugfix-signup-form分支,由于还没merge,所以会报错。若确定真的要删,用-D:

1
2
3
(master)$ git branch -d bugfix-signup-form
error: The branch 'bugfix-signup-form' is not fully merged.
If you are sure you want to delete it, run 'git branch -D bugfix-signup-form'.

Comparing Branches

在将分支merge到master之前,先看看改了啥:

1
2
3
4
5
6
(master)$ git log master..bugfix-signup-form
commit 7a5cdb3ea29a72530f598fa7fee1358a6c4dcb23 (bugfix-signup-form)
Author: Stone <masaike@qq.com>
Date: Fri Apr 23 21:56:15 2021 +0800

fix the bug that prevented the users from signing up

查看具体改了啥内容(由于当前分支就是master, master..也可以省略不写):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(master)$ git diff master..bugfix-signup-form
diff --git a/audience.txt b/audience.txt
index 01fd2e1..ecbc229 100644
--- a/audience.txt
+++ b/audience.txt
@@ -1,4 +1,3 @@
-AUDIENCE
-
-This course is for anyone who wants to learn Git.
-No prior experience is required.
\ No newline at end of file
+WHO THIS COURSE IS FOR
+======================
+This course is for anyone who wants to learn Git.
\ No newline at end of file

看简略的修改状态信息:

1
2
(master)$ git diff --name-status bugfix-signup-form
M audience.txt

Stashing

bugfix-signup-form分支对audience.txt修改后,该分支尚未merge到master分支,此时master分支却又对audience.txt进行了修改,此时不允许切换到分支:

1
2
3
4
5
6
7
(master)$ git switch bugfix-signup-form
error: Your local changes to the following files would be overwritten by checkout:
audience.txt
Please commit your changes or stash them before you switch branches.
Aborting

(master)$

如果我们还不想commit在master分支对audience.txt的修改,可以先用stash保存工作现场:

1
2
(master)$ git stash push -m "New tax rules."
Saved working directory and index state On master: New tax rules.

By default, new untracked files are not included in the stash, 要用-a放入stash:

1
2
3
4
5
6
7
8
9
10
(master)$ echo hello > newfile.txt

(master)$ git status -s
?? newfile.txt

(master)$ git stash push -m "My new stash with newfile1.txt"
No local changes to save //------这样不行的--------------

(master)$ git stash push -am "My new stash"
Saved working directory and index state On master: My new stash

查看stash:

1
2
3
(master)$ git stash list
stash@{0}: On master: My new stash
stash@{1}: On master: New tax rules.

Stashing了就可以成功切换分支了:

1
2
(master)$ git switch bugfix-signup-form
Switched to branch 'bugfix-signup-form'

在分支的工作做完,换回master分支,想恢复工作现场,先看看改了啥(根据stash号):

1
2
3
(master)$ git stash show 1
audience.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

可以的话就apply到本地目录:

1
(master)$ git stash apply 1

用 git stash apply恢复后,保存的现场并不删除,需要用git stash drop 删除:

1
2
(master)$ git stash drop 1
Dropped refs/stash@{1} (92b61ede11aa9f3c076aed7c1409c7cc683e4efb)

清除全部stash:

1
(master)$ git stash clear

Merging

1
2
3
/******Merges*******/
👉 Fast-forward merges (if branches have not diverged)
👉 3-way merges (if branches have diverged)

Fast-forward merges

当前分支合并另一个分支的时候,如果合并的过程中没有冲突,则会通过直接移动两个分支的指针,来达到合并。

4_02

只有bugfix分支在改动,改到stable了,直接移动master指针到bugfix指向的位置,然后丢弃bugfix指针就行了。


3-way merges

4_03

两个分支都在改动,最后merge到一起。


Fast-forward Merges

1
2
3
(master)$ git log --oneline --all --graph
* 7a5cdb3 (bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 (HEAD -> master) add audience.txt
1
2
3
4
5
(master)$ git merge bugfix-signup-form
Updating 82ca774..7a5cdb3
Fast-forward
audience.txt | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
1
2
3
(master)$ git log --oneline --all --graph
* 7a5cdb3 (HEAD -> master, bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 add audience.txt

No fast-forward merges

merge 了 master 和 bugfix-signup-form 分支后,创建并切换到新分支bugfix-login-form。此时假如对已有文件 file1.js 进行 modify 并 commit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(master)$ git switch -C bugfix-login-form
Switched to and reset branch 'bugfix-login-form'

(bugfix-login-form)$ code file1.js

(bugfix-login-form)$ git add .

(bugfix-login-form)$ git commit -m "update file1.js"
[bugfix-login-form 1ad00a7] update file1.js
1 file changed, 1 insertion(+), 1 deletion(-)

(bugfix-login-form)$ git log --oneline --all --graph
* 1ad00a7 (HEAD -> bugfix-login-form) update file1.js
* 7a5cdb3 (master, bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 add audience.txt

此时master和bugfix-signup-form指向同一commit,bugfix-login-form 指向本 modify commit。然后用 No fast-forward 的方式来合并两分支,可以看到 git merge 命令的返回结果中不再有“Fast-forward”出现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(bugfix-login-form)$ git switch master
Switched to branch 'master'

(master)$ git merge --no-ff bugfix-login-form
Merge made by the 'recursive' strategy.
file1.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

(master)$ git log --oneline --all --graph
* 9612ab4 (HEAD -> master) Merge branch 'bugfix-login-form'
|\
| * 1ad00a7 (bugfix-login-form) update file1.js
|/
* 7a5cdb3 (bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 add audience.txt
1
2
3
4
/**使用No fast-forward merges的优缺点(两派观点)**/
👉 CONS:pollutes the history (those who prefer linear history)
👉 PROS:1) True reflection of history
2) Allow reverting a feature (easier for us to undo a feature)

如果使用No fast-forward merges:

4_04

红色标记的commit 是F1和F2的结合,如果红标的commit是个bad commit, 蓝标的commit 是和红标完全相反的commit,我们只需要revert 一个commit就行了。

而如果使用fast-forward merges:

4_05

要revert两个commit,会更加复杂。

3-way merges

创建新分支并在此分支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
(master)$ git switch -C feature-change-password
Switched to a new branch 'feature-change-password'

(feature-change-password)$ git log --oneline --all --graph
* 9612ab4 (HEAD -> feature-change-password, master) Merge branch 'bugfix-login-form'
|\
| * 1ad00a7 (bugfix-login-form) update file1.js
|/
* 7a5cdb3 (bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 add audience.txt

(feature-change-password)$ echo hello > change-password.txt

(feature-change-password)$ git add .

(feature-change-password)$ git commit -m "Build the change password form."
[feature-change-password 49f4f13] Build the change password form.
1 file changed, 1 insertion(+)
create mode 100644 change-password.txt

(feature-change-password)$ git log --oneline --all --graph
* 49f4f13 (HEAD -> feature-change-password) Build the change password form.
* 9612ab4 (master) Merge branch 'bugfix-login-form'
|\
| * 1ad00a7 (bugfix-login-form) update file1.js
|/
* 7a5cdb3 (bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 add audience.txt

返回master分支并在此分支commit新修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(feature-change-password)$ git switch master
Switched to branch 'master'

(master)$ code audience.txt

(master)$ git commit -am "Update audience.txt"
[master 4aa3534] Update audience.txt
1 file changed, 1 insertion(+), 1 deletion(-)

(master)$ git log --oneline --all --graph
* 4aa3534 (HEAD -> master) Update audience.txt
| * 49f4f13 (feature-change-password) Build the change password form.
|/
* 9612ab4 Merge branch 'bugfix-login-form'
|\
| * 1ad00a7 (bugfix-login-form) update file1.js
|/
* 7a5cdb3 (bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 add audience.txt

Merge这两个分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(master)$ git merge feature-change-password
Merge made by the 'recursive' strategy.
change-password.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 change-password.txt

(master)$ git log --oneline --all --graph
* 91dd8b9 (HEAD -> master) Merge branch 'feature-change-password'
|\
| * 49f4f13 (feature-change-password) Build the change password form.
* | 4aa3534 Update audience.txt
|/
* 9612ab4 Merge branch 'bugfix-login-form'
|\
| * 1ad00a7 (bugfix-login-form) update file1.js
|/
* 7a5cdb3 (bugfix-signup-form) fix the bug that prevented the users from signing up
* 82ca774 add audience.txt

Viewing the Merged Branches

查看merge到master的branch:

1
2
3
4
5
(master)$ git branch --merged
bugfix-login-form
bugfix-signup-form
feature-change-password
* master

这些分支已经merge了,就可以安全地删除了:

1
2
(master)$ git branch -d bugfix-login-form
Deleted branch bugfix-login-form (was 1ad00a7).

查看还没merge的分支:

1
(master)$ git branch --no-merged

Merge Conflicts

1
2
3
4
Conflicts (difference in two branches)
👉 Change1, Change2
👉 Change, Delete
👉 Add1, Add2

Demo:

  1. 创建新分支bugfix-change-password并提交对change-password.txt的修改
1
2
3
4
5
6
7
8
(master)$ git switch -C bugfix-change-password
Switched to a new branch 'bugfix-change-password'

(bugfix-change-password)$ code change-password.txt

(bugfix-change-password)$ git commit -am "Update change-password.txt"
[bugfix-change-password.txt 7e3da10] Update change-password.txt
1 file changed, 2 insertions(+)
  1. 切换到master分支,提交对change-password.txt的修改
1
2
3
4
5
6
7
8
(bugfix-change-password)$ git switch master
Switched to branch 'master'

(master)$ code change-password.txt

(master)$ git commit -am "Update change-password.txt"
[master adebbcf] Update change-password.txt
1 file changed, 2 insertions(+)
  1. Merge两个分支时出现conflict:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(master)$ git merge bugfix-change-password
merge: bugfix-change-password - not something we can merge

(master)$ git merge bugfix-change-password.txt
Auto-merging change-password.txt
CONFLICT (content): Merge conflict in change-password.txt
Automatic merge failed; fix conflicts and then commit the result.

(master|MERGING)$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)

Unmerged paths: //---------merge失败的原因所在------------------
(use "git add <file>..." to mark resolution)
both modified: change-password.txt

no changes added to commit (use "git add" and/or "git commit -a")

看看文件:

4_06

VSCode提供了几种(可以直接点击的):Accept Current Change等三种方法消除conflict

也可以手动改,但此时不能增加新的内容,只能选择两个分支的修改内容。最后改为:

1
2
3
4
hello

change in the master branch.
change in the bugfix branch.

这回就可以成功提交:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(master|MERGING)$ git add change-password.txt

(master|MERGING)$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)

Changes to be committed:
modified: change-password.txt

(master|MERGING)$ git commit
[master 74c5e1c] Merge branch 'bugfix-change-password.txt'

(master)$

Visual Merge Tools

1
2
3
👉 Kdiff 
👉 P4Merge
👉 WinMerge (Windows Only)

在官网下载P4Merge并安装,然后配置(安装路径):

1
2
3
$ git config --global merge.tool p4merge

$ git config --global mergetool.p4merge.path "D:/Program Files/P4Merge/p4merge.exe"

4_07

Aborting a Merge

想merge却发现有冲突,此时没有时间处理冲突,要回到merge之前的状态:

1
2
3
4
5
6
7
8
(master)$ git merge bugfix-change-password
Auto-merging change-password.txt
CONFLICT (content): Merge conflict in change-password.txt
Automatic merge failed; fix conflicts and then commit the result.

(master|MERGING)$ git merge --abort

(master)$

Undoing a Faulty Merge

merge了之后发现这个merge不合适,又不想merge了:

4_08

1
2
3
4
5
6
7
(master)$ git log --oneline --all --graph
* bbf6499 (HEAD -> master) Merge branch 'bugfix-change-password'
|\
| * fdfcee5 (bugfix-change-password) Update change-password.txt
* | 5975f40 Update change-password.txt
|/
* 3c6ba48 Update change-password.txt

4_09

用reset回到上一个master指向的commit,这之后的commit都会消失(看log):

1
2
3
4
5
6
7
8
(master)$ git reset --hard HEAD~1
HEAD is now at 5975f40 Update change-password.txt

(master)$ git log --oneline --all --graph
* 5975f40 (HEAD -> master) Update change-password.txt
| * fdfcee5 (bugfix-change-password) Update change-password.txt
|/
* 3c6ba48 Update change-password.txt

现在没有一个指针指向红标的commit,Git会将其视为垃圾,一段时间后自动将其删除:

4_10

但是在Git删除前它还在,还可以恢复出来:

1
2
3
4
5
6
7
8
9
10
(master)$ git reset --hard bbf6499
HEAD is now at bbf6499 Merge branch 'bugfix-change-password'

(master)$ git log --oneline --all --graph
* bbf6499 (HEAD -> master) Merge branch 'bugfix-change-password'
|\
| * fdfcee5 (bugfix-change-password) Update change-password.txt
* | 5975f40 Update change-password.txt
|/
* 3c6ba48 Update change-password.txt

4_11

4_12

4_13

git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。

适用场景: 如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(master)$ git log --oneline --all --graph
* bbf6499 (HEAD -> master) Merge branch 'bugfix-change-password'
|\
| * fdfcee5 (bugfix-change-password) Update change-password.txt
* | 5975f40 Update change-password.txt
|/
* 3c6ba48 Update change-password.txt

(master)$ git revert -m 1 HEAD
[master 5f99ab9] Revert "Merge branch 'bugfix-change-password'"
1 file changed, 1 deletion(-)

(master)$ git log --oneline --all --graph
* 5f99ab9 (HEAD -> master) Revert "Merge branch 'bugfix-change-password'"
* bbf6499 Merge branch 'bugfix-change-password'
|\
| * fdfcee5 (bugfix-change-password) Update change-password.txt
* | 5975f40 Update change-password.txt
|/
* 3c6ba48 Update change-password.txt

由于当前commit有两个parent commit (因为有两分支),所以用 -m 1 表示回到第一个parent commit (即上一个master指向的commit),可以看到所有的commit都保留了。

参考

https://blog.csdn.net/yxlshk/article/details/79944535

Squash Merging

4_14

可能B1和B2只是小改动,checkpoint之类的,我们不想让它们pollute了commit history, 所以用一个总的commit结合了这两个commit。而事实上并没有merge两个分支。

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
(master)$ git switch -C bugfix-photo-upload
Switched to a new branch 'bugfix-photo-upload'

(bugfix-photo-upload)$ echo bigfix >> audience.txt

(bugfix-photo-upload)$ git commit -am "Update audience.txt"
[bugfix-photo-upload c699541] Update audience.txt
1 file changed, 1 insertion(+), 1 deletion(-)

(bugfix-photo-upload)$ echo bigfix >> file1.js

(bugfix-photo-upload)$ git commit -am "Update file1.js"
[bugfix-photo-upload abb7001] Update file1.js
1 file changed, 1 insertion(+), 1 deletion(-)

(bugfix-photo-upload)$ git switch master
Switched to branch 'master'

(master)$ git merge --squash bugfix-photo-upload
Updating 5f99ab9..abb7001
Fast-forward
Squash commit -- not updating HEAD
audience.txt | 2 +-
file1.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

(master)$ git status -s
M audience.txt
M file1.js

(master)$ git commit -m "Fix the bug on the photo upload page"
[master 3a99538] Fix the bug on the photo upload page
2 files changed, 2 insertions(+), 2 deletions(-)

(master)$ git log --oneline --all --graph
* 3a99538 (HEAD -> master) Fix the bug on the photo upload page
| * abb7001 (bugfix-photo-upload) Update file1.js
| * c699541 Update audience.txt
|/
* 5f99ab9 Revert "Merge branch 'bugfix-change-password'"

实际上并没有merge:

1
2
3
4
5
6
7
8
9
10
11
12
13
(master)$ git branch
bugfix-change-password
bugfix-photo-upload
bugfix-signup-form
* master

(master)$ git branch --merge
bugfix-change-password
bugfix-signup-form
* master

(master)$ git branch --no-merge
bugfix-photo-upload

删除bugfix-photo-upload后可以看到,只剩一个总的commit记录了:

1
2
3
4
5
6
(master)$ git branch -D bugfix-photo-upload
Deleted branch bugfix-photo-upload (was abb7001).

(master)$ git log --oneline --all --graph
* 3a99538 (HEAD -> master) Fix the bug on the photo upload page
* 5f99ab9 Revert "Merge branch 'bugfix-change-password'"

Rebasing

(图与 demo 不十分吻合,在 demo 中 feature 分支只有一个 commit)

  1. 初始状态:master 和 feature-shopping-cart 是 diverse 的,要么用 3-way merge,要么将feature-shopping-cart 分支 rebase,总之是不能 fast-forward merge 的

4_15

1
2
3
4
5
(master)$ git log --oneline --all --graph
* 4026973 (HEAD -> master) update toc.txt
| * 34112c9 (feature-shopping-cart) add cart.txt
|/
* 7370c4a update
  1. 将 feature-shopping-cart 分支 rebase 到 master 指向的 commit:

    4_17

1
2
3
4
5
6
7
8
9
10
(master)$ git switch feature-shopping-cart
Switched to branch 'feature-shopping-cart'

(feature-shopping-cart)$ git rebase master
Successfully rebased and updated refs/heads/feature-shopping-cart.

(feature-shopping-cart)$ git log --oneline --all --graph
* 21dc4d0 (HEAD -> feature-shopping-cart) add cart.txt
* 4026973 (master) update toc.txt
* 7370c4a update
  1. 现在可以 fast-forward merge 了:

    4_18

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(feature-shopping-cart)
$ git switch master
Switched to branch 'master'

(master)$ git merge feature-shopping-cart
Updating 4026973..21dc4d0
Fast-forward
cart.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 cart.txt

(master)$ git log --oneline --all --graph
* 21dc4d0 (HEAD -> master, feature-shopping-cart) add cart.txt
* 4026973 update toc.txt
* 7370c4a update

但是,rebasing 很有可能会有 conflict,如下例中 master 和 feature-shopping-cart 各自更改toc.txt,就不能将 feature-shopping-cart rebase 到 master:

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
(master)$ echo ocean > toc.txt

(master)$ git commit -am "Update toc.txt"
[master f2e571a] Update toc.txt
1 file changed, 1 insertion(+), 2 deletions(-)

(master)$ git switch feature-shopping-cart
Switched to branch 'feature-shopping-cart'

(feature-shopping-cart)$ echo mountain > toc.txt

(feature-shopping-cart)$ git commit -am "add mountain to toc.txt"
[feature-shopping-cart 06ee042] add mountain to toc.txt
1 file changed, 1 insertion(+), 2 deletions(-)

(feature-shopping-cart)$ git log --oneline --all --graph
* 06ee042 (HEAD -> feature-shopping-cart) add mountain to toc.txt
| * f2e571a (master) Update toc.txt
|/
* 21dc4d0 add cart.txt

(feature-shopping-cart)$ git rebase master
error: could not apply 06ee042... add mountain to toc.txt
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 06ee042... add mountain to toc.txt
Auto-merging toc.txt
CONFLICT (content): Merge conflict in toc.txt

用p4merge解决一下conflict:

1
2
3
4
5
6
7
8
9
(feature-shopping-cart|REBASE 1/1)$ git mergetool
Merging:
toc.txt

Normal merge conflict for 'toc.txt':
{local}: modified file
{remote}: modified file

(feature-shopping-cart|REBASE 1/1)$ git rebase --abort

toc.txt.orig 是解决冲突的时候产生的额外文件,删掉就好了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(feature-shopping-cart)$ git status
On branch feature-shopping-cart
Untracked files:
(use "git add <file>..." to include in what will be committed)
toc.txt.orig

nothing added to commit but untracked files present (use "git add" to track)

(feature-shopping-cart)$ cat toc.txt.orig
<<<<<<< HEAD
ocean
=======
mountain
>>>>>>> 06ee042 (add mountain to toc.txt)

(feature-shopping-cart)$ git clean -fd
Removing toc.txt.orig

为了不产生这种文件,可以设置一下:

1
(feature-shopping-cart)$ git config --global mergetool.keepBackup false

Cherry Picking

4_19

比如 F1 是有意思的commit,我们想要提交到master,但是我们还没有准备好将feature分支merge 到 master 分支,可以 cherry picking F1 到 master。

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
(master)$ git log --oneline --all --graph
* 06ee042 (feature-shopping-cart) add mountain to toc.txt
| * f2e571a (HEAD -> master) Update toc.txt
|/
* dc9b37f add toc.txt

(master)$ git cherry-pick 06ee042
Auto-merging toc.txt
CONFLICT (content): Merge conflict in toc.txt
error: could not apply 06ee042... add mountain to toc.txt
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

(master|CHERRY-PICKING)$ git mergetool
Merging:
toc.txt

Normal merge conflict for 'toc.txt':
{local}: modified file
{remote}: modified file

(master|CHERRY-PICKING)$ git status -s
M toc.txt

(master|CHERRY-PICKING)$ git commit
[master 3fcca9a] add mountain to toc.txt
Date: Mon Apr 26 21:54:11 2021 +0800
1 file changed, 1 insertion(+), 1 deletion(-)

(master)$ git log --oneline --all --graph
* 3fcca9a (HEAD -> master) add mountain to toc.txt
* f2e571a Update toc.txt
| * 06ee042 (feature-shopping-cart) add mountain to toc.txt
|/
* dc9b37f add toc.txt

最后可以看到master前进了一个commit,而且是pick了feature-shopping-cart分支的commit。

Picking Files from Another Branch

是 picking files, 而不是 picking commit 了。

1
2
3
4
5
6
7
8
9
10
11
(master)$ git switch -C feature-send-email
Switched to a new branch 'feature-send-email'

(feature-send-email)$ echo river > toc.txt

(feature-send-email)$ git commit -am "Update toc.txt"
[feature-send-email 4680781] Update toc.txt
1 file changed, 1 insertion(+), 1 deletion(-)

(feature-send-email)$ git switch master
Switched to branch 'master'

使用 git restore:

1
2
3
4
5
6
7
(master)$ git restore --source=feature-send-email -- toc.txt

(master)$ git status -s
M toc.txt

(master)$ cat toc.txt
river

然后就可以在 master 分支上提交了。