版本管理对开发人员来说至关重要,之前一直使用svn(主要是TortoiseSVN)作为团队配合的协作工具。但是自己相关的开源项目使用的是Git发布在github上。由于项目自身的局限性,很少有大家修改共同文件,以及放弃working directory本地未提交修改的情况。因此对于git的使用存在着些许模糊。本篇博文通过实例来讲解一下git如何放弃working direcotry中未提交的本地修改。
git相较于svn只拥有一个中央仓库而言,每个本地的部分都是一个独立的仓库,往往最终通过商定后合并到同一个仓库作为中心仓库。正是因为git的分布性,使得git存在着本地仓库和远程仓库,大致关系如下:
本地仓库与远程仓库通过pull和push来实现同步,除此以外git本地仓库的操作也因为存在着缓冲区index(也可称之为staged)使得git的操作相较于svn较复杂。
checkout在svn中就是简单的从中央仓库首次签出代码建立本地副本,此后即可通过update、commit、revert等几个简单的操作来实现版本管理的大多数工作。
- 【svn update】:update可以将svn中央版本库的最新代码下载到本地副本,这里有几种情况。第一种,本地没有修改,update后会直接将本地副本同步到服务器最新状态,并且在本地文件夹会显示绿色对号(TortoiseSVN);第二种,本地有所修改但未与中央版本库最新一次修改有交集,update后依然会更新最新状态到本地副本,并且在本地文件夹会显示绿色对号(TortoiseSVN);第三种,本地有所修改但与中央版本库最新一次修改有交集,update后依然会更新最新状态到本地副本,但会在本地文件夹会显示黄色叹号(TortoiseSVN),表明有冲突需要手动解决。
- 【svn revert】:revert最简单的就是放弃本地的修改,这种情况最常使用。另一种情况就是回滚到之前的提交。
- 【svn commit】:commit就是讲本地副本提交到中央服务器。
上述就是svn大致的操作,其回滚操作简单明了。
如上图所示,git相较于svn比较复杂的是因为在本地和版本库之间多了staged缓冲区和远端版本库(之所以git适合分布式协作开发是因为每个本地的版本库可以脱离远端版本库而独立运行,两者的地位完全一样),因此在git的回滚和修改提交时相较于svn比较复杂一些,根据上面git reset和git checkout的对比分析,我们可以得出结论:在staged中存储的是一个snapshot镜像,该镜像是commit提交的目标(当然可以直接使用commit -a来跳过stage缓冲区,直接将working本地工作目录提交到本地版本库)。那么git中如何来放弃本地的修改,以及如何回滚到之前的提交呢?
下面通过实例来讲解一下git中如何放弃本地working directory的修改。
(1) 创建git仓库
(2) 提交三次,准备测试环境
(3) 修改a.txt测试文件,使得working directory改变
(4) git checkout放弃working directory的修改
通过如下指令可以实现放弃working directory的修改:
<code class="language-bash hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">git checkout .//或者git checkout a.txt</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
具体结果如下:
【备注1】:通过git checkout master或者git checkout HEAD是无法放弃working directory的修改的,因为当前所处的位置就是master分支的HEAD。实际结果如下图所示:
【备注2】:既然【备注1】中是因为当前分支已经是master的HEAD而无法放弃working directory的修改,那么通过git checkout HEAD~n签出不同的版本是否可以放弃working directory的修改呢?
尝试一下后会弹出如下错误:
error: Your local changes to the following files would be overwritten by checkout:
a.txt
Please commit your changes or stash them before you can switch branches.
Aborting
因为此时如果调整到非HEAD提交,那么会与本地的修改冲突。所以如果想回滚查看之前的版本的话,正确的步骤是:
<code class="language-bash hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">git checkout . //或者 git checkout every-file-changed-in-working-directory git log <span class="hljs-operator" style="box-sizing: border-box;">-a</span> --oneline //查看希望返回的之前版本号 git checkout commit-number//commit-number是你想返回的版本 git status //查看当前的状态</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
此时我们可以看到之前提交的状态,但是又出现了一个问题。输入git log –oneline发现之前多次commit的日志不见了。难道之前的版本不存在了?
其实这里有一个方法可以看到之前所有的记录,输入如下指令:
<code class="language-bash hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">git reflog</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
如前文所述:git相较于svn比较复杂的是因为在本地和版本库之间多了staged缓冲区和远端版本库(之所以git适合分布式协作开发是因为每个本地的版本库可以脱离远端版本库而独立运行,两者的地位完全一样),因此在git的回滚和修改提交时相较于svn比较复杂一些,本次介绍的放弃本地修改仅仅是对已经被git版本库跟踪文件(tracked files)的分析,如果新增未添加到版本库的文件(即untracked files)的放弃需要结合其他的git指令,后续会进一步介绍,敬请期待。
作者:[email protected]
时间:2016-06-19