切换分支
- git checkout
切换分支时,Git 做了什么?
切换分支,首先意味着 HEAD 的指向变化了,比方说切换到 master 分支:
$ git checkout master
// 内部命令
$ git symbolic-ref HEAD refs/heads/master
git checkout
的参数除了分支名之外,还可以是标签名或者是提交对象:
$ git checkout v2.6.17
这时候切换到了一个游离的提交位置上。当然这不是常见的情况,因为我们总是希望在某个分支上工作,而且这种游离的工作在一段时间之后是会被垃圾回收的。所以如果想要把游离的工作保留下来,你还是需要用git checkout -b <branchname>
。应该说这本身就不是个好的做法。
在没有提交的情况下切换分支
通常来说,写代码之前我们会想好应该在哪个分支下面写,然后切换到那个分支去修改工作区。
但是,如果我在一个分支下面写了半天之后才发现,应该把这些代码放到别的分支去,这该怎么办?如果我不动已经"弄脏的"工作区,直接就git checkout
切换过去,git 会怎么处理?
它有这么几个选择:
- 忽略工作区的修改,用新分支下的工作区代码
- 忽略新分支的工作区代码,把当前工作区的代码挪过去
- 尝试合并二者
很明显第一个选择是不可能的,因为这样做直接把我工作区里的工作成果全部丢弃了。第二个也不可能,因为当前分支切过去了,意味着我是希望以目的分支为工作起点的,但是工作区却还是起点分支的样子,我不得不把目的分支到起点分支之间的修改全部抹平,这不现实。
最合适的是第三个选择,Git 的做法也是如此。
没有冲突的提交
下面是一个例子,初始化项目:
$ git init
$ echo This is the README file. > README
$ git add .
$ git commit -m "init"
新建分支,修改工作区:
$ git checkout -b test
$ echo This line was added in the working directory while in the test branch. >> README
$ cat README
This is the README file.
This line was added in the working directory while in the test branch.
这时候如果要切换回 master 的话,实际上工作区就是不干净的,因为 README 都还没暂存提交。前面也提到了,这种情况 Git 会采用合并操作:
$ git checkout master
M README
swtitched to branch 'master'
$ cat README
This is the REAMME file.
This line was added in the working directory while in the test branch.
$ git status
// 结果是处于未暂存状态,即,是处于工作区。
有冲突的提交
之前的没有冲突的情况还是比较简单,那如果冲突了呢?
开头和之前的例子一样:
$ git init
$ echo This is the readme file. > README
$ git add .
$ git commit -m "init"
现在开始有所不同:
$ git branch test
$ echo Second line added from the master branch. >> README
$ git commit -a -m "Line 2 added"
这里我先创建了一个 test 分支,然后在 master 分支上加了一行并且提交。
再回到 test 分支上:
$ git checkout test
$ cat README
This is the readme file.
这里没有把 master 分支的内容合并过来是因为 master 分支上的工作区是干净的。
然后 test 分支也开始修改:
$ echo Second line added from the test branch. >> README
$ git checkout master
error: You have local changes to 'README'; cannot switch branches.
很明白了,这时候的 test 分支上的工作区不干净,试图切换分支的时候会尝试合并到 master 分支上。但是修改了同一个地方导致了冲突,这时候无法成功地切换分支。