使用Git有近半年时间了,配合github使用,再也不用担心代码的备份问题。
之前写过一篇使用git提交到github,那时刚使用github不久,对git的认识也不深,仅仅知道如何commit,push和pull,对于分支等概念就更加不懂了。
不久前在网上看到一本书,《Pro Git》,对Git的解剖非常深入浅出。虽然我还没看完,但已经迫不及待地分享出来。下面的内容是我看过书之后对Git的更深认识,都是摘抄或提炼书中的内容。如果你有时间,非常建议你读读原书,链接在文章最后。
Git基础
Git只关心文件是否发生变化,而不关心哪些内容发生变化。提交之前,git会对文件进行校验和计算,使用的是SHA-1算法,计算出一串40个十六进制字符组成的字符串。
对于任何一个文件,在Git看来,都只有三个状态:已修改(modified),已暂存(staged),已提交(committed)。暂存表示把已修改的文件放在下次提交时要保存的清单中,即使用git add
命令后的文件状态。
基本的Git工作流程如下所示:
- 在工作目录中修改某些文件。
- 对这些文件作快照,并保存到暂存区域。
- 提交更新,将保存在暂存区域的文件快照转存到git目录中。
执行git init
后会在当前目录下创建一个的名为.git的隐藏目录,所有Git需要的数据和资源都存放在这个目录中。
要查看当前目录下的文件处于什么状态,可以用git status
命令。如果你在上次commit之后没有任何修改,会看到下面的输出:
# On branch master
nothing to commit (working directory clean)
如果新添加了文件,git status
可以看到显示没有追踪的文件:
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# readme.md
要查看尚未暂存的文件更新了哪些内容,可以用命令git diff
要查看已经暂存文件和上次提交时快照之间的差异,可以用命令git diff --cached
要从git中移除某个文件,就必须从已跟踪的文件清单中移除,然后提交。可以使用命令git rm
,这样会把目录中的文件也一并删除。如果只是想把文件从暂存区移除,但仍保留在当前目录中,用--cached
选项即可:git rm --cached readme.md
Git分支
何谓分支
使用分支可以让你离开主线,去debug或者开发新功能。
使用git commit
之前,Git会先计算当前目录的校验和,然后在Git仓库中将这些目录保存为树(tree)对象。之后Git创建的提交对象,除了包含相关提交信息以外,还包含着指向这个树对象的指针,这样就能在将来需要的时候,重现此次快照的内容。每个commit对象的内容如下:
每次commit都会新建一个对象,并指向上一个commit对象。两次提交后,就会变成:
git使用master作为分支的默认名字,也就是说如果你没有切换到其他分支上,当前的分支就是master。master在每次提交的时候都会向前移动,所以master实际指向最后一次提交对象。
使用git branch testing
创建一个新的分支,这会在当前的commit对象上新建一个分支指针:
那git如何知道当前在哪个分支呢?实际上还有一个名为HEAD的指针,指向正在工作的分支。创建一个分支后,并不会切换到新建分支上,所以上一步创建了testing分支,但还是在master上工作,所以HEAD指向master:
要切换分支,可以使用git checkout branch_name
命令。例如git checkout testing
,这样HEAD就指向了testing分支:
如果这时再commit一次,新建一个新的commit对象,就会变成:
切换回master分支,再提交一次,这时master就会向前移动,但是testing的祖先仍然不变,变成:
基本的分支与合并
假设现在要修补一个bug,bug的编号是#53。先新建一个分支,并切换过去。
git checkout -b iss53
当你在iss53分支下工作了一段时间后,有更紧急的问题需要修补,你需要做的只是切回master分支,并新建一个hotfix分支:
解决问题后,用git merge
进行合并分支:
git checkout master
git merge hotfix
这时hotfix的使命完成,用git branch -d hotfix
删除hotfix分支。
然后回到iss53分支上继续工作。在问题解决之后回到master分支然后合并。在我们看来,这次合并跟之前的合并hotfix分支,没有什么不一样。但是在git看来,当前的master分支,并不是iss53分支的直接祖先。
这时,git会进行简单的三方合并,做一个新的快照,即下图的C6。
至此,关于Git的基础,尤其是关于分支的概念,应该都有了更深的认识。