集中式版本控制主要特点是集中存放所有资料,所有人的所有变动都更新到中央服务器中。同时所有相关人员想要进行相关浏览和修改,都需要从中央服务器下载最新版资料才能开展工作,所以对网络比较依赖。如何直接修改忘记下载最新版或者网络断掉,整个工作就会受到影响,适合小项目。
分布式版本控制系统的特点就是每一个相关人员的电脑都是关键结点,记录自己的更新和改动,当有网络的时候向整个系统提交更新,每个人都知道我做了什么和别人做了什么,减少了沟通成本,适合大项目。
TXT文件,网页,程序代码文件这类文件的改动有具体的提示,但是像照片,视频这些二进制文件,不能有效提示改动信息,只能提示文件大小改变了多少。
修改和回退
每提交一个新版本,实际上Git就会把它们自动串成一条时间线。
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD
指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL
:
改为指向add distributed
:
工作区,暂存区,版本库
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
- 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
- 第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
git reset --hard HEAD^:回退到上一个版本,HEAD^^(表示上上一个版本)
常用命令
git status:查看当前工作区的状态
git diff:可以查看修改内容。
git add readme.txt:添加到仓库
git commit -m "add readme.txt":提交到仓库
git log:命令显示从最近到最远的提交日志
git reset --hard HEAD^:回退到上一个版本,HEAD^^(表示上上一个版本)
git reset --hard commit_id:只要知道commit_id就能去到那个版本,不管是前进还是后退,commit_id可以是前几个字符
git reflog:显示你的每一次命令,因此当你关掉界面时,还可以用这个命令找到commit_id
git checkout -- readme.txt:把readme.txt文件在工作区的修改全部撤销
撤销和回退
情况一:
$ git checkout -- readme.txt
命令git checkout -- readme.txt
意思就是,把readme.txt
文件在工作区的修改全部撤销,这里有两种情况:
- 之前没有添加到暂存区,然后再readme.txt中(添加了傻逼BOOS),现在,撤销修改就回到和版本库一模一样的状态;
- 之前添加过一次暂存区,然后再readme.txt中(添加了傻逼BOOS),现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit
或git add
时的状态。
情况二:
你不但写了一些胡话,还git add
到暂存区了:
用命令git reset HEAD <file>
可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
情况三:
现在,假设你不但改错了东西,还从暂存区提交到了版本库,怎么办呢?还记得版本回退一节吗?可以回退到上一个版本。
情况四:
你把stupid boss
提交推送到远程版本库,你就真的惨了……
小结
- 场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令
git checkout -- file
。 - 场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令
git reset HEAD <file>
,就回到了场景1,第二步按场景1操作。 - 场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
删除文件
小提示:先手动删除文件,然后使用git rm <file>和git add<file>效果是一样的。
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
$ git checkout -- test.txt
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!
分支管理
创建一个分支(dev),可以在分支上修修改改,最后在和主分支(master)合并
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
分支冲突
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph
命令可以看到分支合并图。
分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev
分支上,也就是说,dev
分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本;
你和你的小伙伴们每个人都在dev
分支上干活,每个人都有自己的分支,时不时地往dev
分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
Git分支十分强大,在团队开发中应该充分应用。
合并分支时,加上--no-ff
参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward
合并就看不出来曾经做过合并。
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
Bug分支
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash(保存现场)
一下,然后去修复bug,修复后,再git stash pop
,回到工作现场;
在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick <commit>
命令,把bug提交的修改“复制”到当前分支,避免重复劳动。
开发一个新feature,最好新建一个分支;
如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>
强行删除。