昨天学习了在本地使用git的方法,我们了解到,在git中,我们的每次提交都会被串成一条时间线,这条时间线就是一条分支
在我们初始化的事情,git默认给我们创建了一个master
的分支,也就是主分支
版本回退的时候,我们使用HEAD
严格来说不是指向提交,而是指向master
,master
才指向提交。也就是说HEAD
指向的是当前分支。
我极度相信图形化的解释更能让人理解,所以还是推荐廖雪峰的博客-git分支
简单的分支操作
创建分支
-
git branch <name>
创建分支
git在初始状态下,只存在master
分支,首先我们创建dev
分支
$: git branch dev
这样就创建了一个分支dev
,我们可以使用git branch
来查看当前分支
$: git branch
dev
* master
可以发现,多出了一条分支,其中*表示处于当前分支,当前分支依然是master
切换分支
-
git checkout <name>
切换分支
现在我们创建了dev
分支,我们可以直接使用git checkout
命令进行切换分支
$: git checkout dev
切换到分支 'dev'
$: git branch
* dev
master
创建并切换
-
git checkout -b <name>
创建并切换分支
如果你想要在创建的时候就直接切换了分支可以直接使用git checkout -b dev
$: git checkout -b abc
切换到一个新分支 'abc'
$: git branch
* abc
dev
master
删除分支
-
git branch -d <name>
删除一个分支
在git中删除分支是十分迅速的,直接使用git branch -d dev
即可
$: git branch -d abc
已删除分支 abc(曾为 815bc52)。
合并分支
-
git merge <name>
合并指定分支到当前分支
注意: 因为我学习分支是在间隔了一段时间,所以源文件被我删除,重新建立了git仓库
我们创建了一个分支,并且在这条分支上进行了提交,使用git branch
检查当前处于的分支
$: git branch
* dev
master
我们在文本中添加了一行forth
,然后在本分支上进行一次commit
提交
$: echo "forth" >> readme.txt
$: cat readme.txt
first
second
third
forth
$: git add readme.txt
$: git commit -m "forth"
[dev 449796e] forth
1 file changed, 1 insertion(+)
我们可以使用git log
查看一下提交记录,我们可以看出在第四次提交的时候,HEAD指向了dev
$: git log
commit 449796ed9c4459653f2f32ebfd2a0d18166880a1 (HEAD -> dev)
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:23:00 2019 +0800
forth
commit 2c48555843e19cfe9c86ceff886e5c1536afe5ec (master)
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:21:19 2019 +0800
third
commit a8aa4a763b1fcd24232ea38e62fcb941ce200561
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:20:54 2019 +0800
second
commit 852d56db6edb8826a9a9bd8621457e21d366260f
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:20:28 2019 +0800
first
现在我们切回master
分支,然后检查readme.txt
,我们会发现,现在readme.txt
中只有三行
$: git checkout master
切换到分支 'master'
$: cat readme.txt
first
second
third
廖雪峰老师在博客中的图片十分形象
此时我们虽然提交了,但是却是提交在了dev
的分支上,而对于master
分支,没有进行任何修改
因为master
分支在之后并没有提交,也就是说,虽然存在分支,但是master
主分支并没有分叉,所以我们可以直接使用git merge
合并
git merge <branchneme>
命令用于合并指定分支到当前分支。
$: git merge dev
更新 2c48555..449796e
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
$: cat readme.txt
first
second
third
forth
可以看出,现在readme.txt
又回来了。需要注意的是Fast-forward
代表这次合并是’快进模式‘,也就是说直接将master
指向dev
的当前提交
我们甚至可以使用git log
来检查一下。
$: git log
commit 449796ed9c4459653f2f32ebfd2a0d18166880a1 (HEAD -> master, dev)
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:23:00 2019 +0800
forth
commit 2c48555843e19cfe9c86ceff886e5c1536afe5ec
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:21:19 2019 +0800
third
commit a8aa4a763b1fcd24232ea38e62fcb941ce200561
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:20:54 2019 +0800
second
commit 852d56db6edb8826a9a9bd8621457e21d366260f
Author: smithgua <206007768@qq.com>
Date: Mon Jul 1 21:20:28 2019 +0800
first
对于第四次提交是想对于master
和dev
分支同时存在的(因为我也没有深入的学习过,通过廖雪峰老师的博客,我是这么认为的)
特殊的分支合并
解决冲突
我们将dev
分支删掉,重新创建一个feature1
分支,然后就继续进行提交
$: git checkout -b feature1
切换到一个新分支 'feature1'
$: echo "fifth" >> readme.txt
$: git add readme.txt
$: git commit -m "fifth"
[feature1 00205b0] fifth
1 file changed, 1 insertion(+)
然后我们切换会master
分支,并且在master
分支上新建一个提交
$: git checkout master
切换到分支 'master'
$: echo "sixth" >> readme.txt
$: git add readme.txt
$: git commit -m "sixth"
[master b3c0296] sixth
1 file changed, 1 insertion(+)
我们还可以使用git log
来做简单的查看
$: git log
commit b3c02961f177ba115b3e315efe2c028161a1072f (HEAD -> master)
Author: smithgua <@qq.com>
Date: Mon Jul 1 22:00:58 2019 +0800
sixth
commit 0e8b7e3e9fb97cad0c41a8818cc757bb839a8b8b
Author: smithgua <@qq.com>
Date: Mon Jul 1 21:54:05 2019 +0800
forth
commit 2c48555843e19cfe9c86ceff886e5c1536afe5ec
Author: smithgua <@qq.com>
Date: Mon Jul 1 21:21:19 2019 +0800
third
commit a8aa4a763b1fcd24232ea38e62fcb941ce200561
Author: smithgua <qq.com>
Date: Mon Jul 1 21:20:54 2019 +0800
second
commit 852d56db6edb8826a9a9bd8621457e21d366260f
Author: smithgua <8@qq.com>
Date: Mon Jul 1 21:20:28 2019 +0800
first
可以看出来在master
分支上,只有第六次提交,而没有第五次提交,这是因为第五次提交是在feature1
上建立的
现在master
和feature1
分支各自都有了新的提交,也就是说,产生了分叉,引用廖雪峰老师的博客中图片
这种情况是无法进习惯执行Fast-forward
的,我们可以尝试一下
$: git merge feature1
自动合并 readme.txt
冲突(内容):合并冲突于 readme.txt
自动合并失败,修正冲突然后提交修正的结果。
也就是说当前情况是存在冲突的,必须手动解决冲突才可以继续提交。我们可以使用git status
来检查冲突的文件
$: git status
位于分支 master
您有尚未合并的路径。
(解决冲突并运行 "git commit")
(使用 "git merge --abort" 终止合并)
未合并的路径:
(使用 "git add <文件>..." 标记解决方案)
双方修改: readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
我们可以查看一下readme.txt
中的文件
$: cat readme.txt
first
second
third
forth
<<<<<<< HEAD
sixth
=======
fifth
>>>>>>> feature1
git使用<<<<<<<
,=======
, >>>>>>>
来标记不同分支的内容,现在我们修改内容保存
$: vim readme.txt
现在文本中是如下的内容
first
second
third
forth
<<<<<<< HEAD
sixth
=======
fifth
>>>>>>> feature1
我们将其修改为如下内容
first
second
third
forth
seventh
现在我们可以再次提交了
$: git add readme.txt
$: git commit -m "conflict fixed"
[master 02c590f] conflict fixed
现在,master
分支和feature1
分支就变成了下图所示,引用廖雪峰老师博客中的图片
我们也可以使用带有参数的git log
来查看分支的合并情况
$: git log --graph --pretty=oneline --abbrev-commit
* 02c590f (HEAD -> master) conflict fixed
|\
| * 4d5aa1d (feature1) fifth
* | 2e910ea sixth
|/
* 021ef09 forth
* f83dd14 third
* 06283ca second
* 805e981 first
总结: 在git分支存在分叉的情况下,我们需要首先解决冲突,之后再提交。
解决冲突就是将合并失败的文件手动编译为我们希望的内容,再提交。
分支管理策略
git merge --no-ff -m "merge with --no-ff" dev
通常,git在合并分支的时候,会使用Fast-forward
模式,这种模式下,删除分支后会丢掉分支信息。
所以我们如果强制禁用Fast forward
模式,git就会在merge时,生成一个新的commit,这样,从分支历史上就可以看出分支信息
使用--no-ff
我们先删除feature1
分支,然后新创建一个分支,并提交一个新的commit
。
$: git branch -d feature1
$: git checkout -b dev
切换到一个新分支 'dev'
$: echo "eighth" >> readme.txt
$: git add readme.txt
$: git commit -m "eighth"
[dev 5f2e123] eighth
1 file changed, 1 insertion(+)
然后我们尝试合并一下,首先将分支转到master
,而且,在使用--no-ff
时,会创建一个新的节点,所以要加上-m
参数,并将commit
描述写进去
$: git checkout master
切换到分支 'master'
$: git merge --no-ff -m "merge with --no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
我们可以使用git log
来查看分支历史
$: git log --graph --pretty=oneline --abbrev=commit
* 2e2604d (HEAD -> master) merge with --no-f
|\
| * 5f2e123 (dev) eighth
|/
* 02c590f conflict fixed
|\
| * 4d5aa1d fifth
* | 2e910ea sixth
|/
* 021ef09 forth
* f83dd14 third
* 06283ca second
* 805e981 first
现在,merge
后就变成下图这样,引用廖雪峰的博客中的图片
需要注意的是,在这个时候,master
所指的那个节点是dev
节点的复制
分支策略
在实际开发中,我们应当按照几个基本原则
master
分支应该是非常稳定的,仅仅用来发布新版本,平时不在上面干活- 干活都在
dev
分支上,也就是说,dev
分支是不稳定的,当我们要发布某个版本的时候,才把dev
分支合并到master
分支上。 - 所有成员都在
dev
分支上工作,每个人都有自己的分支,时不时地往dev分支上合并(这个合并应该是要解决冲突的)
我比较好奇dev
是怎么往master
分支上合并的,所以我尝试了一下
当前是这样的
现在我们给dev
分支新添加了一个节点,也就是说变成了下图那样
使用命令实现这一情况
$: git checkout dev
切换到分支 'dev'
$: echo "ninth" >> readme.txt
$: git add readme.txt
$: git commit -m "ninth"
[dev 14ade7e] ninth
1 file changed, 1 insertion(+)
$: git checkout master
切换到分支 'master'
然后我们使用git merge
来合并分支,并且使用git log
来查看一下
$: git merge --no-ff -m "merge with --no-ff two" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
$: git log --graph --pretty=oneline --abbrev-commit
* a0758fa (HEAD -> master) merge with --no-f two
|\
| * 14ade7e (dev) ninth
* | 2e2604d merge with --no-f
|\ \
| |/
| * 5f2e123 eighth
|/
* 02c590f conflict fixed
|\
| * 4d5aa1d fifth
* | 2e910ea sixth
|/
* 021ef09 forth
* f83dd14 third
* 06283ca second
* 805e981 first
可以看出来又新建了一个节点,而且master
所指的那个节点和dev
所指的那个节点仍旧是复制的
现在我们尝试一下删除dev
节点,并再次使用git log
检查一下
$: git branch -d dev
已删除分支 dev(曾为 14ade7e)。
$: git log --graph --pretty=oneline --abbrev-commit
* a0758fa (HEAD -> master) merge with --no-f two
|\
| * 14ade7e ninth
* | 2e2604d merge with --no-f
|\ \
| |/
| * 5f2e123 eighth
|/
* 02c590f conflict fixed
|\
| * 4d5aa1d fifth
* | 2e910ea sixth
|/
* 021ef09 forth
* f83dd14 third
* 06283ca second
* 805e981 first
也就是说,即便删除了dev
节点,但是其合并还是有所显示
分叉合并
分支-保护现场
-
git stash
暂存当前工作状态
-
git stash pop
来弹出最近一次stash的内容并且把将其删除
软件开发中,bug就像家常便饭一样。有了bug就要修改,而在git中,我们可以通过新建一个临时分支来修复bug,修复后,合并分支,然后将临时分支删除
现在我们修复一个bug的任务时,我们首先创建一个issue
分支来修复它,但是,我们正在dev
分支上进行的开发还没有结束
$: git status
位于分支 dev
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)
修改: readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
这个时候,我们因为种种原因而无法提交,但是又必须理解修复bug,这个时候我们可以使用stash
功能,将工作区存储起来,然后之后可以继续恢复现场
$: git status
保存工作目录和索引状态 WIP on dev: a0758fa merge with --no-f two
这个时候再次使用git status
就可以看出工作区是干净的了。然后就可以创建分支进习惯你修复bug了
首先确定在哪个分支上修复bug,假定需要在master
分支上修复,我们就在master
分支上创建临时分支
$: git checkout master
切换到分支 'master'
$: git checkout -b issue
切换到一个新分支 'issue'
加入修复bug就是把readme.txt
中的seventh修改为fifth,然后提交
$: cat readme.txt
first
second
third
forth
seventh
eighth
ninth
$: vim readme.txt
$: git add readme.txt
$: git commit -m "fix bug"
[issue 6438fab] fix bug
1 file changed, 1 insertion(+), 1 deletion(-)
现在我们切换到master
分支,并完成合并,最后删除issue
分支
$: git checkout master
$: git merge --no-ff -m "merged fix bug" issue
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
完成合并了,现在回到dev
分支继续工作。我们可以使用git stash list
来查看刚刚存储的工作区
$: git checkout dev
$: git status
位于分支 dev
无文件要提交,干净的工作区
$: git stash list
stash@{0}: WIP on dev: a0758fa merge with --no-f two
现在我们需要恢复工作区,有两种方法:
1、使用git stash apply
来恢复,但是这种恢复,stash内容并不删除,需要使用git stash drop
来删除
2、直接使用git stash pop
,恢复的同时,也删除了stash内容
$: git stash pop
位于分支 dev
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git checkout -- <文件>..." 丢弃工作区的改动)
修改: readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
丢弃了 refs/stash@{0} (d9f26ca4f7ce76802cfa1822bf3bbe0fa98623a1)
强制删除
当我们在某个分支上工作时,突然被告知这条分支要被舍弃,这个时候,我们就需要强制删除该分支
举例说明
加入我们在dev
上有一个提交
$: git checkout dev
$: vim readme.txt
$: git add readme.txt
$: git commit -m "seventh"
[dev f401acc] seventh
1 file changed, 1 insertion(+), 1 deletion(-)
然后我们回到master
分支,并且正准备合并他,但是这时候突然被要求要删除该分支。
我们可以使用git branch -D dev
来强制删除
$: git branch -d dev
error: 分支 'dev' 没有完全合并。
如果您确认要删除它,执行 'git branch -D dev'。
$: git branch -D dev
已删除分支 dev(曾为 f401acc)。