Git中的代码分支的代码同步

作者: Android架构 | 来源:发表于2019-05-14 15:01 被阅读17次

    当提交代码到远程分支,经常会遇到提交的时候被拒绝的情况

    $ git push origin master
    To git@gitee.com:micaixiaoduanku/Demo.git
     ! [rejected]        master -> master (fetch first)
    error: failed to push some refs to 'git@gitee.com:micaixiaoduanku/Demo.git'
    hint: Updates were rejected because the remote contains work that you do
    hint: not have locally. This is usually caused by another repository pushing
    hint: to the same ref. You may want to first integrate the remote changes
    hint: (e.g., 'git pull ...') before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    

    这种情况是由于本地分支代码的版本已经落后远程分支代码版本这个时候通常会有三种选择

    1. pull远程代码,再本地做merge后push到远程分支
    2. 直接进行一个merge远程分支的操作,再做提交
    3. 进行一次rebase再做提交
      这三种操作方式操作方式和结果是有区别的,下面做一个总结
      准备工作:
      我在码云上创建一个空仓库,并且clone下来
    $ git clone git@gitee.com:micaixiaoduanku/Demo.git
    Cloning into 'Demo'...
    remote: Counting objects: 3, done.
    remote: Total 3 (delta 0), reused 0 (delta 0)
    Receiving objects: 100% (3/3), done.
    Checking connectivity... done.
    $ mv Demo Demo1
    $ git clone git@gitee.com:micaixiaoduanku/Demo.git
    Cloning into 'Demo'...
    remote: Counting objects: 3, done.
    remote: Total 3 (delta 0), reused 0 (delta 0)
    Receiving objects: 100% (3/3), done.
    Checking connectivity... done.
    $ mv Demo Demo2
    $ ls
    Demo1   Demo2
    

    如上所示,目前本地拥有2个仓库的clone版本Demo1和Demo2.
    下面我创建一个fileA文件并提交到远程分支master上面

    $ cd Demo1
    $ ls
    README.md
    $ touch fileA
    $ git add .
    $ git commit -m "add fileA from Demo1"
    [master f8a717c] add fileA from Demo1
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 fileA
    $ git push origin master
    Counting objects: 3, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (3/3), 273 bytes | 0 bytes/s, done.
    Total 3 (delta 0), reused 0 (delta 0)
    To git@gitee.com:micaixiaoduanku/Demo.git
       35e89fa..f8a717c  master -> master
    

    接下来进入Demo2仓库,创建一个fileB文件并提交

    $ touch fileB
    $ git add .
    $ git commit -m "add fileB from Demo2"
    [master 8761ffb] add fileB from Demo2
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 fileB
    

    这个时候去push到远程master分支上面会出现,文章开始所描述的情况

    $ git push origin master
    To git@gitee.com:micaixiaoduanku/Demo.git
     ! [rejected]        master -> master (fetch first)
    error: failed to push some refs to 'git@gitee.com:micaixiaoduanku/Demo.git'
    hint: Updates were rejected because the remote contains work that you do
    hint: not have locally. This is usually caused by another repository pushing
    hint: to the same ref. You may want to first integrate the remote changes
    hint: (e.g., 'git pull ...') before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    

    第一种操作,根据提示进行pull

    $ git pull origin master
    

    出现了一个提示

    Merge branch 'master' of gitee.com:micaixiaoduanku/Demo
    
    # Please enter a commit message to explain why this merge is necessary,
    # especially if it merges an updated upstream into a topic branch.
    #
    # Lines starting with '#' will be ignored, and an empty message aborts
    # the commit.
    

    上面的意思是,这里进行了一个merge远程分支master的操作,并且是作为一次commit, 当然你可以删除这个Message忽略这次merge.(如果忽略这次merge,需要自己手动进行merge, 待会儿我会补充这种情况如何处理,下面先看不删除Message的情况)
    接着我们进行再进行push操作

    $ git push origin master
    Counting objects: 4, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (4/4), done.
    Writing objects: 100% (4/4), 559 bytes | 0 bytes/s, done.
    Total 4 (delta 0), reused 0 (delta 0)
    To git@gitee.com:micaixiaoduanku/Demo.git
       f8a717c..3b567c1  master -> master
    

    这下成功了,看看提交记录

    $ git log
    commit 3b567c182ad6e262404ce60d7ec82447c837c98a
    Merge: 20fe0ea f8a717c
    Author: huangli <huangli@bilibili.com>
    Date:   Fri Jan 19 16:02:38 2018 +0800
    
        Merge branch 'master' of gitee.com:micaixiaoduanku/Demo
    
    commit 20fe0ea4baca93380b12836c026b15681b5c6905
    Author: huangli <huangli@bilibili.com>
    Date:   Fri Jan 19 15:58:58 2018 +0800
    
        add fileB from Demo2
    
    commit f8a717cb55e6e75163d66e4d62d2af0f84d96eb0
    Author: huangli <huangli@bilibili.com>
    Date:   Fri Jan 19 15:57:56 2018 +0800
    
        add fileA from Demo1
    

    这种情况有提交“Merge branch 'master' of gitee.com:micaixiaoduanku/Demo”的提交记录,其实我本意并不希望出现这个提交记录,我只希望有一条“add fileB from Demo2”的提交记录,在刚才pull的过程中,我拉下来了远程仓库的fileA文件,这是一个merge的过程,在git中merge是一个commit的操作,切记(这点和SVN不同),也许有同学会问到,那我如果删除前面提到commit的Message会不会就不会有这条提交记录了?我们来试试看
    我在删除Merge branch 'master' of gitee.com:micaixiaoduanku/Demo 会得到这条提示

    error: Empty commit message.
    Not committing merge; use 'git commit' to complete the merge.
    

    再来看看log

    $ git log
    commit 8cda7fa99bdae380b8486c70402c16664ed338e6 (HEAD -> master)
    Author: 351573105 <351573105@qq.com>
    Date:   Sat Jan 20 20:51:47 2018 +0800
    
        add fileB from Demo2
    
    commit 00d805930f9bd5b1dff5beb2027c3b8b7c3238c4
    Author: Eric <micaixiaoduanku@sina.cn>
    Date:   Sat Jan 20 20:43:03 2018 +0800
    
        Initial commit
    

    果然,没有那条我讨厌的merge log了,这个时候我再看看本地分支的status

    $ git status
    On branch master
    Your branch and 'origin/master' have diverged,
    and have 1 and 1 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)
    
    All conflicts fixed but you are still merging.
      (use "git commit" to conclude merge)
    
    Changes to be committed:
    
        new file:   fileA
    

    我晕,merge下来的fileA是在暂存区,还没有commit, 看来是逃不过这条commit message的。

    总结:pull这种方式会存在一个merge的过程,这个merge过程是会当成一个commit提交的,这样会造成一个结果是:我把fileA merge过来了并提交了,那么log中将会出现一个 merge的commit里面包含增加fileA文件,那么pull下来的log记录将会和“add fileA from Demo1” 中提交fileA的这条记录有冲突,试想一下,目前3个同事协同开发,同事A, 创建一个文件A并提交,同事B, 创建文件B并提交(这个时候也要进行同步,但是他用的rebase, 不会有多条commit记录),重点看同事C , 创建文件C并提交,他进行了pull操作,然后merge了文件A和文件B, 这是两条提交记录,一条是添加文件C,另外一条是文件A和文件B的一条merge commit, 这个时候提交记录看上去就很奇怪。

    • 一是同事A和同事B的内容重复
    • 二是你明明只想提交一个文件C,却顺带提交了文件A和文件B
      这也是在这种情况下建议用rebase的原因.

    第二种操作,直接进行merge

    切换到Demo1,编辑fileA

    $ vim fileA
    

    添加一行

    Demo1 修改fileA
    

    然后往远程分支上面提交

    $ git add .
    $ git commit -m "Demo1 修改 fileA"
    [master 78cbea3] Demo1 修改 fileA
     1 file changed, 1 insertion(+)
    $ git push origin master
    To git@gitee.com:micaixiaoduanku/Demo.git
     ! [rejected]        master -> master (fetch first)
    error: failed to push some refs to 'git@gitee.com:micaixiaoduanku/Demo.git'
    hint: Updates were rejected because the remote contains work that you do
    hint: not have locally. This is usually caused by another repository pushing
    hint: to the same ref. You may want to first integrate the remote changes
    hint: (e.g., 'git pull ...') before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    

    这个时候又不同步了,会叫你进行pull的情况,这个时候我们选择去merge远程分支
    先执行git fetch命令(fetch是获取远程仓库所有信息,但是不会merge到本地仓库,这是它和pull的区别,pull是会进行merge的)

    $ git fetch
    remote: Counting objects: 4, done.
    remote: Compressing objects: 100% (4/4), done.
    remote: Total 4 (delta 0), reused 0 (delta 0)
    Unpacking objects: 100% (4/4), done.
    From gitee.com:micaixiaoduanku/Demo
       f8a717c..3b567c1  master     -> origin/master
    

    再执行

    git merge origin/master 
    
    Merge remote-tracking branch 'origin/master'
    
    # Please enter a commit message to explain why this merge is necessary,
    # especially if it merges an updated upstream into a topic branch.
    #
    # Lines starting with '#' will be ignored, and an empty message aborts
    # the commit.
    

    同样会出现之前进行pull操作的情况,但这个时候它默认的message不是“Merge branch 'master' of gitee.com:micaixiaoduanku/Demo”,看出区别了吗?一个pull的message是merge远程的分支,而fetch后再merge的message是merge的origin/master远程跟踪, 它实质上是一种本地merge(本地分支和本地分支进行merge, pull是本地分支和远程分支进行merge). 随后我们看下log

    $ git log
    commit 3efb4143cb6ff5fd9c1f96d3acdf6a31c7466402
    Merge: 78cbea3 3b567c1
    Author: huangli <huangli@bilibili.com>
    Date:   Fri Jan 19 16:12:47 2018 +0800
    
        Merge remote-tracking branch 'origin/master'
    
    commit 78cbea3d1f3203517fcb63c06d2cbe1ad93bacc5
    Author: huangli <huangli@bilibili.com>
    Date:   Fri Jan 19 16:10:49 2018 +0800
    
        Demo1 修改 fileA
    
    commit 3b567c182ad6e262404ce60d7ec82447c837c98a
    Merge: 20fe0ea f8a717c
    Author: huangli <huangli@bilibili.com>
    Date:   Fri Jan 19 16:02:38 2018 +0800
    
        Merge branch 'master' of gitee.com:micaixiaoduanku/Demo
    
    commit 20fe0ea4baca93380b12836c026b15681b5c6905
    Author: huangli <huangli@bilibili.com>
    Date:   Fri Jan 19 15:58:58 2018 +0800
    

    同样会多一条merge的commit记录.
    最后再进行push

    $ git push origin master
    Counting objects: 5, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (4/4), done.
    Writing objects: 100% (5/5), 542 bytes | 0 bytes/s, done.
    Total 5 (delta 1), reused 0 (delta 0)
    To git@gitee.com:micaixiaoduanku/Demo.git
       3b567c1..3efb414  master -> master
    

    总结: 这种方式和pull很像,区别就是一个远程直接merge,一个是先fetch再进行本地merge. 同样它也会产生一个merge操作后commit日志,这点是对于有提交记录洁癖的人不太妥当.

    第三种操作,进行ReBase

    什么是ReBase?http://gitbook.liuhui998.com/4_2.html
    再切换回Demo2,修改fileA文件,在第一行写“Demo2 修改fileA”,然后提交到远程分支.

    $ vim fileA
    $ git add .
    $ git commit -m "Demo2 修改fileA"
    [master 2aac6c6] Demo2 修改fileA
     1 file changed, 1 insertion(+)
    $ git push origin master
    To git@gitee.com:micaixiaoduanku/Demo.git
     ! [rejected]        master -> master (fetch first)
    error: failed to push some refs to 'git@gitee.com:micaixiaoduanku/Demo.git'
    hint: Updates were rejected because the remote contains work that you do
    hint: not have locally. This is usually caused by another repository pushing
    hint: to the same ref. You may want to first integrate the remote changes
    hint: (e.g., 'git pull ...') before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    

    这个时候先进行一次fetch操作

    $ git fetch
    remote: Counting objects: 5, done.
    remote: Compressing objects: 100% (4/4), done.
    remote: Total 5 (delta 1), reused 0 (delta 0)
    Unpacking objects: 100% (5/5), done.
    From gitee.com:micaixiaoduanku/Demo
       3b567c1..3efb414  master     -> origin/master
    

    接着rebase

    $ git rebase origin/master
    First, rewinding head to replay your work on top of it...
    Applying: Demo2 修改fileA
    Using index info to reconstruct a base tree...
    M   fileA
    Falling back to patching base and 3-way merge...
    Auto-merging fileA
    CONFLICT (content): Merge conflict in fileA
    Failed to merge in the changes.
    Patch failed at 0001 Demo2 修改fileA
    The copy of the patch that failed is found in:
       /Users/huangli/Desktop/mygit/test/Demo2/.git/rebase-apply/patch
    
    When you have resolved this problem, run "git rebase --continue".
    If you prefer to skip this patch, run "git rebase --skip" instead.
    To check out the original branch and stop rebasing, run "git rebase --abort".
    

    fileA出现了冲突,我们先去解决冲突

    <<<<<<< 3efb4143cb6ff5fd9c1f96d3acdf6a31c7466402
    Demo1 修改fileA
    =======
    Demo2 修改fileA
    >>>>>>> Demo2 修改fileA
    

    看看目前status

    $ git status
    rebase in progress; onto 7d18bfc
    You are currently rebasing branch 'master' on '7d18bfc'.
      (fix conflicts and then run "git rebase --continue")
      (use "git rebase --skip" to skip this patch)
      (use "git rebase --abort" to check out the original branch)
    
    Unmerged paths:
      (use "git reset HEAD <file>..." to unstage)
      (use "git add <file>..." to mark resolution)
    
        both modified:   fileA
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    目前处于一个rebasing状态,接下来要做的是,解决冲突后执行一个"git rebase --continue",好,我们先解决一下冲突,修改成如下

    Demo1 修改fileA
    Demo2 修改fileA
    

    然后执行

    $ git rebase --continue
    fileA: needs merge
    You must edit all merge conflicts and then
    mark them as resolved using git add
    

    提示说还需要add过后表明解决了冲突,ok, 我先add.

    $ git add fileA
    $ git rebase --continue
    Applying: Demo2 修改fileA
    

    最后来看看提交记录.

    $ git log
    commit 884a0b87c06dcecf1792cb0c900d26cb3f2f0a88 (HEAD -> master)
    Author: 351573105 <351573105@qq.com>
    Date:   Sat Jan 20 22:10:27 2018 +0800
    
        Demo2 修改fileA
    

    哈哈,终于没有令代码洁癖厌烦的merge commit log了。

    总结:

    在解决本地分支和远程分支代码不同步的时候使用rebase的优势显而易见,它既可以完成代码的merge工作,同时可以不出现merge commit log记录,从而保证提交记录的整洁。所以多人协同在同一条分支下面进行开发的情况下,出现分支代码不同步的情况下,一定要使用rebase进行的冲突处理。

    自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎么学,方法有没有?

    没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎么进阶学习的朋友。【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

    资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!

    点击链接加入群聊【Android移动架构总群】:加入群聊

    资料大全

    相关文章

      网友评论

        本文标题:Git中的代码分支的代码同步

        本文链接:https://www.haomeiwen.com/subject/gforaqtx.html