八、Git标签和分支

1. 标签

标签是Git的对象,包含了对commit对象的引用;另外每个标签都会有一个标签相同名称的ref文件存储在.git/refs/tags/目录下,文件内容为Git对象的SHA值,此处有两种情况:
1)若为轻量级标签,Git不会真正建立tag对象,而由tag的ref文件直接引用commit的SHA值;
2)若为含有附注的标签,则Git会建立tag对象,tag对象包含commit的引用,而tag的ref文件则包含tag对象的引用。

轻量级标签和含附注标签

1.1 查看标签

`git tag`                    # 查看全部标签,按字母序排列 
`git tag -l 'expression'`    # 查看符合条件的标签
`git show <object>`          # 显示Git四种对象的具体信息
查看标签

1.2 管理标签

1.2.1 新建轻量级标签

# 新建轻量级标签,可指定Git对象创建标签,若不指定默认为HEAD。
git tag tagname  [commit|object]    
新建轻量级标签

1.2.2 新建含附注的标签

# 新建含附注标签,可指定Git对象创建标签,若不指定默认为HEAD。
git tag -a tagname -m ‘tag message’ [commit|object]    
含附注标签
含附注标签

1.2.3 轻量级标签和含附注标签的区别

  • 轻量级标签不含打标签人、打标签时间、message等信息
  • 轻量级标签并没有真正建立git的tag对象,它只是在.git/refs/tags/目录下创建了一个tag名字的ref文件,文件内容为tag指向的commit引用。


    只有含附注的标签真正建立了tag对象

1.2.4 分享标签

git push [remote-branch] tagName # 把标签推送至指定远程分支
git push [remote-branch] --tags  # 把所有分支推送至指定远程分支
git push [remote-branch] :refs/tags/tagName  # 删除远程分支指定标签

# 默认情况下,git push不会把标签传送到远程服务器

标签除轻量级标签和含附注的标签外,还有签署标签。若持有签署者的公钥则可以通过验证操作来验证。

2. 分支

分支不是Git对象,它只是包含git的commit对象引用的常规文件,一般保存在.git/refs/heads/和.git/refs/remotes/两个目录,前者是本地分支,后者是远程分支。

2.1 分支概念和原理

  1. 首先回顾下Git的四个对象blob、tree、commit和tag。
    • blob对象:对应工作区的文件,按Git定义的格式存储了文件内容,blob索引为其内容的SHA值;
    • tree对象:对应工作区的目录,可含有子目录和文件。tree对象的内容为其包含文件名和文件对应的blob的SHA值(或其子目录名称和对应的tree对象的SHA值),tree索引为其内容的SHA值;
    • commit对象:包含顶级树(即工作区根目录)的SHA值引用和提交信息,其索引为其内容的SHA值;
    • tag对象:包含了特定commit对象的索引,也称引用,若是含附注的tag还包含打标签的信息,例如标签人、标签时间和message等。
  2. 分支和轻量级tag类似,只包含了commit对象的索引。
相同点 不同点
分支 含commit对象的索引 分支更新后,分支替换为新的commit索引
标签 含commit对象的索引 创建后内容不再变化
  1. 分支是包含commit索引的常规文件,存储在.git/refs/heads/目录和.git/refs/remotes/目录下。
  2. HEAD是一个具有特殊意义的常规文件,内容为当前分支。例如当前分支为master,那么HEAD文件内容为ref: refs/heads/master
  3. 情景例子
    1. 假设当前有两个分支master和dev,现在HEAD指向master分支(即master是当前分支),如下图所示。
      当前状态
    2. 当前分支(master分支)进行一次提交后,如下图所示。
      master分支发生新的提交
    3. 执行git checkout dev切换分支,结果如图。
      切换分支
2.2 分支命令

假设当前HEAD指向唯一的分支master,且当前有两个提交,如下图所示。

初始状态
2.2.0 查看分支
git branch -l # 查看本地分支
git branch    # 查看本地分支的缺省命令
git branch -r # 查看远程分支
git branch -a # 查看所有分支
其他参数:
-v  # 显示分支的最后一次提交信息
2.2.1 创建并检出分支
git checkout -b dev # 创建并检出dev分支
等同于下面两条命令
git branch dev     # 创建dev分支
git checkout dev   # 检出dev分支/切换至dev分支
创建分支

切换分支/检出分支
2.2.2 切换分支

git checkout master

切换分支/检出分支
2.2.3 合并分支

经过一系列提交后,git空间状态如下图所示。
当前状态
  • No FF(非快进)/ merge commit(合并提交)
    当前分支为master分支,dev分支和master分支在47a2提交处发生分离。此时若执行合并操作,则会进行合并提交,也称No FF提交。

git merge dev

merge commit的执行步骤如下:

  1. git首先会对要合并的两个分支的末端的提交和它们的分离处(共同祖先)的提交进行一次简单的三方合并计算。
    三方合并计算
  2. 根据计算结果判断是否有合并冲突。当两个分支的操作是互斥时就会发生冲突,例如两个分支都对同一个文件的同一处文本发生了修改操作,则会有合并冲突。
    1)若无冲突,默认情况下自动执行以下操作:
    a. 将工作区的合并结果进行commit操作,产生一个合并提交。该合并提交有两个parent,即两个合并分支的末端的commit对象。
    b. 当前分支指向新的commit。
    2)若有冲突,则需手动解决冲突,然后手动进行提交,产生的合并结果与上面相同。

    总之,merge commit操作就是根据三个commit对象的快照信息,计算一个新的合并快照,于此同时新建commit对象完成合并操作。
    合并结果
  • Fast forward(快进)

