當(dāng)提交代碼到遠(yuǎn)程分支,經(jīng)常會遇到提交的時候被拒絕的情況
$ 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.
這種情況是由于本地分支代碼的版本已經(jīng)落后遠(yuǎn)程分支代碼版本這個時候通常會有三種選擇
1,pull遠(yuǎn)程代碼,再本地做merge后push到遠(yuǎn)程分支
2辐棒,直接進(jìn)行一個merge遠(yuǎn)程分支的操作,再做提交
3牍蜂,進(jìn)行一次rebase再做提交
這三種操作方式操作方式和結(jié)果是有區(qū)別的漾根,下面做一個總結(jié)
準(zhǔn)備工作:
我在碼云上創(chuàng)建一個空倉庫,并且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
如上所示,目前本地?fù)碛?個倉庫的clone版本Demo1和Demo2.
下面我創(chuàng)建一個fileA文件并提交到遠(yuǎn)程分支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
接下來進(jìn)入Demo2倉庫鲫竞,創(chuàng)建一個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到遠(yuǎn)程master分支上面會出現(xiàn)辐怕,文章開始所描述的情況
$ 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.
第一種操作,根據(jù)提示進(jìn)行pull
$ git pull origin master
出現(xiàn)了一個提示
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.
上面的意思是贡茅,這里進(jìn)行了一個merge遠(yuǎn)程分支master的操作秘蛇,并且是作為一次commit, 當(dāng)然你可以刪除這個Message忽略這次merge.(如果忽略這次merge其做,需要自己手動進(jìn)行merge, 待會兒我會補(bǔ)充這種情況如何處理顶考,下面先看不刪除Message的情況)
接著我們進(jìn)行再進(jìn)行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”的提交記錄妖泄,其實我本意并不希望出現(xiàn)這個提交記錄驹沿,我只希望有一條“add fileB from Demo2”的提交記錄,在剛才pull的過程中蹈胡,我拉下來了遠(yuǎn)程倉庫的fileA文件渊季,這是一個merge的過程朋蔫,在git中merge是一個commit的操作,切記(這點和SVN不同)却汉,也許有同學(xué)會問到驯妄,那我如果刪除前面提到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是在暫存區(qū),還沒有commit, 看來是逃不過這條commit message的翩伪。
總結(jié):pull這種方式會存在一個merge的過程微猖,這個merge過程是會當(dāng)成一個commit提交的,這樣會造成一個結(jié)果是:我把fileA merge過來了并提交了缘屹,那么log中將會出現(xiàn)一個 merge的commit里面包含增加fileA文件凛剥,那么pull下來的log記錄將會和“add fileA from Demo1” 中提交fileA的這條記錄有沖突,試想一下轻姿,目前3個同事協(xié)同開發(fā)犁珠,同事A, 創(chuàng)建一個文件A并提交,同事B, 創(chuàng)建文件B并提交(這個時候也要進(jìn)行同步,但是他用的rebase, 不會有多條commit記錄)互亮,重點看同事C , 創(chuàng)建文件C并提交盲憎,他進(jìn)行了pull操作,然后merge了文件A和文件B, 這是兩條提交記錄胳挎,一條是添加文件C饼疙,另外一條是文件A和文件B的一條merge commit, 這個時候提交記錄看上去就很奇怪。
- 一是同事A和同事B的內(nèi)容重復(fù)
-
二是你明明只想提交一個文件C慕爬,卻順帶提交了文件A和文件B
這也是在這種情況下建議用rebase的原因.
第二種操作窑眯,直接進(jìn)行merge
切換到Demo1,編輯fileA
$ vim fileA
添加一行
Demo1 修改fileA
然后往遠(yuǎn)程分支上面提交
$ 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.
這個時候又不同步了医窿,會叫你進(jìn)行pull的情況磅甩,這個時候我們選擇去merge遠(yuǎn)程分支
先執(zhí)行g(shù)it fetch命令(fetch是獲取遠(yuǎn)程倉庫所有信息,但是不會merge到本地倉庫姥卢,這是它和pull的區(qū)別卷要,pull是會進(jìn)行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
再執(zhí)行
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.
同樣會出現(xiàn)之前進(jìn)行pull操作的情況,但這個時候它默認(rèn)的message不是“Merge branch 'master' of gitee.com:micaixiaoduanku/Demo”独榴,看出區(qū)別了嗎僧叉?一個pull的message是merge遠(yuǎn)程的分支,而fetch后再merge的message是merge的origin/master遠(yuǎn)程跟蹤, 它實質(zhì)上是一種本地merge(本地分支和本地分支進(jìn)行merge, pull是本地分支和遠(yuǎn)程分支進(jìn)行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記錄.
最后再進(jìn)行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
總結(jié): 這種方式和pull很像棺榔,區(qū)別就是一個遠(yuǎn)程直接merge,一個是先fetch再進(jìn)行本地merge. 同樣它也會產(chǎn)生一個merge操作后commit日志瓶堕,這點是對于有提交記錄潔癖的人不太妥當(dāng).
第三種操作,進(jìn)行ReBase
什么是rebase?http://gitbook.liuhui998.com/4_2.html
再切換回Demo2症歇,修改fileA文件郎笆,在第一行寫“Demo2 修改fileA”谭梗,然后提交到遠(yuǎn)程分支.
$ 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.
這個時候先進(jìn)行一次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出現(xiàn)了沖突,我們先去解決沖突
<<<<<<< 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狀態(tài)宛蚓,接下來要做的是激捏,解決沖突后執(zhí)行一個"git rebase --continue",好凄吏,我們先解決一下沖突缩幸,修改成如下
Demo1 修改fileA
Demo2 修改fileA
然后執(zhí)行
$ 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了表谊。
總結(jié): 在解決本地分支和遠(yuǎn)程分支代碼不同步的時候使用rebase的優(yōu)勢顯而易見,它既可以完成代碼的merge工作盖喷,同時可以不出現(xiàn)merge commit log記錄爆办,從而保證提交記錄的整潔。所以多人協(xié)同在同一條分支下面進(jìn)行開發(fā)的情況下课梳,出現(xiàn)分支代碼不同步的情況下距辆,一定要使用rebase進(jìn)行的沖突處理.