要么改变世界,要么适应世界

Git学习笔记之分支管理

2022-02-09 14:55:23
303
目录

书接上回,本文主要介绍Git的分支管理操作。

Git的分支功能为我们团队分工提供了方便,并且每一个分支在合并之前不会对另外的分支产生影响:

与分支管理相关的命令:

命令 说明 命令 说明
git branch (branchname) 创建分支 git checkout/switch (branchname) 切换分支
git merge (branchname) 合并指定分支 git branch 列出所有分支
git branch -d (branchname) 删除指定分支

Git默认给我们生成了一个master主分支

$ git branch
* master

我们之前说的HEAD指向当前版本,严格来说是指向master,而master指向的是该分支的最新提交,因此HEAD指向的是最新提交,熟悉类C语言的指针相关知识应该很容易理解这部分内容。

使用分支

新建分支

新建一个前端分支front

$ git switch -c front
Switched to a new branch 'front'

-c代表新建一个分支 switch代表切换分支

确保当前所在分支

$ git branch
* front
  master

在该分支下新建我们的文件front.txt,并提交

$ touch front.txt
$ git add front.txt
$ git commit -m "new front branch"

我们再转回主分支master

$ git switch master
Switched to branch 'master'

此时我们会发现我们之前新建的front.txt文件不见了,这是因为该文件是在front分支下提交的,此时的前端分支比我们的主分支“提前”。

同样的方法新建一个接口分支并加一个文件

$ git switch -c interface
Switched to a new branch 'interface'
$ touch interface.txt
$ git add interface.txt
$ git commit -m "new interface branch"
[interface 824a607] new interface branch
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 interface.txt
 $ git switch master
Switched to branch 'master'

此时仓库情况如图:

合并分支

两边的人员工作都做完了,就可以考虑合并了,毕竟一直单干啥事都干不了

$ git merge front
$ git merge interface

意思是依次将当前分支(即master)合并到目标分支,我们尝试合并第二个时可能会遇到下面的情况

Merge branch 'interface'
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

意思是说希望我们能够给出合理的解释,为什么要合并这两个分支,我们可以直接关闭( 按键盘左上角Esc,输入:wq即可退出)也可以写入一些信息( 按键盘字母 i 进入insert模式并输入说明然后关闭 )

merge front and interface

然后我们的当前主分支下就会出现front.txtinterface.txt两个文件了。

删除分支

我们合并好分支后,对于不需要的分支可以删除,不会对我们目前的分支产生影响,因为我们当前的主分支比两个分支都“提前”,删除实际上删除的是指针

$ git branch -d front
Deleted branch front (was 0c93a6f).
$ git branch -d interface
Deleted branch interface (was 824a607).
$ git branch
* master
$ git log
commit 844e6a7ef9d46e3386bb0e18fecef93121f1831c (HEAD -> master)
Merge: 0c93a6f 824a607
Author: YaleXin <495592364@qq.com>
Date:   Wed Feb 9 15:03:51 2022 +0800

    merge front and interface

commit 824a60792b798f2ae9dfb55859142c41773573ad
Author: YaleXin <495592364@qq.com>
Date:   Wed Feb 9 14:45:35 2022 +0800

    new interface branch

commit 0c93a6f1f8ca2c884040437b3568514518ffbb7a
Author: YaleXin <495592364@qq.com>
Date:   Wed Feb 9 14:37:57 2022 +0800

    new front branch
:

可以发现我们的提交都没有丢失

解决冲突

当然了合并也不是每一次都能愉快地进行,不然前后端之间的矛盾也不会有这么多了。

假如前端说JavaScript是世界上最好的语言!

$ git switch -c front
Switched to a new branch 'front'

新建lan.txt文件并在文件中输入

`JavaScript`是世界上最好的语言!

然后提交

$ git add .
warning: LF will be replaced by CRLF in lan.txt.
The file will have its original line endings in your working directory
$ git commit -m "最好的语言"
[front 2ba9fe4] 最好的语言
 1 file changed, 1 insertion(+)
 create mode 100644 lan.txt

而后端的人却说Java是世界上最好的语言!

$ git switch master
Switched to branch 'master'

新建lan.txt文件并在文件中输入

`Java`是世界上最好的语言!

然后提交

$ git add .
warning: LF will be replaced by CRLF in lan.txt.
The file will have its original line endings in your working directory
$ git commit -m "最好的语言"
[master 8ee9862] 最好的语言
 1 file changed, 1 insertion(+)
 create mode 100644 lan.txt

然后尝试合并

$ git merge front
Auto-merging lan.txt
CONFLICT (add/add): Merge conflict in lan.txt
Automatic merge failed; fix conflicts and then commit the result.

这可把Git难住了,不同的分支对同一文件有不同的修改方式,Git尽最大能力也无法将其合并,现在只能我们自己手动合并冲突了。

我们打开lan.txt文件可以发现

$ cat lan.txt
<<<<<<< HEAD
`Java`是世界上最好的语言!
=======
`JavaScript`是世界上最好的语言!
>>>>>>> front

上面表明<<<<<<<=======之间的是当前分支的内容,=======>>>>>>>之间的是front分支的内容,我们手动将其改成

自然语言是世界上最好的语言!

然后提交

$ git add .
$ git commit -m "你们俩别吵了"
[master 7cec3a6] 你们俩别吵了
$ git log
commit 7cec3a623357cbea756a12235a995df2f85d6eed (HEAD -> master)
Merge: 8ee9862 2ba9fe4
Author: YaleXin <495592364@qq.com>
Date:   Wed Feb 9 16:06:57 2022 +0800

    你们俩别吵了

