Git中的push和pull的默認行爲

在討論 push 和 pull 的默認行爲前咱們須要先了解 upstream、downstream 和 FETCH_HEAD 的概念。git

upstream && downstream

通俗來講,當本地倉庫 R 的某分支 x 的代碼 push 到遠程倉庫 R'的 x'分支時,把 x'分支稱爲 x 分支的 upstream,相對地把 x 分支稱爲 x'分支的 downstream。R 和 R'以及 x 和 x'能夠不一樣名,但一般咱們都設置爲同名(默認同名)。經過 upstream 和 downstream 就創建起了本地分支和遠程分支間的映射關係。如下是關於 track 關係的經常使用命令:github

  • 查詢 upstream 和 downstream 的映射關係bash

    git branch -vvcat .git/configfetch

    $ git branch -vv
    =>  dev    32cf90b [origin/dev] e23rw
        master 9b04659 [origin/master] dadfa
    
    $ cat .git/config
    => [branch "master"]
            remote = origin
            merge = refs/heads/master
        [branch "dev"]
            remote = origin
            merge = refs/heads/dev
    複製代碼
  • 創建當前分支的 upstreamspa

    git branch -u [repository-name/branch-name]code

    $ git branch -u origin/dev
    =>  Branch 'dev' set up to track remote branch 'dev' from 'origin'.
    複製代碼
  • 取消其餘分支的 upstreamrem

    git branch --unset-upstream [branch-name]it

    省略分支名則表示取消當前分支的 upstream。io

    //取消dev分支的upstream
    $ git branch --unset-upstream dev
    複製代碼

FETCH_HEAD

FETCH_HEAD 是一個短時間引用,表示剛剛從遠程獲取的分支的最新 commit。每執行一次 fetch 操做都會更新一次 FETCH_HEAD 列表,這個列表存在於.git/FETCH_HEAD 文件中,它的每一行對應一個分支的最新 commit,第一行表示當前分支的最新 commit。 在 master 分支下執行 git fetch,而後查看.git/FETCH_HEAD 文件,輸出以下:ast

9b04659a6105b139fad28018ee0f8c777379134a	branch 'master' of https://github.com/fengyueran/test
91edbb325972ffb8e924e664d61aa79054967e12	not-for-merge	branch 'dev' of https://github.com/fengyueran/test
32cf90b6fdad208260acde62fa24e72653895758	not-for-merge	branch 'dev1' of https://github.com/fengyueran/test
32cf90b6fdad208260acde62fa24e72653895758	not-for-merge	branch 'dev2' of https://github.com/fengyueran/test
複製代碼

能夠看到,直接 git fetch 會獲取全部分支的最新 commit,第一行爲 master 分支,即當前分支。此時執行 git fetch origin master,而後查看.git/FETCH_HEAD 文件,輸出以下:

9b04659a6105b139fad28018ee0f8c777379134a		branch 'master' of https://github.com/fengyueran/test
複製代碼

能夠看到只獲取了指定分支 master 的最新 commit。

push

推送到遠程分支命令:

$ git push [remote-repository-name] [branch-name]

例: 將代碼推送到遠程倉庫pb的dev分支
$ git push pb dev
複製代碼

當咱們不顯示指定倉庫名和分支名而直接用 git push 會是什麼效果呢? 對於 origin 倉庫的 master 分支,是能夠直接推送的,以下:

$ git push
=> Counting objects: 3, done.
   Writing objects: 100% (3/3), 201 bytes | 201.00 KiB/s, done.
   Total 3 (delta 0), reused 0 (delta 0)
   To https://github.com/fengyueran/test.git
   * [new branch]      master -> master
複製代碼

之因此可以直接推送是由於在 clone 的時候會自動建立 master 分支來跟蹤 origin/master。

對於非 origin 倉庫非 master 分支 git push 會是怎樣呢? 以下,切換到 dev 分支而後 git push

$ git checkout -b dev
$ git push
=> fatal: The current branch dev has no upstream branch.
   To push the current branch and set the remote as upstream, use

   git push --set-upstream origin dev
複製代碼

提示沒有 upstream 的分支,也就說本地的 dev 分支 push 時不知道推送到遠程的哪一個分支,也就無法推送。但這取決於具體的 git 配置,在 Git2.0 以前,直接 git push,若是沒有 upstream 就以當前分支名做爲 upstream。咱們能夠經過配置 push.default 來改變這種行爲,命令以下:

$ git config push.default [option]
複製代碼

push.default 選項

push.default 有幾個可選值: nothing, current, upstream, simple, matching

  • nothing

    什麼都不推送除非顯示地指定遠程分支。

  • current

    推送當前分支到遠程同名分支,若是遠程不存在,則建立同名分支。

    $ git config push.default current
    $ git push
    => Total 0 (delta 0), reused 0 (delta 0)
       remote:
       remote: Create a pull request for 'dev' on GitHub by visiting:
       remote:      https://github.com/fengyueran/test/pull/new/dev
       remote:
       To https://github.com/fengyueran/test.git
       * [new branch]      dev -> dev
    複製代碼
  • upstream

    推送當前分支到 upstream 分支上,所以必須有 upstream 分支,這種模式一般用於從一個倉庫獲取代碼的情景。

  • simple

    和 upstream 相似,不一樣點在於,必須保證本地分支與 upstream 分支同名,不然不能 push。

  • matching

    推送全部本地和遠程兩端都存在的同名分支。

在 Git2.0 以前 push.default 默認值爲 matching,2.0 以後默認值爲 simple,沒有 upstream 不能被推送。

pull

拉取遠程分支命令:

$ git pull [remote-repository-name] [branch-name]

例: 拉取遠程倉庫pb的dev分支
$ git pull pb dev
複製代碼

當咱們不顯示指定倉庫名和分支名而直接用 git pull 會是什麼效果呢?

事實上 git pull = git fetch + git merge FETCH_HEAD,直接 git pull 時會首先執行 git fetch origin 獲取 origin 倉庫全部分支,而後執行 git merge FETCH_HEAD 將 FETCH_HEAD(遠程某個分支的最新 commit) 合併到當前分支。 若是是 git pull --rebase 第二步則執行 rebase 操做,即 git rebase FETCH_HEAD。

以下: git pull pb dev 至關於分兩步執行

  • 將 pull 替換爲 fetch 執行命令 git fetch pb dev
  • git merge FETCH_HEAD

第二步 merge 時會訪問 git 的默認配置。

// cat .git/config
[branch "master"]
	remote = origin
	merge = refs/heads/master
複製代碼

能夠看到 master 分支的 upstream 爲遠程的 master 分支,所以在 pull 合併時會合並遠程的 master 分支,這裏的 refs/heads/master 指的是遠程倉庫的 master 分支。固然咱們能夠修改這個配置,從新創建 upstream 或直接修改配置。 這裏直接經過如下命令修改配置

git config branch.master.merge refs/heads/dev
複製代碼

此時,再查看配置

[branch "master"]
	remote = origin
	merge = refs/heads/dev
複製代碼

merge 的值變成了 refs/heads/dev,也就是說在 master 分支運行 pull 再 merge 的時候會 merge 遠程倉庫的 dev 分支而不是 master 分支。

相關文章
相關標籤/搜索