有些人将Git的branching模型称为它的杀手锏。上一节Git internals,我们弄懂了Git的内部原理,但是覆盖的不全。不篇继续学习一些内部原理,同时也全面学习相关的命令。
index也叫做暂存区。用来构建commit要提交的内容。当完成一次提交后,index和那次提交保持一致,然后你可以通过git add等命令来往index中添加、删除文件。然后使用git commit来提交新的index。
branch只是一个指向commit的可移动的指针。默认的branch名字叫做master。当你开始提交,master都指向你最后一次commit,并且每次commit,它都自动向前移动。
创建一个新的branch:
1 | $ git branch testing |
新的branch在创建的时候,和当前branch一致,指向同一个commit。之后你可以切换到新的branch,commit一些提交,此时新branch就和旧的branch分道扬镳了。
git有一个特殊的指针叫做HEAD,它表示当前的branch。
切换分支:
1 | $ git checkout testing |
该命令执行后,HEAD指向testing分支。
将另外一个分支合并到当前分支:
1 | $ git merge hotfix |
Git创建一个快照,该快照是两个分支的合并,并且创建一个merge commit,这个commit有两个parent。
合并时,Git决定两个分支的共同祖先。合并后,可以删除hotfix分支。
冲突的解决办法:
当两个分支修改了同一行内容,那么将产生冲突,如下将testing merge到master,a文件master修改为c,testing修改为b,产生冲突:
1 2 3 4 5 6 7 8 9 10 | $ git merge testing Auto-merging a CONFLICT (content): Merge conflict in a Automatic merge failed; fix conflicts and then commit the result. $ cat a <<<<<<< HEAD c ======= b >>>>>>> testing |
编辑后,提交:
1 2 | $ vim a $ git commit -a -m 'fix conflict' |
上述commit的父为之前的两个分支的最后一次commit。
也可以使用mergetool来解决冲突。
Remote references是那些位于远程仓库的引用,包括branches,tags等。使用git ls-remote显示remote references,或者git remote show显示远程分支。
Remote-tracking branches是不可移动的本地引用,表示远程分支在本地的状态。只有当你推送或者拉取数据时,Remote-tracking branch才移动。
Remote-tracking branches的形式为<remote>/<branch>
git fetch <remote>
用来从服务器同步新的更新,它移动origin/master分支。‘
git push <remote> <branch>
推送本地分支到服务器
从remote-tracking branch checkout一个本地branch,将自动创建一个tracking branch。它track的branch叫做upstream branch。tracking branches是这些和remote branch有直接关系的branch。
当你处于tracking branch,并且执行git pull,git知道从那个服务器的哪个分支提取数据合并。
当你克隆一个仓库时,git自动创建一个track origin/master的分支master,可以手动创建tracking branches
1 2 | $ git checkout -b <branch> <remote>/<branch> $ git checkout --track origin /serverfix |
当执行
1 | $ git checkout serverfix |
如果本地不存在serverfix,但是远端存在,此时会自动创建一个tracking branch。
upstream shorthand
@{upstream} @{u} 表示当前分支的upstream branch
因此,如果当前分支是master,git merge @{u}等价于git merge origin/master
使用git branch -vv可以显示branch对应的upstream branch
git fetch命令,将从服务器fetch down所有的你还没有的改动,但是并不会更新你的本地工作目录,需要你手动合并。
git pull命令等于git fetch命令,立即跟着一个git merge命令。
使用下述命令:
1 | $ git push origin --delete serverfix |
这样只是将branch的指针移除,并不会删除数据,直到执行garbage collection相关的命令。
Git有两种主要的方式,将一个branch的改变集成到另一个branch:merge和rebase。
merge是两个分支最后一次commit的合并。
下面是rebase的例子:
1 2 | $ git checkout experiment $ git rebase master |
它寻找共同的祖宗,然后把experiment的每个改动生成一个patch,apply到master分支,然后experiment指向apply后的地方。master分支不变。
此时,可以切换到master分支,执行fast-forward merge
1 2 | $ git checkout master $ git merge experiment |
结果和merge是一样的,但是rebase有一个更清晰的历史记录。