git checkout dev # 检出dev分支

检出dev分支

此时,dev和master两个分支的末端有通路,即有连通的引用链。若在dev分支执行合并master操作,无需创建新的commit对象,可直接将dev的分支指向两个分支中的那个最远末端的commit即可(也就是所谓的快进操作)。

git merge master

合并结果
# 常用参数
git merge -m <msg> <commit> ... 
# -m 后可指定提交信息,否则git自动产生提交信息,类似“merge branch `dev` into master”。
git merge --abort
# 合并失败后会恢复合并前的状态,类似事务失败的情况。建议执行此操作前保持工作区修改内容已提交,否则可能无法恢复。
--commit 
# 合并成功后自动提交(只针对merge commit)
--no-commit 
# 合并成功后不自动提交,需手动提交(只针对merge commit)
--edit,-e 和 --no-edit
# 自动合并后,是否编辑提交信息,前者会进入编辑页面对提交信息进行编辑;后者则接受git产生的提交信息。
--ff和--no-ff
# 针对fast forward合并,指定是否产生新的commit对象。前者不会产生新的commit对象,而后者则会产生新的commit对象指向两个分支的末端commit对象。git默认是--ff操作。
--ff-only
# 只有当fast forward情况时执行合并,否则不做合并操作。开发中常用此操作,例如master分支和fixbug分支常进行fast forward合并的操作。
--squash 
# 压缩合并,详见下一节《Git补充内容》
2.2.4 衍合分支

rebase(衍合)是merge之外的另一种分支合并方式,它和merge的方式产生的最终快照内容相同,但和merge有很大区别。

原理:
1)回到两个分支(待衍合分支和被衍合进去的分支)的共同祖先;
2)提取待衍合分支自共同组先后的每次提交时的差异内容,保存至临时文件;
3)把这些差异文件按次序应用到被衍合进入的分支(类似打补丁),每次应用差异文件都会生成一个新的commit对象;
4)衍合完成,得到和merge一样的快照内容;但是rebase丢失了产生这些差异文件的commit引用,这些commit对象会变成悬挂态而在合适的时候被git垃圾回收。

优点:rebase会产生一个干净的提交历史。例如为某一开源项目进行贡献时,可把本地的分支代码衍合至远程开源库分支的最新提交,这样管理开源库的人就可以通过fast forward纳入你贡献的代码。

不同点 merge rebase
原理 三个commit的合并 差异文件的在目标分支末端的依次应用
是否重写历史
适用范围 公有分支 私有分支
  • 衍合实例

    假设当前状态如下图所示。
    当前状态

git rebase master # 当前分支衍合至master分支

衍合分支
# 常用参数
git rebase <newbase> <branch>
# 把branch分支衍合至newbase分支;若省略branch,则默认为当前分支。

git rebase --onto <newbase> <upstream> <branch>
# branch分支结合upstream分支,可指定从该两者的共同祖先结点开始产生差异文件。
2.2.5 删除分支
git branch --merged       # 查看当前分支和已并入当前分支的其他分支
git branch --no-merged    # 查看未并入当前分支的其他分支
git branch -d branchName  # 删除已并入当前分支的其他指定分支
git branch -D branchName  # 强制删除其他指定分支

2.3 远程跟踪分支和跟踪分支

Checking out a local branch from a remote-tracking branch automatically creates what is called a “tracking branch” (and the branch it tracks is called an “upstream branch”).
——引自《ProGit》

  • 远程跟踪分支:本地仓库通过clone、fetch或pull操作把远程仓库的分支内容down到本地git仓库后,远程仓库的.git/refs/heads/下的分支索引文件down到本地仓库的.git/refs/remotes/下,以此可被git检索到,在本地仓库形成远程跟踪分支。一般用(远程仓库名)/(分支名)形式表示远程跟踪分支。
  • 跟踪分支:从远程跟踪分支检出的本地分支,称为跟踪分支。值得注意的是:克隆仓库时git会自动建立一个master分支来跟踪远程跟踪分支orgin/master。

跟踪分支会通过本地的远程跟踪分支来间接的对远程仓库的分支进行更新操作。详见Git远程仓库

# 常用命令及参数
git checkout --track [远程名]/[分支名]
# 创建跟踪分支并检出

git checkout -b [分支名] [远程名]/[分支名]
# 创建跟踪分支并检出,可指定跟踪分支名称

git push [远程名] :[分支名]
# 删除远程分支

附注:

  1. git help show
    git help show

参考:

1.git merge的三方合并

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容

  • 以下内容是我在学习和研究Git时,对Git操作的特性、重点和注意事项的提取、精练和总结,可以做为Git操作的字典,...
    科研者阅读 4,129评论 4 50
  • 以下内容是我在学习和研究Git时,对Git操作的特性、重点和注意事项的提取、精练和总结,可以做为Git操作的字典,...
    科研者阅读 3,525评论 2 19
  • 打标签 同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签。人们在发布某个软件版本(比如 v1.0...
    三也视界阅读 23,486评论 0 5
  • 一粒米不知为何撒在键盘上 卡在两个数字1和4中间 这样就定格了一生一世 没来由地想象它的前世今生 它的祖祖辈辈和子...
    一半师兄阅读 208评论 0 0
  • 你是一个积极的人,一个热爱生活的人,一定要找到自己,最真的自己,最可爱的自己,自己喜欢的自己,你是独一无二的,你是...
    置身世外阅读 210评论 0 0