git push
通常對於一個本地的新建分支,例如git checkout -b develop
, 在develop分支commit了代碼之後,如果直接執行git
push
命令,develop分支將不會被push到遠程倉庫(但此時git push
操作有可能會推送一些代碼到遠程倉庫,這取決於我們本地git
config配置中的push.default
默認行爲,下文將會逐一詳解)。
因此我們至少需要顯式指定將要推送的分支名,例如git push origin develop
,才能將本地新分支推送到遠程倉庫。
當我們通過顯式指定分支名進行初次push操作後,本地有了新的commit,此時執行git push
命令會有什麼效果呢?
如果你未曾改動過git config中的push.default
屬性,根據我們使用的git不同版本(Git 2.0之前或之後),git
push
通常會有兩種截然不同的行爲:
- develop分支中本地新增的commit被push到遠程倉庫
- push失敗,並收到git如下的警告
fatal: The current branch new has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin develop
爲什麼git版本不同會有兩種不同的push行爲?
因爲在git的全局配置中,有一個push.default屬性,其決定了git
push
操作的默認行爲。在Git 2.0之前,這個屬性的默認被設爲'matching',2.0之後則被更改爲了'simple'。
我們可以通過git version
確定當前的git版本(如果小於2.0,更新是個更好的選擇),通過git
config --global push.default 'option'
改變push.default的默認行爲(或者也可直接編輯~/.gitconfig文件)。
push.default 有以下幾個可選值:
nothing, current, upstream, simple, matching
其用途分別爲:
-
nothing - push操作無效,除非顯式指定遠程分支,例如
git push origin develop
(我覺得。。。可以給那些不願學git的同事配上此項)。 -
current - push當前分支到遠程同名分支,如果遠程同名分支不存在則自動創建同名分支。
-
upstream - push當前分支到它的upstream分支上(這一項其實用於經常從本地分支push/pull到同一遠程倉庫的情景,這種模式叫做central workflow)。
-
simple - simple和upstream是相似的,只有一點不同,simple必須保證本地分支和它的遠程
upstream分支同名,否則會拒絕push操作。 -
matching - push所有本地和遠程兩端都存在的同名分支。
因此如果我們使用了git2.0之前的版本,push.default = matching,git push後則會推送當前分支代碼到遠程分支,而2.0之後,push.default = simple,如果沒有指定當前分支的upstream分支,就會收到上文的fatal提示。
upstream & downstream
說到這裏,需要解釋一下git中的upstream到底是什麼:
git中存在upstream和downstream,簡言之,當我們把倉庫A中某分支x的代碼push到倉庫B分支y,此時倉庫B的這個分支y就叫做A中x分支的upstream,而x則被稱作y的downstream,這是一個相對關係,每一個本地分支都相對地可以有一個遠程的upstream分支(注意這個upstream分支可以不同名,但通常我們都會使用同名分支作爲upstream)。
初次提交本地分支,例如git push origin develop
操作,並不會定義當前本地分支的upstream分支,我們可以通過git
push --set-upstream origin develop
,關聯本地develop分支的upstream分支,另一個更爲簡潔的方式是初次push時,加入-u參數,例如git
push -u origin develop
,這個操作在push的同時會指定當前分支的upstream。
注意push.default = current可以在遠程同名分支不存在的情況下自動創建同名分支,有些時候這也是個極其方便的模式,比如初次push你可以直接輸入 git push 而不必顯示指定遠程分支。
git pull
弄清楚git push
的默認行爲後,再來看看git
pull
。
當我們未指定當前分支的upstream時,通常git pull
操作會得到如下的提示:
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> new1
git pull
的默認行爲和git
push
完全不同。當我們執行git pull
的時候,實際上是做了git
fetch + git merge
操作,fetch操作將會更新本地倉庫的remote tracking,也就是refs/remotes中的代碼,並不會對refs/heads中本地當前的代碼造成影響。
當我們進行pull的第二個行爲merge時,對git來說,如果我們沒有設定當前分支的upstream,它並不知道我們要合併哪個分支到當前分支,所以我們需要通過下面的代碼指定當前分支的upstream:
git branch --set-upstream-to=origin/<branch> develop
// 或者git push --set-upstream origin develop
實際上,如果我們沒有指定upstream,git在merge時會訪問git config中當前分支(develop)merge的默認配置,我們可以通過配置下面的內容指定某個分支的默認merge操作
[branch "develop"]
remote = origin
merge = refs/heads/develop // [1]爲什麼不是refs/remotes/develop?
或者通過command-line直接設置:
git config branch.develop.merge refs/heads/develop
這樣當我們在develop分支git pull時,如果沒有指定upstream分支,git將根據我們的config文件去merge origin/develop
;如果指定了upstream分支,則會忽略config中的merge默認配置。
以上參考原文:https://segmentfault.com/a/1190000002783245
最近使用git pull的時候多次碰見下面的情況:
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> release
其實,輸出的提示信息說的還是比較明白的。
使用git在本地新建一個分支後,需要做遠程分支關聯。如果沒有關聯,git會在下面的操作中提示你顯示的添加關聯。
關聯目的是在執行git pull, git push操作時就不需要指定對應的遠程分支,你只要沒有顯示指定,git pull的時候,就會提示你。
解決方法就是按照提示添加一下:
git branch --set-upstream-to=origin/remote_branch your_branch
其中,origin/remote_branch是你本地分支對應的遠程分支;your_branch是你當前的本地分支。