什么是版本控制
所谓的版本控制就是在文件修改的过程中保存了修改历史,有了这些修改历史可以很方便的撤销以前对文件的操作。
在git中的每一次提交就是一个版本,git将这些版本信息保存在git仓库中,开发者可以从git仓库中找到这些历史版本,从这些历史版本中可以查看对应的修改内容、撤销或者修改之前的操作。
集中式版本控制 VS 分布式版本控制
git属于分布式版本控制系统。分布式和集中式的区别在于,分布式除了中央仓库之外还有本地仓库,每个开发者的机器上都有一个本地仓库,这个本地仓库包含了所有的版本历史,git中的很多操作都是和本地仓库交互,所以不需要联网也可以继续工作。只有在从远程仓库拉取和提交代码时才需要联网操作。
而集中式版本控制系统的特点是只有一台中央服务器,存放着所有版本历史。而其它客户端机器上保存的是中央服务器最新版本的文件快照,不包括项目文件的变更历史,每次提交都需要联网操作。
所以中央仓库在这两个系统中的作用:
分布式:同步代码
集中式:同步代码、保存版本历史
Git中的HEAD、branch
HEAD:始终指向当前commit
git log复制代码
第一行commit
后面括号中的内容都是指向当前commit
的引用,这里可以看出HEAD
是指向master
(分支)然后间接指向当前commit
,用一张图表示:
通常情况下我们可以理解为HEAD
指向当前所在分支,然后间接指向最新的一次commit
。
但是当HEAD
处于detached
状态时,它就直接指向commit
而不指向任何分支。
git checkout --detach复制代码
上图可以看到此时HEAD
直接指向commit
。过程如下图:
HEAD
是 Git
中一个独特的引用,它是唯一的。而除了 HEAD
之外,Git
还有一种引用,叫做 branch
(分支)。HEAD
除了可以指向 commit
,还可以指向一个 branch
,当它指向某个 branch
的时候,会通过这个 branch
来间接地指向某个 commit;另外,当 HEAD
在提交时自动向前移动的时候,它会带着它所指向的 branch
一起移动。
如果在这里提交一次commit
,HEAD会带着branch
向前移动
git commit复制代码
先在可以在log
中查看
git log复制代码
可以看出在创建新的commit
后,HEAD
和master
都指向了它
分支管理
分支是Git很强大的特性。日常开发中我们都不会在master分支进行,而是在新建分支上开发,开发完成后再进行合并。在此过程中经常会遇到各种问题,我也记录下自己在工作过程中在分支管理方面出过错的地方:分支合并、版本回退
1.版本回退
一般版本回退的方式有两种:reset
和revert
。
他们的区别在于,reset
是将一个分支的末端指向另一个提交(移动HEAD以及它指向的branch
),这可以用来移除当前分支的一些提交。revert
在撤销的同时会创建一个新的提交。
git reset
图示:
reset
前
现在执行reset
回到2c9728101101d
的版本
git reset 2c9728101101d --hard复制代码
从log
中可以看到reset
后最新的一次commit
就是2c9728101101d
,reset
之前的两次commit
被移除。如果之前已经将代码提交到远程,reset
后再次推送的话会提示版本落后,此时需要强制提交。
git reset
参数:
--hard
重置位置的同时,清空工作目录的所有改动
--soft
重置位置的同时,保留工作目录和暂存区的内容
--mixed
重置位置的同时,保留工作目录的内容,并清空暂存区(默认) 再次执行revert
,撤销2c97281011
这次提交
git revert 2c9728101101d3efa8e复制代码
可以看到这里新增了的一条commit
58d2eb2a85087
2.分支合并
merge
时的目标 commit
和 HEAD
处的 commit
并不存在分叉,当前分支领先目标commit:空操作 merge
时的目标 commit
和 HEAD
处的 commit
并不存在分叉,当前分支落后目标commit:fast-forward git rebase
:给 commit
序列重新设置基础点(也就是父 commit
),也就是说把指定的 commit
以及它所在的 commit
串,以指定的目标 commit
为基础,依次重新提交一次。 git checkout branch1git rebase master复制代码
rebase
,5和6两条 commits
把基础点从2换成了4。通过这种方式,就让分叉的提交记录重新回到了一条线。而且 rebase
后的 commit
虽然内容和 rebase
之前相同,但它们已经是不同的 commits
。 rebase
后要切回到 master
再 merge
一下,把 master
移动到最新的 commit
。