转自大神周沫凡:https://mofanpy.com/tutorials/others/git/
Git book:https://git-scm.com/book/zh/v2(p54)
目录
1.查看分支(git log --oneline --graph)
2.使用branch创建dev分支(git branch dev)
4.新建并同时切换到该分支(git checkout -b +分支名)
很多时候我们需要给自己或者客户用一个稳定的版本库, 然后同时还在开发另外一个升级版. 自然而然, 我们会想到把这两者分开处理, 用户使用稳定版, 我们开发我们的开发版. 不过 git 的做法却不一样, 它把这两者融合成了一个文件, 使用不同的分支来管理. 所以这一节我们来说说 git 中的 分支 Branch.
Git创建分支、在不同分支之间切换都在瞬间完成,git鼓励在工程中频繁使用分支与合并。Git分支本质上是指向提交对象的可变指针。git的默认分支名字是master,多次提交操作后,其实已经有一个指向最后那个提交对象的master分支,它会在每次的提交操作后自动向前移动。
注:Git的master分支并不是一个特殊分支,它和其它分支完全没有区别。之所以几乎每个仓库都有master分支,是因为git init命令默认创建它,并且大多数人懒得去改动它。
之前我们说编辑的所有改变都是在一条主分支 master
上进行的. 通常我们会把 master
当作最终的版本, 而开发新版本或者新属性的时候, 在另外一个分支上进行, 这样就能使开发和使用互不干扰了。
1.查看分支(git log --oneline --graph)
(git log --oneline --graph会输出你的提交历史、各个分支的指向以及分支分叉情况)
(git log -n 查看前n次的提交内容)
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline --graph
* edb3ff8 (HEAD -> master) back to change 1 and add commit for 1.txt
* 11f06ae change 2
* 2d350cb change 1
* d19b6a5 1.txt
2.使用branch创建dev分支(git branch dev)
(git branch dev #使用branch创建dev分支)
(git branch #查看当前分支(主线和分支))
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git branch dev #使用branch创建dev分支
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git branch #查看当前分支(主线和分支)
dev
* master # * 代表了当前的 HEAD 所在的分支
3.分支切换(git checkout + 分支名)
(git checkout dev 切换到dev分支)
git怎么知道当前在哪一个分支上呢?——HEAD指针,它指向当前所在的本地分支
git branch命令仅仅创建一个新分支,并不会自动切换到新分支中去。当我们想把 HEAD
切换去 dev
分支的时候, 我们可以用到上次说的 checkout
:
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git checkout dev
Switched to branch 'dev'
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (dev)
$ git branch
* dev #当前处于dev分支下
master
NOTE:切换分支时,一定要注意你工作目录里的文件会被改变。如果是切换到一个较旧的分支,你的工作目录会恢复到该分支最后一次提交(commit)时的样子,如果Git不能干净利落完成这个任务,它将禁止切换分支。
4.新建并同时切换到该分支(git checkout -b +分支名)
(git checkout -b +分支名:新建一个dev分支并切换到dev分支上)综合以上2和3,想要新建一个dev分支并同时切换到那个分支上,可以运行带有-b的git checkout命令
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git checkout -b dev
Switched to a new branch 'dev' #新建了dev分支
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (dev)
$ git branch
* dev #并且此时HEAD直接在dev分支下
master
5.删除分支(git branch -d +分支名)
(git branch -d +分支名 #-d用于删除特定分支)条件:当前HEAD不处于此分支
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (dev)
$ git checkout master
Switched to branch 'master'
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git branch -d dev #-d用于删除特定分支
Deleted branch dev (was edb3ff8).
6.合并分支(git merge +分支名)
(git merge +分支名:将该分支与master分支合并)
- 当master是该分支的直接祖先时,git只会简单的将指针向前推进(指针右移)
如图所示,分支master的提交 c2 是分支hotfix的提交 c4 的直接祖先,当master和hotfix合并时,master的指针右移(快进),此时master和hotfix指向了同一个位置,此时可以删除hotfix分支。【我的理解:即此时hotfix基于master分支的内容增加/减少,而master没有变】
- 当master不是该分支的直接祖先时,git会使用两个分支的末端所指的快照以及这两个分支的公共祖先(离得最近的祖先),做一个简单的三方合并,最后做了一个新的快照并且自动创建一个新的提交指向它。这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。其中git会自行决定选取哪一个提交作为最优的共同祖先,并以此作为合并的基础。
如图所示,分支master的提交 c4 不是分支iss53的提交 c5 的直接祖先,当master和iss53合并时,c4、c5和c2做一个简单的三方合并,做了新的快照 c6 且master指向 c6。此时可以删除iss53分支。【我的理解:即此时iss53基于之前master的位置c2增加/减少,而此时master也改变为c4】
Note:如果直接 git merge dev
, git 会采用默认的 Fast forward
(快进)格式进行 merge
, 这样 merge
的这次操作不会有 commit
信息. log
中也不会有分支的图案. 我们可以采取 --no-ff
这种方式保留 merge
的 commit
信息.
实验
- 将dev的修改推送到master
我们的开发板 dev
已经更新好了, 我们要将 dev
中的修改推送到 master
中, 大家就能使用到正式版中的新功能了.首先我们要切换到 master(
切换至 master 才能把其他分支合并过来),
再将 dev
推送过来.
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git merge --no-ff -m "keep merge info" dev # 保留 merge 信息
Merge made by the 'recursive' strategy.
1.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
此时dev版本已经推送至merge版本,1.txt文件内容已经得到更新:
此时,git log --oneline --graph 命令下可以看到分支图形改变。
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (master)
$ git log --oneline --graph
* 3a56813 (HEAD -> master) keep merge info
|\
| * 347bf05 (dev) change 3 in dev # 这里就能看出, 我们建立过一个分支
|/
* edb3ff8 back to change 1 and add commit for 1.txt
* 11f06ae change 2
* 2d350cb change 1
* d19b6a5 1.txt
新实验:
当下只有一个主分支master,想要新建一个math分支,但是在master和math两个分支下,最后一行显示的内容不一样(备注:修改完文件后一定要记得add且commit)
1.master下修改1.py为如下:
2.将其add且commit
Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git commit -am "当前所在分支 master"
[master 68d00e7] 当前所在分支 master
1 file changed, 2 insertions(+), 1 deletion(-)
3.新建分支math,且切换到math下对1.py文件进行修改:
Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git branch math
Administrator@PC201710130840 MINGW64 /f/Git (master)
$ git checkout math
Switched to branch 'math'
4.math下修改1.py为如下:
5.将其add且commit
Administrator@PC201710130840 MINGW64 /f/Git (math)
$ git commit -am "当前所在分支 math"
[math 6a837db] 当前所在分支 math
1 file changed, 1 insertion(+), 1 deletion(-)
这样,在master和math两个分支下就能看到两个不同形式的1.py了!!!
总结:同一个文件夹下的同一个文件,因为所切换到的分支不同,文件所显示的内容也不同。
- 在dev分支中修改并不影响在master中的内容
dev
分支中的 1.txt
和 3.txt
和 master
中的文件是一模一样的. 因为当前的指针 HEAD
在 dev
分支上, 所以现在对文件夹中的文件进行修改将不会影响到 master
分支.
我们在 1.txt
上加入这一行 # I was changed in dev branch
, 然后再 commit
:
此时1.txt文件在dev分支下的内容为:
(将 add 与 commit 合并的方式:git commit -am “xxx”,注意:其只适用于已经在管理库中的文件)
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (dev)
$ git commit -am "change 3 in dev" #名称为change 3 in dev
[dev 347bf05] change 3 in dev
1 file changed, 2 insertions(+), 1 deletion(-)
此时再切换到master,会发现1.txt文件没有# I was changed in dev branch这句话。
Administrator@PC201710130840 MINGW64 ~/Desktop/daily-learning/gitTUT (dev)
$ git checkout master
Switched to branch 'master'
总结:
- git log --oneline --graph 查看分支图
- git branch dev 使用branch创建dev分支
- git checkout + 分支名 分支切换
- git checkout -b +分支名 以上2个的结合:新建并同时切换到该分支
- git branch -d +分支名 删除分支
- git merge +分支名 合并分支
- git commit -am “xxx” 将 add 与 commit 合并的方式