介绍分支
很多版本控制系统都是某一种形式支持分支的,分支类似于项目的复制,比如你做了
一个代码写得很好的项目,现在需要一个新的功能,你不可能是在你写得很好的项目
里面进行修改添加的,而是应该复制整个项目进行编写代码,而分支就是实现这样的
功能,分支名称就是你复制的大量代码起的名字.
使用分支可以将工作从开发主线上面分离出来,避免影响主线的开发.
但是很多的版本控制系统的分支是个低效的,他们完全创建一个源代码的目录副本
,对于大项目,这样很浪费时间,而Git的分支模型就很高效,分支是Git的一个亮点.
分支的位置
前面讲过Git的目录,部分如下
其中有两个是和分支有关的,其实分支的名称就是类似一个变量的指针,指针指向的是提交对象hash值,而默认的主分支就是master,例如下面的图片
Git目录中的HEAD保存的就是当前的分支是什么,
而refs里面保存的是每一个分支的最后提交的提交对象的hash值
分支的使用
-
创建分支:git branch 分支名
就是创建一个可以移动的新的指针,这个就是分支,当然,这个指针指向的是当前所在的提交对象
你会发现,虽然创建了一个指针,HEAD指向的还是master,不会自动切换到新的分支上
-
切换分支:
git checkout 分支名 | 切换分支 |
git checkout | 什么参数都没有,就是显示分支得列表 |
git checkout -b 分支名 | 前面的步骤,需要先新建分支,然后再切换过去,这样麻烦,这个命令就是一步完成,新建分支并且切换过去 |
切换分支需要注意的点:
①:切换分支会改变三个地方:HEAD,暂存区,工作目录
HEAD改变成切换的分支名
暂存区变成切换的分支的最后暂存区的样子
工作目录变成切换分支的最后的样子
所以因为上面的原因,在切换分支的时候,确保当前的分支是已提交的状态,就是
在执行git status的时候全部显示已提交状态.
这里说一下三种切换分支的情况:
①: 就是你在一个分支上新建了一个文件,但是你没有跟踪它,在没有跟踪的情况
切换回主线或者切换到其他的分支,这时这个新建的文件就会跟踪你去到主线或者
其他分支,本来这个文件不属于主线或者其他分支的,这样就会造成代码污染主线
或其他分支.而这个新建的文件为什么会跟着你去到主线或者其他分支呢,是因为你没有跟着它,所以它不在git的管理范围,所以切换分支,工作目录就不会对它进行删除
②: 就是你已经跟踪的新建的文件,但是没有提交,这时切换分支.本来已经跟踪的肯定是会在暂存区的,
你切换分支新建文件进入暂存区的也会被带到新的分支上,而且工作目录的新建文件也会被带到新的
分支上,这样也会污染新的分支.
③: 就是已经提交过的文件,现在升级需要修改,修改后的文件你没有跟踪和提交,就想切换分支
这样git是不会给你切换的,因为修改前的文件已经在这个分支提交过,那么修改后git认为修改后的文件一定属于这个分支,所以就强制不给你切换,得让你提交后再能切换.
- 删除分支(不能自己删除自己,得先切换到其他目录上)
git branch -d 分支名 | 这个是删除已经合并的分支,如果分支没有合并,删除就会报错 |
git branch -D 分支名 | 这个是强制删除分支,没有合并的分支也可以删除掉 |
git log --oneline --decorate --graph --all | 这个是可以看整个项目得完整历史,因为切换到主线上,很多主线后面的分支的提交看不了,这个代码就可以看了 |
- 其他
git branch -v | 以查看每一个分支的最后一次提交 |
git branch 分支名 提交对象的hash值 | 新建一个分支并且使分支指向对应的提交对象 ,利用这个可以实现版本的回退,比如你的提交对象的hash值是第一个版本的,那么就回退到第一个版本 |
git config --global alias.别名 “命令” | 这个是当git的命令很长的时候,我们可以给他配一个别名,注意:alias.后面直接加别名,不能空格,后面的命令是写git后面的命令,不用加git,命令要用""括起来,例如:git config --global alias.st status ,配置后直接敲git st 和git status一样 |
git reflog | 就是在版本库里面看所有的提交,包括删除的 |
- 一个使用例子
现在是主分支上面已经有两个稳定的代码就是Jane1.txt和jane2.txt,现在主分支
master指向jane2.txt,
然后你需要修改一个bug,所以创建了一个jing1的分支,在jing1分支上面打了代码jing1.txt和jing.txt,如下图:
然后现在你需要立即解决另外一个bug,所以你需要返回到主分支上面
再新建一个分支urgent,在里面打了jane3.txt和修改了jane1.txt,将这个紧急bug
修改好后测试没问题,应该合并到主分支上,如下图
这里因为urgent和master是在同一条线上的,就是master分支要合并的分支是在master的前面,这样子git就会简单地将HEAD指针向前移动,指向urgent最后的提交对象上面,这样合并不需要处理分歧,也叫做快进
现在处理完了urgent的问题,又回到jing1分支继续写代码,修改了jane1.txt的代码
完成后你又要将jing1分支和master合并,
这时合并就出现了问题了,因为jing1的jane1.txt代码在urgent分支修改过,在jing1分支也修改过,合并的时候就会出现分歧,
而且对于合并过urgent分支的master主分支来说,jing1分支就是过时的,因为master
已经升级过了,
这时jing1和master合并也叫典型合并,需要处理冲突,合并后会提示需要处理的
是哪一个文件代码,你对它进行修改,add,commit后就可以了
上面的逻辑代码如下:
镜风@▒龵 MINGW64 /g/git/workspace/1 (master)
$ git log --oneline --decorate --graph --all
* b238c63 (jing1) jing1.txt comitt for jing1
* a2e2d45 (HEAD -> master) jane2
* 7942d53 jane1
镜风@▒龵 MINGW64 /g/git/workspace/1 (master)
$ git checkout jing1
Switched to branch 'jing1'
镜风@▒龵 MINGW64 /g/git/workspace/1 (jing1)
$ git ls-files -s
100644 eeaa10d7dbd999222fb0557b3b8d7c1bd2c465d4 0 jane1.txt
100644 32b22f6bd6e40627e9502847ec7cf36a3bc87420 0 jane2.txt
100644 d82550eebd096160ee791e84cc4053c6214bf183 0 jing1.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (jing1)
$ git checkout master
Switched to branch 'master'
镜风@▒龵 MINGW64 /g/git/workspace/1 (master)
$ git checkout -b urgent
Switched to a new branch 'urgent'
镜风@▒龵 MINGW64 /g/git/workspace/1 (urgent)
$ git ls-files -s
100644 eeaa10d7dbd999222fb0557b3b8d7c1bd2c465d4 0 jane1.txt
100644 32b22f6bd6e40627e9502847ec7cf36a3bc87420 0 jane2.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (urgent)
$ vim jane1.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (urgent)
$ echo "jane3.txt" > jane3.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (urgent)
$ git add ./
warning: LF will be replaced by CRLF in jane1.txt.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in jane3.txt.
The file will have its original line endings in your working directory
镜风@▒龵 MINGW64 /g/git/workspace/1 (urgent)
$ git commit -m "jane1.txt的修改和jane3.txt增加 to urgent"
[urgent 114582a] jane1.txt的修改和jane3.txt增加 to urgent
2 files changed, 2 insertions(+)
create mode 100644 jane3.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (urgent)
$ git checkout master
Switched to branch 'master'
镜风@▒龵 MINGW64 /g/git/workspace/1 (master)
$ git merge urgent
Updating a2e2d45..114582a
Fast-forward
jane1.txt | 1 +
jane3.txt | 1 +
2 files changed, 2 insertions(+)
create mode 100644 jane3.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (master)
$ git checkout jing1
Switched to branch 'jing1'
镜风@▒龵 MINGW64 /g/git/workspace/1 (jing1)
$ ll
total 4
-rw-r--r-- 1 镜风 197121 7 3月 2 21:35 jane1.txt
-rw-r--r-- 1 镜风 197121 6 3月 2 14:04 jane2.txt
-rw-r--r-- 1 镜风 197121 30 3月 2 21:35 jing.txt
-rw-r--r-- 1 镜风 197121 8 3月 2 21:35 jing1.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (jing1)
$ vim jane1.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (jing1)
$ git commit -a -m "修改了jane1.txt to jing1分支"
[jing1 be620f2] 修改了jane1.txt to jing1分支
1 file changed, 1 insertion(+)
镜风@▒龵 MINGW64 /g/git/workspace/1 (jing1)
$ git checkout master
Switched to branch 'master'
镜风@▒龵 MINGW64 /g/git/workspace/1 (master)
$ git merge jing1
Auto-merging jane1.txt
CONFLICT (content): Merge conflict in jane1.txt
Automatic merge failed; fix conflicts and then commit the result.
镜风@▒龵 MINGW64 /g/git/workspace/1 (master|MERGING)
$ vim jane1.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (master|MERGING)
$ git add ./
镜风@▒龵 MINGW64 /g/git/workspace/1 (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: jane1.txt
new file: jing.txt
new file: jing1.txt
镜风@▒龵 MINGW64 /g/git/workspace/1 (master|MERGING)
$ git commit -m "master合并jing1"
[master 37ea712] master合并jing1
镜风@▒龵 MINGW64 /g/git/workspace/1 (master)
$ git log --oneline --decorate --graph --all
* 37ea712 (HEAD -> master) master合并jing1
|\
| * be620f2 (jing1) 修改了jane1.txt to jing1分支
| * 22c6705 jing.txt的修改 to jing1
| * 83c7ef7 commit for jing.txt to jing1
| * b238c63 jing1.txt comitt for jing1
* | 114582a (urgent) jane1.txt的修改和jane3.txt增加 to urgent
|/
* a2e2d45 jane2
* 7942d53 jane1
典型合并后需要修改的代码的样子
分支模式
一般的分为长期分支和特性分支
上面这张图就很清晰明了,最上面的mater是全公司的人结合的稳定的代码
develop分支就是每一个程序员自己的代码,但是修改时不会直接在develop分支上面修改,而是再继续创建其他的分支修改
这里的master分支和develop分支都是相对稳定的,就是长期分支
下面的topic分支就是程序员为每一个功能或者bug创建的分支,是特性分支
分支的本质
其实分支就是一个有可变指针指向的提交对象,前面介绍过git的文件夹
里面有一个refs文件夹,里面就是保存分支的
比如这里就是保存了三个分支,每一个分支在这里就是一个文件,里面保存的是
每一个分支最后一个提交对象的hash值,
在目录中还有一个HEAD文件,里面保存的就是HEAD当前指向的分支
每一次有新的提交对象提交的时候,HEAD就会向前移动,同时HREAD指向的分支也会变化