git随笔四则 - pull v.s. fetch, stash, rebase, merge

比较了一下git fetch和git pull,总结了一下git stash、git rebase和git merge的常用用法。关于更为详细的细节,比如更多的options,还请参阅git的手册。

get fetch和git pull的区别

简单来说,git pull = git fetch + git merge

做一个小实验:

1. git fetch & git status
git status 仍然会显示 "Your branch is behind 'xxx branch' by N commits"

2. 断网
将电脑网线拔掉或者将无线关闭。

3. git merge & git status
git merge 会显示merge的过程,而git status会显示当前已经是最新的代码。

这个实验说明了:
1. git fetch将远程服务器上的代码拉到了本地,但并不是本地的代码库里,而是本地的某个临时存储的区域,比如可能是.git文件夹里某处(尚需求证);
2. git merge是将以上临时存储区域的代码合并到代码库。当然,这其中可能会存在冲突,那就需要解决冲突。

有一种说法是git fetch比git pull更安全,就是因为在没有冲突的情况下是git pull会自动merge的而开发者可能没有察觉到。但是笔者似乎自用git pull以来,都没有遇见过此种情况,因为如果开发者改变了本地的代码,而无论是commit了还是没有commit,就去运行git pull,似乎都是会有警告的。所以似乎并不存在这种更加安全的说法。如果是这样,那么git pull其实就没什么不好,反而更加方便易用了。

git stash

git stash是一个比较有用的命令。当开发者开发到一半还没有commit的时候,突然意识到应该将代码pull下来,然后在基于pull下来的代码的基础上再继续开发,那么这个时候就可以用git stash了。
git stash将当前的改动保存到一个临时区域(stash),在合适的时机再回放出来。看一个常见case:
1. git stash 或 git stash save
这个命令将当前尚未commit的改动保存到临时区域(stash)。


2. git pull
将最新代码拉到本地。


3. git stash apply
将刚才存储到临时区域的改动再放进代码库里


4. 如果有冲突,则解决冲突;若没有冲突,则可以继续开发了。

常见的git stash的几个命令如下(以下只是简要介绍,更多细节还是要参见手册):
1. git stash list[<options>]
列出当前的stashes. 每个stash都有名字,如:stash@{0}代表当前最新的stash,stash${1}代表前一个stash. 一个输出示例如下:
stash@{0}: WIP on submit: 6ebd0e2... Update git-stash documentation
stash@{1}: On master: 9cc0589... Add git-stash
其中,"WIP on submit" 和 "On master"是这个stash所在的branch,而后面的内容是这个stash被创建时所基于的commit. 

2. git stash show [<stash>]
显示该stash和其所base的代码的不同之处,如git stash show -p stash@{1}显示第二新的stash和基本代码的差异。

3. git stash pop [<stash>]
将stash list里的一个指定的stash移除,并将其应用在当前代码上(apply it on top of the current working tree state, i.e. do the inverse operation of git stash save)。

4. git stash apply [<stash>]
和pop类似,但不会将stash从stash list移除。

5. git stash clear
删除所有的stash

git rebase

git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream> [<branch>]]
如果指定了<branch>,git rebase就会在做任何事情之前先自动执行git checkout <branch>;否则它将保持在当前的branch上。

如果有冲突,那么解决了冲突之后再运行git rebase --continue. 

另一个选择是绕过这这个有冲突的commit,即运行git rebase --skip. 

而运行git rebase --abort的作用是checkout原来的branch并删除.git/rebase-apply下的相关文件,即放弃做rebase了。

Case 1. 

看图如下,并假设当前branch是topic
          A---B---C topic
         /
    D---E---F---G master

那么当运行如下2句命令的任何一句:
git rebase master
git rebase master topic = git checkout topic + git rebase master

结果是:
                         A'--B'--C' topic
                         /
    D---E---F---G master
    
这是因为,rebase谁的含义就是以谁为主,来更新当前的branch,在这里就是“以master为主来更新topic”. 那么,所有在topic上开发的commits就会以最新master的commit为基准,在其上重放topic上的commits,所以效果就是在master的G的后面又跟上了A,B,C. 

Case 2.
如果upstream branch上已经有了一个当前branch上有的commit,那么该commit将被忽略。见下图:
       A---B---C topic
       /
    D---E---A'---F master
    
git rebase会生成:
                   B'---C' topic
                  /
    D---E---A'---F master
    

Case 3.

git rebase还有一种--onto的用法。见下图。
                            H---I---J topicB
                           /
                  E---F---G  topicA
                 /
    A---B---C---D  master
    
运行 git rebase --onto master topicA topicB 

会生成:
                 H'--I'--J'  topicB
                /
                | E---F---G  topicA
                |/
    A---B---C---D  master


git merge

假设有如下的情形,并且当前的branch是master. 
      A---B---C topic
     /
    D---E---F---G master
    
那么在运行了git merge topic之后,会形成下图:
      A-----B---C topic
     /                \
    D---E---F---G---H master
    
git merge topic会重放(replay)自topic branch偏离master以来的所有commits,即A、B、C. 

那么git merge和git rebase又有什么不同呢?
如果在master上运行的是git rebase topic的话,就会以topic为主,将EFG放到C的后面作为master的commits,见下图。
                         E'--F'--G' master
                        /

    D---A---B---C topic


总结:

个人理解是:

在topic branch上想同步master上的代码,用 git rebase master , 因为这样是以master为主,在topic branch上replay(重放) master上的改动;

而在master上想同步topic branch上的代码,则用 git merge master, 这样还是以master为主,在master上replay topic branch上的改动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值