Git中的push和pull的默认行为

栏目: 编程工具 · 发布时间: 5年前

内容简介:在讨论 push 和 pull 的默认行为前我们需要先了解 upstream、downstream 和 FETCH_HEAD 的概念。通俗来说,当本地仓库 R 的某分支 x 的代码 push 到远程仓库 R'的 x'分支时,把 x'分支称为 x 分支的 upstream,相对地把 x 分支称为 x'分支的 downstream。R 和 R'以及 x 和 x'可以不同名,但通常我们都设置为同名(默认同名)。通过 upstream 和 downstream 就建立起了本地分支和远程分支间的映射关系。以下是关于

在讨论 push 和 pull 的默认行为前我们需要先了解 upstream、downstream 和 FETCH_HEAD 的概念。

upstream && downstream

通俗来说,当本地仓库 R 的某分支 x 的代码 push 到远程仓库 R'的 x'分支时,把 x'分支称为 x 分支的 upstream,相对地把 x 分支称为 x'分支的 downstream。R 和 R'以及 x 和 x'可以不同名,但通常我们都设置为同名(默认同名)。通过 upstream 和 downstream 就建立起了本地分支和远程分支间的映射关系。以下是关于 track 关系的常用命令:

  • 查询 upstream 和 downstream 的映射关系

    git branch -vvcat .git/config

    $ 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
    复制代码
  • 建立当前分支的 upstream

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

    $ git branch -u origin/dev
    =>  Branch 'dev' set up to track remote branch 'dev' from 'origin'.
    复制代码
  • 取消其他分支的 upstream

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

    省略分支名则表示取消当前分支的 upstream。

    //取消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 文件,输出如下:

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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Design for Hackers

Design for Hackers

David Kadavy / Wiley / 2011-10-18 / USD 39.99

Discover the techniques behind beautiful design?by deconstructing designs to understand them The term ?hacker? has been redefined to consist of anyone who has an insatiable curiosity as to how thin......一起来看看 《Design for Hackers》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换