一、分支概念
在**版本回退**里,每次提交,git都把它们串成一条时间线,这条时间线可以理解为是一个**分支**。默认git创建仓库以后,只有一个分支,叫做**主分支master**。
分支的命名和设计,完全可以由团队创作者自己来管理。
**HEAD指针**,严格来说**不是**指向提交,而是指向**master**,**master**才是指向提交的。而**HEAD**指向的分支就是**当前分支**。
每次提交,**master分支**都会向前移动一步,这样,随着不断的提交,**master分支**线也会越来越长,而**HEAD**只要一直指向**master分支**即可指向当前分支。
通过查看版本库,也能发现一些关联:
1 hyb@139-159-150-152:~/gitcode$ cat .git/HEAD
2 ref: refs/heads/master
3 hyb@139-159-150-152:~/gitcode$ cat .git/refs/heads/master
4 5476bdeb12510f7cd72ac4766db7988925ebd302
二、创建分支
创建新的分支的命名,完全由使用者决定,这里创建新的**分支dev**。
1 hyb@139-159-150-152:~/gitcode$ git branch //查看当前本地所有分⽀
2 * master
3 hyb@139-159-150-152:~/gitcode$ git branch dev //新建分⽀dev
4 hyb@139-159-150-152:~/gitcode$ git branch
5 dev
6 * master
当创建新的**分支dev**后,**git**新建了一个**dev指针**,*****表示当前**HEAD**指向的分支是**master分支。**
1 hyb@139-159-150-152:~/gitcode$ ls .git/refs/heads/
2 dev master
3 hyb@139-159-150-152:~/gitcode$ cat .git/refs/heads/*
4 5476bdeb12510f7cd72ac4766db7988925ebd302
5 5476bdeb12510f7cd72ac4766db7988925ebd302
打印结果显示**master**和**dev**指向同一个**修改提交**。
三、切换分支
使用命令**git checkout**完成分支**切换**。
1 hyb@139-159-150-152:~/gitcode$ git checkout dev
2 Switched to branch 'dev'
3 hyb@139-159-150-152:~/gitcode$ git branch
4 * dev
5 master
6 hyb@139-159-150-152:~/gitcode$ cat .git/HEAD
7 ref: refs/heads/dev
当**HEAD**指向**dev分支**,表明当前分支已经是**dev分支**了。
在**dev分支**下修改**ReadMe**文件,新增一行内容,并完成**提交**操作。
1 hyb@139-159-150-152:~/gitcode$ vim ReadMe
2 hyb@139-159-150-152:~/gitcode$ cat ReadMe
3 hello bit
4 hello git
5 hello world
6 hello version1
7 hello version2
8 hello version3
9 write aaa for new branch//这一行是新增的一行
10 hyb@139-159-150-152:~/gitcode$ git add .
11 hyb@139-159-150-152:~/gitcode$ git commit -m"modify ReadMe"
12 [dev 3740dce] modify ReadMe
13 1 file changed, 1 insertion(+)
现在再切换到**master**分支,原来在**dev分支**的提交并**不会**影响**master分支。**
1 hyb@139-159-150-152:~/gitcode$ git checkout master
2 Switched to branch 'master'
3 hyb@139-159-150-152:~/gitcode$ cat ReadMe
4 hello bit
5 hello git
6 hello world
7 hello version1
8 hello version2
9 hello version3
现在来观察一下两个分支最新的提交。
1 hyb@139-159-150-152:~/gitcode$ cat .git/refs/heads/dev
2 bdaf528ffbb8e05aee34d37685408f0e315e31a4
3 hyb@139-159-150-152:~/gitcode$ cat .git/refs/heads/master
4 5476bdeb12510f7cd72ac4766db7988925ebd302
如果用图来表示,它是下面这个样子的:
四、合并分支
为了在**master**分支上面能看到新的提交,需要将**dev分支**的内容合并到**master分支**上面。**git****merge**命令用于将**指定分支**合并到**当前分支。**
1 hyb@139-159-150-152:~/gitcode$ git branch
2 * dev
3 master
4 hyb@139-159-150-152:~/gitcode$ git checkout master //切换到 master 上进⾏合并
5 Switched to branch 'master'
6 hyb@139-159-150-152:~/gitcode$ git merge dev //合并 dev 分⽀
7 Updating 16623e1..3740dce
8 Fast-forward
9 ReadMe | 1 +
10 1 file changed, 1 insertion(+)
11 hyb@139-159-150-152:~/gitcode$ cat ReadMe
12 hello bit
13 hello git
14 hello world
15 hello version1
16 hello version2
17 hello version3
18 write aaa for new branch
如果用图来表示,它是下面这个样子的:
在执行**git merge**命令后,显示结果出现了字符串**"Fast-forward"**,表示**快进模式**,实际发生的是直接将**master**指向当前**dev**的最新提交,所以合并速度非常快,当然除了**Fast-forward**模式,还有其他合并模式。
五、删除分支
合并分支完成后,临时创建的**dev分支**就没有用了,需要删除**dev分支,**但是,在当前分支下,是**不能**删除当前分支的,因此,要删除**dev**分支,就需要切换到**master**分支。
1 hyb@139-159-150-152:~/gitcode$ git checkout master
2 Switched to branch 'master'
3 hyb@139-159-150-152:~/gitcode$ git branch -d dev
4 Deleted branch dev (was bdaf528).
5 hyb@139-159-150-152:~/gitcode$ git branch
6 * master
7
如果用图来表示,它是下面这个样子的:
因为创建、合并、删除分支的速度非常快,因此**git**提倡使用**分支**来完成某一个任务,结束后再删掉分支,这和直接在**master分支**上面开发是一样的,但是过程**更安全**。
六、合并冲突
在实际合并分支的时候,可能会遇到代码冲突的问题。
为了演示这一问题,现在创建新的分支**dev1**,并切换到**dev1分支**下面,可以使用**git checkout -b dev1**一步完成创建和切换分支的动作。
1 hyb@139-159-150-152:~/gitcode$ git checkout -b dev1
2 Switched to a new branch 'dev1'
3 hyb@139-159-150-152:~/gitcode$ git branch
4 * dev1
5 master
在**dev1**分支下面修改**ReadMe**文件,并进行一次提交。
1 hyb@139-159-150-152:~/gitcode$ cat ReadMe
2 hello bit
3 hello git
4 hello world
5 hello version1
6 hello version2
7 hello version3
8 write bbb for new branch //将 aaa 该为 bbb,视为dev1对ReadMe的修改
9 hyb@139-159-150-152:~/gitcode$ git add .
10 hyb@139-159-150-152:~/gitcode$ git commit -m"modify ReadMe"
11 [dev1 0854245] modify ReadMe
12 1 file changed, 1 insertion(+), 1 deletion(-)
现在切换到**master**分支,观察**ReadMe**文件的内容,由于并没有合并操作,因此**master**分支下面的**ReadMe**文件没有发生变化。
1 hyb@139-159-150-152:~/gitcode$ git checkout master
2 Switched to branch 'master'
3 hyb@139-159-150-152:~/gitcode$ cat ReadMe
4 hello bit
5 hello git
6 hello world
7 hello version1
8 hello version2
9 hello version3
10 write aaa for new branch//master分支下面还是aaa
此时,在**master**分支下面,对**ReadMe**文件**再**做一次修改,并完成提交操作。
1 hyb@139-159-150-152:~/gitcode$ git branch
2 dev1
3 * master
4 hyb@139-159-150-152:~/gitcode$ vim ReadMe
5 hyb@139-159-150-152:~/gitcode$ cat ReadMe
6 hello bit
7 hello git
8 hello world
9 hello version1
10 hello version2
11 hello version3
12 write ccc for new branch //master分支将aaa修改为ccc
13 hyb@139-159-150-152:~/gitcode$ git add .
14 hyb@139-159-150-152:~/gitcode$ git commit -m"modify ReadMe"
15 [master c10f6d0] modify ReadMe
16 1 file changed, 1 insertion(+), 1 deletion(-)
现在,**master**分支和**dev1**分支都有了新的提交,如果用图来表示,它是下面这个样子的:
这种情况下,**git**会试图将每个分支的修改合并起来,但是可能造成**合并冲突**。
1 hyb@139-159-150-152:~/gitcode$ git merge dev1
2 Auto-merging ReadMe
3 CONFLICT (content): Merge conflict in ReadMe
4 Automatic merge failed; fix conflicts and then commit the result.
5 hyb@139-159-150-152:~/gitcode$ git status
6 On branch master
7 You have unmerged paths.
8 (fix conflicts and run "git commit")
9 (use "git merge --abort" to abort the merge)
10
11 Unmerged paths:
12 (use "git add <file>..." to mark resolution)
13 both modified: ReadMe
14
15 no changes added to commit (use "git add" and/or "git commit -a")
合并的结果告诉我们,**ReadMe**文件存在冲突,此时打印**ReadMe文件**,**git**会使用<<<<<<<<<、==========、>>>>>>>>>>来标记出不同分支的冲突内容。
1 hyb@139-159-150-152:~/gitcode$ cat ReadMe
2 hello bit
3 hello git
4 hello world
5 hello version1
6 hello version2
7 hello version3
8 <<<<<<< HEAD
9 write ccc for new branch
10 =======
11 write bbb for new branch
12 >>>>>>> dev1
此时,我们必须要手动修改冲突的代码,**并且再次完成提交操作**,一定要再次提交!!!
1 hyb@139-159-150-152:~/gitcode$ cat ReadMe
2 hello bit
3 hello git
4 hello world
5 hello version1
6 hello version2
7 hello version3
8 write bbb for new branch
9 hyb@139-159-150-152:~/gitcode$ git add .
10 hyb@139-159-150-152:~/gitcode$ git commit -m"merge ReadMe"
11 [master 2976afc] merge ReadMe
如果用图来表示,它是下面这个样子的:
执行带特定参数的**git log**也可以看到合并冲突的情况。
1 hyb@139-159-150-152:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
2 * 2976afc (HEAD -> master) merge ReadMe
3 |\
4 | * c594fd1 (dev1) modify ReadMe
5 * | c10f6d0 modify ReadMe
6 |/
七、分支管理策略
合并分支时,**git**默认使用**Fast-forward**模式,使用**Fast-forward**模式合并的结果如下图所示:
这种合并模式下,**master分支**不会有新的提交,仅仅是将**master**指向**dev**的最新提交,因此速度也比较快,但是如果在当前这种情况**删除dev分支**,再查看分支历史时,会丢掉分支信息,看不出来最新的提交是**merge进来的**还是**分支提交进来的**。
在之前解决**合并冲突**时,**master分支多了一次提交**,如果用图来表示,就是下面这个样子:
可以看到,这种合并模式下,**master**多了一次提交,并不是直接指向**dev**的最新提交,那么这就不是**Fast-forward**模式了,这种合并模式有一个优点,就是即使在删除dev分支后,也能通过**查看分支历史**看出来最新一次提交是**合并而来**,而不是**master**直接提交而来。
1 hyb@139-159-150-152:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
2 * 2976afc (HEAD -> master) merge ReadMe
3 |\
4 | * c594fd1 modify ReadMe
5 * | c10f6d0 modify ReadMe
6 |/
7
因此,**git**也支持我们禁用**Fast-forward**模式。在**非Fast-forward**合并模式下,合并时会多一次**提交commit**,这样就可以在分支历史上看出提交信息。
下面,对这种合并模式作演示。首先,创建新的**分支dev2**并切换到该分支。
1 hyb@139-159-150-152:~/gitcode$ git checkout -b dev2
2 Switched to a new branch 'dev2'
修改**ReadMe**文件,并做一次提交。
1 hyb@139-159-150-152:~/gitcode$ cat ReadMe
2 hello bit
3 hello git
4 hello world
5 hello version1
6 hello version2
7 hello version3
8 write bbb for new branch
9 a,b,c,d//这一行是修改的内容
10 hyb@139-159-150-152:~/gitcode$ git add .
11 hyb@139-159-150-152:~/gitcode$ git commit -m"modify ReadMe"
12 [dev2 41b082f] modify ReadMe
13 1 file changed, 1 insertion(+)
切回**master分支**,并且合并**dev2分支**的提交。
1 hyb@139-159-150-152:~/gitcode$ git checkout master
2 Switched to branch 'master'
3 hyb@139-159-150-152:~/gitcode$ git merge --no-ff -m "merge with no-ff" dev2
4 Merge made by the 'recursive' strategy.
5 ReadMe | 1 +
6 1 file changed, 1 insertion(+)
7 hyb@139-159-150-152:~/gitcode$ cat ReadMe
8 hello bit
9 hello git
10 hello world
11 hello version1
12 hello version2
13 hello version3
14 write bbb for new branch
15 a,b,c,d
16
请注意,**参数--no-ff**,表示**禁用Fast-forward**模式,**禁用Fast-forward**表示会做一次**新的提交**,因此,使用**-m参数**作提交描述。
合并后,查看分支历史。
1 hyb@139-159-150-152:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
2 * 5bd16b4 (HEAD -> master) merge with no-ff
3 |\
4 | * 41b082f (dev2) modify ReadMe
5 |/
如果用图来表示,它是下面这个样子的:
所以,在合并分支时,我们尽量使用**--no-ff**模式,合并后,**分支历史**会显示合并详情,能看出来曾经做过合并,而使用**Fast-forward**模式就看不出来。
八、分支策略
在实际企业级开发中,我们按照下面几个原则进行分支管理:
首先,master分支是非常稳定的,仅仅用来发布新版本,平时的开发工作都在其他分支。
一般的开发工作都在dev分支上面进行,dev分支是不稳定的,发布测试版本,dev版本经过大量测试后,如果这个测试版本是稳定可靠的,再将dev分支合并到master分支上面,在master分支上面发布稳定的版本。
团队中的每个人都有自己的分支,进行自己的任务开发,在某一个约定的时间,将自己开发的内容合并到dev分支上面。
如果用图来表示,就是下面这个样子的:
九、bug分支
假如我们当前正在**dev2分支**进行开发,开发到一半,即已经书写了部分有效代码,此时,主分支**master**出现了**bug**,那么现在的主要任务就是**修复bug**。
但是**dev2分支**的代码在**工作区的开发程度还不能提交**,要怎么办。
** git**提供了**git stash**命令,用来将当前的工作区的代码进行**临时储存**。
1 hyb@139-159-150-152:~/gitcode$ git stash
2 Saved working directory and index state WIP on dev2: 41b082f modify ReadMe
3 hyb@139-159-150-152:~/gitcode$ git status
4 On branch dev2
5 nothing to commit, working tree clean
执行**git stash**后,**dev2**分支上工作区的代码得以保存。
修复**bug**是基于**master**分支的,因此要切回**master**再新建**临时分支**来修复**bug。**
1 hyb@139-159-150-152:~/gitcode$ git checkout master //切回master
2 Switched to branch 'master'
3 hyb@139-159-150-152:~/gitcode$ git checkout -b fix_bug //新建并切换到 fix_bug 分⽀
4 Switched to a new branch 'fix_bug'
5 hyb@139-159-150-152:~/gitcode$ vim ReadMe
6 hyb@139-159-150-152:~/gitcode$ cat ReadMe
7 hello bit
8 hello git
9 hello world
10 hello version1
11 hello version2
12 hello version3
13 write bbb for new branch
14 a,b,c,d,e //修复bug,假如bug是忘记写e
15 hyb@139-159-150-152:~/gitcode$ git add ReadMe // 重新add,commit
16 hyb@139-159-150-152:~/gitcode$ git commit -m"fix bug"
17 [fix_bug 4bbc0c4] fix bug
18 1 file changed, 1 insertion(+),
修复**bug**后,切回**master分支**,合并该分支到**master分支**,并且**删除**这个临时分支。
1 hyb@139-159-150-152:~/gitcode$ git checkout master
2 Switched to branch 'master'
3 hyb@139-159-150-152:~/gitcode$ git merge --no-ff -m"merge fix_bug branch" fix_bu
4 Merge made by the 'recursive' strategy.
5 ReadMe | 2 +-
6 1 file changed, 1 insertion(+), 1 deletion(-)
7 hyb@139-159-150-152:~/gitcode$ cat ReadMe
8 hello bit
9 hello git
10 hello world
11 hello version1
12 hello version2
13 hello version3
14 write bbb for new branch
15 a,b,c,d,e
16 hyb@139-159-150-152:~/gitcode$ git branch -d fix_bug
17 Deleted branch fix_bug (was 4bbc0c4).
至此,**修复bug**的工作已经完成,我们**切回dev2**继续我们的开发工作。
1 hyb@139-159-150-152:~/gitcode$ git checkout dev2
2 Switched to branch 'dev2'
3 hyb@139-159-150-152:~/gitcode$ git status
4 On branch dev2
5 nothing to commit, working tree clean
执行**git status**命令可以发现工作区没有修改,是因为我们将代码进行了保存。可以执行**git****stash list**进行查看是否有被保存的代码。
1 hyb@139-159-150-152:~/gitcode$ git stash list
2 stash@{0}: WIP on dev2: 41b082f modify ReadMe
现在要将原来的开发到一半的状态进行恢复**,执行git stash pop**。
1 hyb@139-159-150-152:~/gitcode$ git stash pop
2 On branch dev2
3 Changes not staged for commit:
4 (use "git add <file>..." to update what will be committed)
5 (use "git restore <file>..." to discard changes in working directory)
6 modified: ReadMe
7
8 no changes added to commit (use "git add" and/or "git commit -a")
9 Dropped refs/stash@{0} (4f873250b3503687b5efd26196776aee7e3724c2)
需要注意的是,执行**git stash pop**后,被**保存的现场**也会被删除。如果你想**恢复现场**的同时继续保存现场,可以执行**git stash apply**命令。如果再要删除现场,可以执行**git stash drop**命令。
如果多次使用**stash**保存多个现场,在恢复时想要**指定**恢复某一个现场,可以执行**git stash****apply stash@{0/1/2···}**来达到要求。
恢复现场后,继续完成**dev2分支**上面的开发工作。
1 hyb@139-159-150-152:~/gitcode$ cat ReadMe
2 hello bit
3 hello git
4 hello world
5 hello version1
6 hello version2
7 hello version3
8 write bbb for new branch
9 a,b,c,d//dev2分支没有修复bug
10 i am coding ... Done!//假设我们已经完成了,然后add、commit
11 hyb@139-159-150-152:~/gitcode$ git add .
12 hyb@139-159-150-152:~/gitcode$ git commit -m"modify ReadMe"
13 [dev2 ed0916d] modify ReadMe
14 1 file changed, 1 insertion(+)
结果表明,我们**在master**分支上修复的**bug**并没有在**dev2**分支上面**也修复**,这是正常的,如果用图来表示,它是下面这个样子的:
我们最终要**在master分支**上面合并**dev2分支**,但是如果在这种情况下合并可能会造成**合并冲突发生**,这就会影响**master分支**的稳定性。
为了避免这样的问题发生,我们实际是在**自己的分支**去合并**master分支**,如果出现合并冲突,也可以很容易的解决而不影响**master分支**,然后再让**master分支**合并**dev分支**。如果用图来表示,它是下面这个样子的:
十、强制删除分支
软件开发中,总是有无穷无尽的功能要添加进来。
添加一个新功能时,为了不让实验性的代码干扰稳定的主分支代码,要创建出许许多多的临时分支。
假设现在正在**feature分支**上面开发功能,但是,产品经理突然通知这个功能**不需要**了,因此,**feature分支**必须尽快的销毁掉。
此时我们的开发内容**不需要**合并到主分支上面,如果切到主分支再删除这个分支,执行**git****branch -d**是无法完成要求的。
因为**git**会认为你当前的开发工作**正在进行**,没有做合并操作,所以对该分支**加以保护**。
1 //新增并切换到 dev3 分⽀
2 hyb@139-159-150-152:~/gitcode$ git checkout -b dev3
3 Switched to a new branch 'dev3'
4
5 //开始开发新功能并提交
6 hyb@139-159-150-152:~/gitcode$ vim ReadMe
7 hyb@139-159-150-152:~/gitcode$ cat ReadMe
8 hello bit
9 hello git
10 hello world
11 hello version1
12 hello version2
13 hello version3
14 write bbb for new branch
15 a,b,c,d,e
16 i am coding ... Done!
17 i am writing new features ...
18 hyb@139-159-150-152:~/gitcode$ git add .
19 hyb@139-159-150-152:~/gitcode$ git commit -m"modify ReadMe for new features"
20 [dev3 cd2f149] modify ReadMe for new features
21 1 file changed, 1 insertion(+)
22
23 //此时新功能叫停
24
25 //切回master准备删除dev3
26 hyb@139-159-150-152:~/gitcode$ git checkout master
27 Switched to branch 'master'
28
29 //常规删除dev3分⽀时失败
30 hyb@139-159-150-152:~/gitcode$ git branch -d dev3
31 error: The branch 'dev3' is not fully merged.
32 If you are sure you want to delete it, run 'git branch -D dev3'.
按照提升,执行**git branch -D强制删除分支**。
1 hyb@139-159-150-152:~/gitcode$ git branch -D dev3
2 Deleted branch dev3 (was cd2f149).
3 hyb@139-159-150-152:~/gitcode$ git branch
4 * master
版权归原作者 UtoCoo 所有, 如有侵权,请联系我们删除。