在多人使用同一個遠程分支合做開發的時候,極可能出現 push 代碼的時候出現如下問題:git
$ git push origin master
# 結果以下
To github.com:hello/demo.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:hello/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.
複製代碼
很明顯此時遠程分支有新的 commit 未同步到本地,沒法推送。正常狀況下咱們會執行如下操做:github
$ git pull origin master
# 結果以下
remote: Counting objects: 2, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (2/2), done.
From github.com:hello/demo
3824da0..f318a05 master -> origin/master
Merge made by the 'recursive' strategy.
one.md | 2 ++
1 file changed, 2 insertions(+)
$ git push origin master
# 結果以下
Enumerating objects: 10, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 1.24 KiB | 1.24 MiB/s, done.
Total 8 (delta 5), reused 0 (delta 0)
To github.com:hello/demo.git
f318a05..1aefef1 master -> master
複製代碼
確實 push 成功了,可是此時用 git log
查看如下提交記錄:gitlab
$ git log
# 結果以下
commit 1aefef1a2bedbd3ebd82db8dcf802011a35a9888 (HEAD -> master, origin/master, origin/HEAD)
Merge: 24cfa5c f318a05
Author: hello <hello@qq.com>
Date: Tue Jul 23 09:53:47 2019 +0800
Merge branch 'master' of github.com:hello/demo
commit 24cfa5c3ad271e85ff0e64793bf2bcc9d700c233
Author: hello <hello@qq.com>
Date: Tue Jul 23 09:50:06 2019 +0800
feat: 新功能提交
commit f318a05b1a4cbc0a6cf8d7dc7d3fb99cbafb0363
Author: world <world@qq.com>
Date: Tue Jul 23 09:48:20 2019 +0800
feat: 其餘功能提交
...
複製代碼
你會發現多出了一條 merge commit,這個 commit 就是在執行 git pull origin master
的時候自動生成的。若是多人屢次如此操做,那麼提交記錄就會出現不少條這種自從生成的 merge commit,很是難看。fetch
要解決以上問題,再也不出現自動生成的 merge commit,那麼只要在執行 git pull origin master
的時候帶上 --rebase
便可:ui
$ git pull --rebase origin master
$ git push origin master
複製代碼
如今經過一個示例項目來示範以上命令的用法。項目(demo)的結構以下:this
# 在 demo 目錄下執行如下命令
$ ls
# 結果以下
one.md two.md
$ cat one.md
# 結果以下
hello one
$ cat two.md
#結果以下
hello two
複製代碼
A、B兩位開發同窗使用一個遠程分支(master)合做開發。A同窗修改了 one.md
文件,提交了一個 commit 而且已經推送到遠程分支 master:spa
$ cat one.md
# 結果以下
hello one
new feature for one
$ git push origin master
# 結果以下
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 1.24 KiB | 1.24 MiB/s, done.
Total 4 (delta 3), reused 0 (delta 0)
To github.com:hello/demo.git
f318a05..1aefef1 master -> master
複製代碼
此時B同窗不知情,也並未將遠程分支的更新拉到本地。B同窗修改了 two.md
文件,也提交了一個 commit 並嘗試推送到遠程分支 master:版本控制
$ cat two.md
# 結果以下
hello two
new feature for two
$ git push origin master
# 結果以下
To github.com:hello/demo.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:hello/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.
複製代碼
發現報錯,沒法推送。此時執行如下命令:code
$ git pull --rebase
$ git push origin master
複製代碼
便可成功推送。three
git pull --rebase
的時候必須保持本地目錄乾淨。即:不能存在狀態爲 modified
的文件。(存在Untracked files
是不要緊的)rebase
,也能夠放棄本次 rebase
git pull --rebase
的時候必須保持本地目錄乾淨modified
狀態的文件本地有受版本控制的文件改動的時候,執行以上命令:
$ git pull --rebase
# 結果以下
error: cannot pull with rebase: You have unstaged changes.
error: please commit or stash them.
複製代碼
會出現以上報錯,沒法操做。
此時查看如下文件狀態:
$ git status
# 結果以下
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: two.md
no changes added to commit (use "git add" and/or "git commit -a")
複製代碼
就是由於本地有文件改動還沒有提交形成的。此時有兩種作法:
commit
)一下git stash
作了以上一種操做以後再嘗試 git pull --rebase
,不會再報錯。
若是作了 git stash
操做,此時能夠經過 git stash pop
回到以前的工做狀態。
Untracked files
查看本地文件狀態:
$ git status
# 結果以下
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
Untracked files:
(use "git add <file>..." to include in what will be committed)
three.md
no changes added to commit (use "git add" and/or "git commit -a")
複製代碼
若是是以上這種狀況,直接執行 git pull --rebase
是不會有問題的。
rebase
,也能夠放棄本次 rebase
在上面的示例項目中,若是 A、B 同窗修改了同一個文件。那麼頗有可能會出現衝突,當 B 同窗來執行命令的時候會出現以下情況:
$ git pull --rebase
# 結果以下
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From gitlab.lrts.me:fed/gitlab-merge
93a1a93..960b5fc master -> origin/master
First, rewinding head to replay your work on top of it...
Applying: feat: 其餘功能提交
Using index info to reconstruct a base tree...
M one.md
Falling back to patching base and 3-way merge...
Auto-merging one.md
CONFLICT (content): Merge conflict in one.md
error: Failed to merge in the changes.
Patch failed at 0001 feat:其餘功能提交
hint: Use 'git am --show-current-patch' to see the failed patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
複製代碼
這種狀況下,能夠手動打開 one.md
文件解決衝突,而後再執行:
$ git add one.md
$ git rebase --continue
複製代碼
解決問題。
也能夠用 git rebase --abort
放棄本次 rebase 操做。
多人基於同一個遠程分支開發的時候,若是想要順利 push 又不自動生成 merge commit,建議在每次提交都按照以下順序操做:
$ git stash
$ git pull --rebase
$ git push
$ git stash pop
複製代碼