学会 Git, 看这篇就够了(3)

Learn Git the hard way 3

Posted by Chinsyo on April 21, 2019

在前文中,我们掌握了 Git 通过远程仓库进行团队协作、关联和克隆远程仓库、推送和拉取提交记录以及解决合并冲突。

本篇将在掌握通过远程仓库进行团队协作的基础上,围绕 Git 中最重要的概念之一 —— 分支,进行探讨。

什么是 HEAD

在介绍分支之前我们先回顾 Git 对数据的存储方式,和 SVN 等其他 VCS 不同,Git 保存的不是文件差异,而是一系列文件快照。前文解释了 Git 日志中摘要的由来和作用,在查看 Git 日志时,还显示有 master(HEAD) 的字样,master 分支的名称,而 HEAD 等效于指向当前版本文件状态的指针。

有些拗口,展开来讲,Git 允许我们查看或恢复到指定历史版本,私以为这里应用的是 23 种设计模式中的备忘录模式。即每次操作以链表的数据结构追加在末尾,并使用一个指针指向链表的末尾表示当前状态,将指针向前移动一个元素指向本次提交之前的状态正是 Word 和 Photoshop 等应用中的撤销(undo)操作,此时将指针向后移动一个元素再次指向链表的末尾等效于重做(redo)操作。

什么是分支

理解了什么是 HEAD 之后很容易知晓每个版本(除初始状态之外)状态都有一个祖先版本。

在前文中,你和同事对某个文件的同一部分进行了修改造成冲突,即对同一个祖先状态衍生了两个子状态,这种场景并不罕见。你正在进行一个功能需要维护 greeting.txt 文件,与此同时你的同事正在修复所有文件中遗漏标点符号的句子,为此你们花费了不少精力解决合并冲突(前文中足足用了20张图片解释 QvQ)。

为了避免冲突发生,尽量划分清楚各自负责的功能和文件,但在工程实践中难以避免配置文件和公共文件的存在。

设想我们正在进行一个项目的开发,这个项目同时存在专业版和轻量版,两个版本都长期维护发布版本,专业版包含轻量版的所有功能。从版本控制的角度,这时我们就需要为两者分别创建分支。

查看分支

Git 中通过 branch 子命令进行分支管理,你可以使用前文获得帮助章节提到的方法获得关于 branch 子命令帮助。

在一个 Git 仓库中,不加参数的使用 git branch 命令(或追加 –list)会显示所有本地分支,* 表示当前工作区所在的分支。

创建分支

在 Git 仓库中,可以基于当前 HEAD 指针创建新的分支。

1
2
# 创建 dev 分支
git branch dev

dev 分支创建完成后查看分支列表。

可以看到已经创建了 dev 分支,但目前工作区仍然指向 master 分支。

切换分支

创建好分支后,通过 checkout 命令在不同分支间切换。

1
git checkout dev

切换分支后,工作区指向 dev 分支,git branch 的输出发生对应变化。

创建分支和切换分支也可以使用 git checkout -b 简化为一个命令。

1
2
3
4
5
# 创建并切换到 feature 分支
git checkout -b feature
# 等效于以下两个命令的组合
git branch feature
git checkout feature

再次使用 git branch 命令验证,feature 分支成功创建并完成切换。

git log 和 git checkout 命令结合可以方便的学习其他开源项目的设计思路,查看变更日志并记录摘要,从初始版本依次检出版本查看仓库状态,通常初始版本代码量较小,方便了解一个项目演进的细节。默认情况下 git log 是按照时间由近及远的顺序展示,追加 –reverse 可以倒序显示,将初始版本显示在日志最前方。

1
2
3
# 倒序显示提交日志, 查看第一次提交的标记
git log --reverse --oneline
# 日志第一行输出 e302971 add greeting.txt
1
2
# 检出首次提交到 initial 分支
git checkout -b initial e302971

合并分支

在前文中演示了合并同事在 master 分支的提交,接下来展示合并两个不同的分支,首先切换到 dev 分支并做出一些修改。

要将 dev 分支合并到 master 分支,首先切换到 master 分支,然后在master 分支执行 merge 命令进行合并。

1
2
git checkout master
git merge dev

删除分支

使用 git branch -d(–delete 的缩写) 删除分支。

1
git branch -d feature

需要注意无法删除当前 HEAD 指向的分支,即 git branch 输出中带有 * 前缀的分支。在作者使用的 Shell 主题 oh-my-zsh 中通过安装插件显示 on git:dev o 的字样,表示目前工作在 dev 分支,所以无法删除 dev 分支。

每个项目应当有且只有一个主分支,任何时候都不要尝试删除主分支,除非你想删除整个仓库。实际上,向主分支直接推送代码也是不规范的操作,下一篇会展开讲解更多关于分支的细节。

推送到远程

在前文中学习了推送本地变更到远程的方法,经过刚才的操作,本地新增了分支,可以通过命令将这些分支推送到远程。

1
2
# 首先查看所有分支, -a 选项会同时显示远程分支
git branch -a

可以看到,本地的 dev 分支和 initial 分支没有对应的远程分支。

git push –all 会将本地所有分支推送到远程,命令执行后会提示有两个 new branch。

这时再次查看所有分支,远程分支多出了 dev 和 initial 分支。

删除本地没有产生新提交的 initial 分支。

git push 命令还可以用于删除远程分支。

1
2
3
git push origin --delete initial
# 由于本地已经删除了 initial 分支, 等效于
git push origin --prune

截止到现在,本地和远程的其他分支都被删除,仅保留了 master 和 dev 分支。

本文围绕 Git 中最重要的概念之一 —— 分支,探讨了分支的作用,及查看、新建、删除、合并的方式。截止目前,本系列文章介绍的仍然只是 Git 的冰山一角,希望每位读者认真的执行一遍这些命令。下一篇文章将会介绍 Git 中如何回退、撤销、储藏变更,修改提交历史和其他相关知识。

转载请注明原始出处 学会 Git, 看这篇就够了(3) © 晨晓 | Chinsyo