本篇博客的环境为 Ubuntu/linux
文章目录
前言
在 Git 中,分支(branch)
是一个独立的开发线路。允许在不影响主线(通常是main
或master
分支)的情况下进行修改和开发
主线就是实际发布的版本,但一个项目可能需要更新迭代,开发新功能或者维护修bug,所以肯定会基于主线进行修改,但又不可能让用户使用还在开发的,不完全的版本,分支就可以解决这样并发开发的问题,当分支完成开发后,再合并到主线中。
在.git
目录结构中,HEAD
指向当前分支,而master指向主分支的最近一次提交的commit id
分支可以理解为一条时间线,每一次提交都是一个时间点
如图,随着不断地提交,master分支都会向前移动一步,分支的线也会越来越长,而HEAD指向master分支,即当前分支
分支基础操作
创建分支
创建分支的命令为:
sh
git branch [分支名]
查看有哪些本地分支
sh
git branch
示例:
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git branch
* master
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git branch dev
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git branch
dev
* master
带*
的表示当前处于该分支,即HEAD
指向的分支
新创建的分支都是基于当前的master
分支
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ ls .git/refs/heads/
dev master
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat .git/refs/heads/*
eac56023195eaf5a3dad49e7d60f93cd2c4e6f6e
eac56023195eaf5a3dad49e7d60f93cd2c4e6f6e
可以看到dev
和master
都指向最新一次提交的commit id
切换分支
切换分支命令如下:
sh
git checkout [分支名]
git checkout -b [分支名] #创建分支并切换
示例:
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout dev
Switched to branch 'dev'
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git branch
* dev
master
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat .git/HEAD
ref: refs/heads/dev
可以看到HEAD
已经指向了dev
分支
接下来在dev
分支下进行修改,并提交
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ vim ReadMe
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
i am coding
i am coding
i am coding
coding on dev branch
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git add .
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git commit -m "md ReadMe:coding on dev branch"
[dev c8acfad] md ReadMe:coding on dev branch
1 file changed, 1 insertion(+)
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout master
Switched to branch 'master'
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
i am coding
i am coding
i am coding
我们会发现,在dev
分支上提交的内容无法在master
分支上观察到,这是因为二者指向的提交已经不一样了
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat .git/refs/heads/dev
c8acfad3696bb5a7dd1a1cd11a2facb9e6bd4bda
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat .git/refs/heads/master
eac56023195eaf5a3dad49e7d60f93cd2c4e6f6e
因为matser
还指向原先的提交点,所以查看的也是之前的版本
合并分支
当dev
分支完成开发后,就需要将内容合并到master
分支上,合并的命令如下:
sh
git merge [分支]
使用该命令,就是将指定分支的提交内容合并到当前分支
示例:
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout master
Already on 'master'
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git merge dev
Updating eac5602..c8acfad
Fast-forward
ReadMe | 1 +
1 file changed, 1 insertion(+)
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
i am coding
i am coding
i am coding
coding on dev branch
Fast-forward
代表快进模式
,也就是直接把master指向dev的当前提交,所以合并速度很快,还有其他模式的合并方式,后续讲解
删除分支
当一个分支完成开发,master
分支也将其内容合并后,该分支的任务就完成了,那么可以将该分支删除,减少分支数,便于管理。
注意如果处于某分支下,是不能删除当前分支的
删除分支的命令如下:
sh
git branch -d [分支名]
git branch -D [分支名] #强制删除
示例:
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git branch -d dev
Deleted branch dev (was c8acfad).
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git branch
* master
此时状态图如下:
因为创建、合并和删除分支都很快,所以 Git 鼓励使用使用分支完成某个任务,并合并后删除分支,这和直接在master分支上工作效果一样,但过程更安全
可能会出现分支还没合并到主分支,但该分支开发内容被弃用的情况,
-d
删除该分支会提示分支未合并此时需要使用
-D
选项强制删除
合并冲突
在实际开发中,可能存在很多分支
如图,dev1
和dev2
基于同一个master
主支线的提交进行后续开发,dev1
先完成开发,并合并进了master
。此时master
的内容已经和dev2
保存的不同,此时合并就会出现合并冲突,Git 不知道要保留哪些代码
示例:
- 创建
dev
分支完成开发
sh
#查看ReadMe内容
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
#创建并切换分支
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout -b dev
Switched to a new branch 'dev'
#完成开发并提交
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ vim ReadMe
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
dev branch coding...
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git add .
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git commit -m "md ReadMe:dev branch coding"
[dev 0e0b57d] md ReadMe:dev branch coding
1 file changed, 1 insertion(+)
master
也同步进行开发
sh
#切换回master分支
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout master
Switched to branch 'master'
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
#完成开发并提交
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ vim ReadMe
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
master branch coding...
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git add .
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git commit -m "md ReadMe:master branch coding"
[master e0afb54] md ReadMe:master branch coding
1 file changed, 1 insertion(+)
此时状态图如下:
- 使用
master
合并dev
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git branch
dev
* master
#合并
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git merge dev
Auto-merging ReadMe
CONFLICT (content): Merge conflict in ReadMe
Automatic merge failed; fix conflicts and then commit the result.
#合并发生冲突,Git标记冲突部分
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
<<<<<<< HEAD
master branch coding...
=======
dev branch coding...
>>>>>>> dev
发生合并冲突后,Git 并不知道要保留哪部分代码,所以索引都保留,然后标记出冲突的部分
Git 使用 <<<<<<
,========
,>>>>>>>>
标记不停分支的冲突内容
我们必须手动调整冲突代码,并且调整完后还需要再次提交修正后的结果(一定要再次提交!!!
)
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ vim ReadMe
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
master branch coding...
dev branch coding...
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ 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:
(use "git add <file>..." to mark resolution)
both modified: ReadMe
no changes added to commit (use "git add" and/or "git commit -a")
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git add .
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git commit -m "solve the merge conflict"
[master c132cde] solve the merge conflict
此时状态图如下:
使用带参数的git log
可以看到分支的合并情况
sh
git log --graph --pretty=oneline --abbrev-commit
左侧有类似时间线的线段,*
表示当时的工作分支
分支管理策略
通常合并分支时,Git 一般会采用Fast forward
模式
直接将master
指向合并分支的最新一次提交的commit id
在Fast forward
模式下,删除分支后,查看分支历史,会丢失分支信息,看不出来最新提交到底是 merge 的还是正常提交的
在合并冲突时,通过日志查看的明显不是Fast forward
模式,从分支历史上可以很清晰的看到分支信息,新提交是通过 merge dev 分支进来的。该模式称为非Fast forward(no-ff)
模式
Git 允许强制禁用Faste forward
模式,就是在合并时带上--no-ff
选项
sh
git merge --no-ff -m "描述" [分支名]
下图是两种模式的状态图差异:
对于没有合并冲突的合并,--no-ff
模式可以保留合并信息,而Fast forword
则没有合并信息
分支策略
实际开发有一些基本原则需要遵守
- master分支是主分支,实际发布的分支,应该是非常稳定的,不能直接在该分支上开发
- 每个新功能的开发/bug修改等都要新建分支完成,完成开发并测试再合并回 master
3.合并时,可以先在工作分支合并 master 分支,确认无误后,再切换到 master 分支合并指定分支
综上,团队合作的分支看起来就像这样:
bug 分支
情景如下:
假如现在在dev2
分支上开发,开发到一半,突然master
分支上有bug,需要解决。在 Git 中,每个 bug 都可以通过一个新的临时分支来修复,修复后再合并分支,最后将临时分支删除
当前dev2
的代码在工作区开发了一半,还无法提交。此时如果切换到master
分支,会影响master
分支的工作区内容
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout -b dev2
Switched to a new branch 'dev2'
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ vim ReadMe
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout master
M ReadMe
Switched to branch 'master'
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
master branch coding...
dev branch coding...
i am coding...
Git 提供 git stash
命令,可以将当前的工作区信息进行存储,被存储的内容可以在将来某个时间恢复出来
sh
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout dev2
M ReadMe
Switched to branch 'dev2'
#使用stash存储工作区修改
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git stash
Saved working directory and index state WIP on dev2: c132cde solve the merge conflict
#此时工作区修改已经被存储起来,dev2和master都看不到修改
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
master branch coding...
dev branch coding...
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git checkout master
Switched to branch 'master'
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ cat ReadMe
hello git
master branch coding...
dev branch coding...
使用如下命令查看存储
sh
git stash list
ubuntu@VM-12-11-ubuntu:~/lesson/gitcode$ git stash list
stash@{0}: WIP on dev2: c132cde solve the merge conflict
使用如下命令恢复工作区修改,恢复的同时会把 stash 删除,只能恢复一次
sh
git stash pop #类似队列那样,从小序号删除
也可以不删除 stash
sh
git stash apply #恢复现场,但不删除stash
git stash drop #需要用该命令删除stash
git stash apply stash@{0} #指定恢复
以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。