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 分支。

相关文章
相关标签/搜索