commit 8ee98627480b081d1885f8adcb7aad9580c2910c
Author: YaleXin <495592364@qq.com>
Date:   Wed Feb 9 15:55:50 2022 +0800

    最好的语言

commit 2ba9fe41d1379e4d57077f6d76ba7ed7e4ec55cd (front)
Author: YaleXin <495592364@qq.com>
Date:   Wed Feb 9 15:51:01 2022 +0800

    最好的语言

分支管理策略

开发分支

通常,合并分支时,如果没有冲突,并且分支是单向一条线路继承下来的,git会使用 fast forword 模式,但是有些快速合并不能成功,但是又没有冲突时,就会触发分支管理策略,Git会自动做一次新的提交。

当然我们也可以手动强制禁用Fast forward模式,Git就会在merge时生成一个新的commit .

我们来看一下区别:

首先新建一个分支并修改lan.txt,然后使用默认方式合并

$ git switch -c default
Switched to a new branch 'default'
修改lan.txt文件
$ git add .
$ git commit -m "default commit"
[default e167bc0] default commit
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git switch master
Switched to branch 'master'
$ git merge default
Updating 7cec3a6..e167bc0
Fast-forward
 lan.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

我们再查看提交情况:

$ git log --pretty=oneline --abbrev-commit --graph
* e167bc0 (HEAD -> master, default) default commit
*   7cec3a6 你们俩别吵了
|\
| * 2ba9fe4 最好的语言
* | 8ee9862 最好的语言
|/
*   844e6a7 merge front and interface
|\
| * 824a607 new interface branch
* | 0c93a6f new front branch
|/
* dcfdaa2 3
* e54198e second commit
* bbe2a77 first commit

合并情况如图所示

让我们再来个禁用Fast forward模式的合并

新建一个分支并修改lan.txt,然后使用禁用Fast forward模式合并

$ git switch -c noFast
Switched to a new branch 'noFast'
修改lan.txt文件
$ git add .
$ git commit -m "noFast commit"
[noFast f7f1ef6] noFast commit
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git switch master
Switched to branch 'master'
$ git merge --no-ff -m "merge by no-ff" noFast
Merge made by the 'ort' strategy.
 lan.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git log --pretty=oneline --abbrev-commit --graph
*   274515d (HEAD -> master) merge by no-ff
|\
| * f7f1ef6 (noFast) noFast commit
|/
* e167bc0 (default) default commit
*   7cec3a6 你们俩别吵了
|\
| * 2ba9fe4 最好的语言
* | 8ee9862 最好的语言
|/
*   844e6a7 merge front and interface
|\
| * 824a607 new interface branch
* | 0c93a6f new front branch
|/
* dcfdaa2 3
* e54198e second commit
* bbe2a77 first commit

合并情况如图所示

即会自动提交一次

有了上述清晰的认识以后,我们以后在日常使用Git开发的时候应该要秉承在master尽量少提交的理念,即尽可能稳定,最好只用来发布版本,然后在分支dev上进行日常开发,每逢大版本更新的时候再把它合并到主分支上面;当然了,在分工明确的前提下,每个人应该至少有属于自己的分支,然后定期合并到dev

临时分支

前面讲到版本库的两条主要分支:masterdev。前者用于正式发布,后者用于日常开发。其实,常设分支只需要这两条就够了,不需要其他了。

但是,除了常设分支以外,还有一些临时性分支,用于应对一些特定目的的版本开发。临时性分支主要有三种:

  • 功能(feature)分支
  • 预发布(release)分支
  • 修补bug(fixbug)分支

这三种分支都属于临时性需要,使用完以后,应该删除,使得代码库的常设分支始终只有masterdev

功能分支

它是为了开发某种特定功能,从dev分支上面分出来的,开发完成后,要再并入dev, 功能分支的名字,可以采用feature-name的形式命名。

预发布分支

预发布分支,它是指发布正式版本之前(即合并到master分支之前),我们可能需要有一个预发布的版本进行测试。预发布分支是从dev分支上面分出来的,预发布结束以后,必须合并进devmaster分支。它的命名,可以采用release-*的形式。

修补分支

软件正式发布以后,难免会出现bug。这时就需要创建一个分支,进行bug修补。

修补bug分支是从master分支上面分出来的。修补结束以后,再合并进masterdeev分支。它的命名,可以采用fixbug-*的形式。

这里有一个场景,你手头上的工作还没做完,但是你接到一个比较紧急的修复任务的时候,你又不想暂时提交这半截子代码,该怎么办?

Git提供了stash命令,它把所有未提交的修改(包括暂存的和非暂存的)都保存起来,用于后续恢复当前工作目录。

$ git status
On branch dev
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   front.txt

no changes added to commit (use "git add" and/or "git commit -a")
$ git stash
Saved working directory and index state WIP on dev: 274515d merge by no-ff
$ git status
On branch dev
nothing to commit, working tree clean

等我们在新的分支上修复好BUG,并合并好分支,然后再将这个暂时的修复分支删除后,就可以切换到我们的dev分支上来继续我们的工作了。

可以看一下之前暂存的代码

$ git stash list
stash@{0}: WIP on dev: 274515d merge by no-ff
$ git status
On branch dev
nothing to commit, working tree clean

回复我们的工作有两种方法:

  • git stash apply恢复,但是恢复后,stash中的内容并不删除,你需要用git stash drop来删除
  • git stash pop,该方法在恢复的同时把stash中的内容也删了:
$ git stash pop
On branch dev
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   front.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (414125ba81aaed29ef4736209c257077fb277202)

然后我们就可以继续愉快地进行我们的工作了。

历史评论
开始评论