2023-01-12 更新
1 新建
master 是默认分支但并不特殊,跟其它分支没有区别。之所以个个仓库都有 master 分支,是因为
git init
时默认新建,而大多数人又懒得改。后来为了所谓的政治正确, git 将默认分支定为 main ,建议去配置文件里改回来。
Git 是怎么新建分支的呢?很简单,它只是新建了一个指向提交对象的指针。
$ git branch testing
注意, git branch
仅新建分支,不会自动切换到新分支,此时你仍然在 master 分支上。
Git 又是怎么知道当前在哪个分支上呢?也很简单,有一个名为 HEAD 的二级指针指向当前所在的本地分支。
2 切换
$ git checkout another_branch
3 贮藏
只有干净的分支才能顺利地切换,对有修改又不提交的内容,我们必须使用命令 git stash
临时贮藏起来。 git stash -u
更加保险,新建的文件也一并贮藏。
$ git stash list
$ git stash apply
$ git stash drop
$ git stash pop = git stash apply + git stash drop
git clean
可以直接丢弃所有当前修改,此时的分支也是干净的。
4 合并
$ git merge branch_name
注意合并方向。
个人经验:语法意为将其它分支合入当前分支。合并的不只是已经提交的部分,还包括未提交的部分。有待进一步确认。
4.1 没有冲突的双方合并
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
fast-forward 表示合并操作没有需要解决的冲突。
紧急问题解决后删除 hotfix 分支 git branch -d hotfix
,因为你已经不再需要它了。
4.2 没有冲突的三方合并
这和你之前合并 hotfix 分支有点不一样,你的开发历史在一次提交后分叉(diverged), master 分支所指的提交对象并不是 iss53 分支所指的提交对象的直接祖先。出现这种情况时,Git 会使用两个分支的末端所指的提交对象(C4 和 C5)以及这两个分支的工作祖先(C2),做一个简单的三方合并。
4.3 有冲突的三方合并
如果你在 iss53 里的修改和在 hotfix 里的修改涉及到同一文件的同一处,合并它们时就会产生冲突。此时 Git 合并但不提交,停下来等待你去解决冲突。标准冲突解决标记如下:
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
你必须在 =======
分割的两部分中二选一。解决冲突后,<<<<<<<
=======
和 >>>>>>>
这些行必须完全删除,并通过 git add 命令将它们标记为冲突已解决。
git mergetool
会启动一个合适的可视化合并工具,前提是你已配置 merge.tool
。
5 管理
5.1 稳定分支
许多开发者都喜欢只在 master 分支上保留完全稳定的代码,用一些名为 develop 或者 next 的平行分支来做后续的开发和测试。稳定分支的指针总是在提交历史中落后一大截,而特性分支的指针往往比较靠前,就像流水线一样。
5.2 特性分支
任何规模的项目都应该有特性分支,它是一种短期分支,往往工作单一。
5.3 异根分支
强迫症的福音:借助 checkout 我们甚至可以直接创建新的空白分支!创建完先清空工作目录。
$ git checkout --orphan <branchname>
$ git rm --cached -r .
注意,此时 git branch
无法观察到该空白分支,因为它没有任何提交记录,是一个空指针,当第一次提交完成后,它才有名有实。随后你将遇到一堆诸如 fatal: refusing to merge unrelated histories
麻烦事,不得不附加 --allow-unrelated-histories
强制执行命令。