git stash与git commit的区别

问题的出现

    写这篇文章的缘由是在工作中初次使用Git的时候遇到了一个奇怪的现象,即每次提交代码的时候,如果没有及时拉取代码就会导致本地库的代码不是最新的,这样自己修改代码之后想要push到远程仓库的时候就会遭到拒绝,每次被拒绝以后我会先拉取代码,然后再继续push,这样可以成功提交代码,可是会产生两个提交对象,一个是我改动产生的提交对象(这个是应该有的),可是还会产生另外一个Merge branch…的提交对象,这个对象里面是我未拉取的别人的提交,最后作为了我的提交push到了远程仓库,这样的现象会使得提交历史记录比较混乱,容易让人迷惑,稍有不慎,就会把别人的提交误认为其他人或自己的。
    由于对Git的了解有限,所以这个现象产生的原因自己一直百思不得其解,直到有一天通过看书与讨论总算弄清楚了现象产生的原因。

隐藏的区别

   在项目开发的过程中,我使用的开发工具是STS,而另一位同事使用的开发工具是IntelliJ IDEA,里面分别集成了Git的插件,使用STS的时候会出现前述的现象,可是使用IDEA在上述情况下并不会产生两个提交对象,也就是不会把他人的提交变成自己的提交再重新提交一遍,我们推测一定是两个工具默认使用的Git命令不同,所以导致产生的现象不一样。
   最后,我们使用命令行重现了两种现象,终于弄懂了不同的Git命令的区别,本质上就是git stash命令和git commit命令的区别。如果我们知道Git的基本原理,那就一定知道Git中存储的是文件的快照而非每个文件与初始版本的差异,那么在每次提交的时候,Git都会对当时的全部文件制作一个快照并保存这个快照的索引(存储在提交对象中)。假设我们在master分支进行开发工作:

          A  local
         /
    D---E---A'  master

在拉取了E(字母代表一个提交对象)提交之后,我们忘记拉取最新的代码就进行了修改,这时候master分支上的提交已经变成了A'
(1) 如果我们使用git commit命令,那么我们本地就会产生一个A的提交对象,那么git pull的时候便需要把master分支合并到本地(可能需要解决冲突),然后再提交:

          A  local
         / 
    D---E---A'  master

合并后产生了一个M提交对象:

          A---M  local
         / 
    D---E---A'  master

最后git push提交到master分支上,则会产生两个提交:

    D---E---A'---A---M    master

(2) 如果我们使用git stash命令,那么我们本地就不会产生新的提交对象,而是把本地的更改先行缓存,那么git pull的时候便可以直接把本地的HEAD更新为A'

          A'  local
         / 
    D---E---A'  master

然后再使用git stash pop命令将本地的修改恢复(可能需要解决冲突),这就相当于我们在A'的基础上进行了修改,然后进行git commit产生了新的提交对象B

          A'---B  local
         / 
    D---E---A'  master

最后git push提交到master分支上,则只会产生一个提交:

    D---E---A'---B    master

总结

    奇怪现象出现的原因并不是Git的bug,而是我们操作方式的不对。通过这个实验,我们也了解了在两个不同的IDE中对于Git操作的默认指令也是不一样的,STS中的EGit插件对于本地的修改会默认git add,而IDEA中集成的Git对本地的修改会默认git stash

版权声明:本文为CSDN博主「cloud_yf」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010629610/article/details/87335894