用于指定远程跟踪分支的git语法与git pull,push,checkout等的语法

时间:2014-11-20 01:25:45

标签: git syntax

git pull命令的语法是git pull [remote] [branch](注意远程名称和分支名称之间的空格)。 e.g:

git pull origin v0

但是,对于另一个命令,语法是[remote] / [branch](这次是' /'而不是分隔[remote]和[branch]的空间):

git branch --set-upstream v0 origin/v0

这对我来说很困惑,因为&origin; v0'也是"远程跟踪分支的名称"在我的本地机器上。例如列出远程跟踪分支的命令:

git branch -r

  origin/master
* origin/v0

然而,让我更加困惑的是,列出所有本地跟踪分支和远程跟踪分支的命令使用的语法 [分支](用于本地分支)和遥控器/ [远程] / [分支]用于远程跟踪分支。 E.g:

git branch -a 

  master
* v0
  remotes/origin/master
  remotes/origin/vo

我的主要问题是我是否正确理解了这些看似模棱两可的语法约定?

第二个问题和评论是:为什么对引用远程跟踪分支的不同方式存在歧义,例如origin / master与remotes / origin / master的情况?

为什么不只是拥有' git branch -a'不提前'遥控/'? e.g:

 git branch -a 

      master
    * v0
     origin/master
    * origin/v0

对于以下功能:

git branch --set-upstream v0 origin/v0

成功:

git branch --set-upstream v0 origin v0

这样一来就知道命令参数引用了一个分支' v0'一个遥远的名字来源'而不是"远程跟踪分支"。

甚至使用详细的命名参数语法:

git branch --set-upstream OfLocalBranch:v0 ToRemoteAndBranch::origin v0

或上述命名方法的一些变体。

2 个答案:

答案 0 :(得分:0)

首先,在git pull remote branch中,branch不对应远程分支,而是对应于本地分支。使用该命令将从远程branch的{​​{1}}远程跟踪分支中提取更改(尽管该行为取决于您的设置)。然而,在那里使用remote不是一个合适的选择。

对于远程跟踪分支,git pull remote/branch是这些分支的真实名称。因此,当列出所有分支时,只需 列出全名以避免歧义,并明确分支是远程分支。但是,当使用remotes/<remote>/<branch>时,您明确地请求远程分支,因此您知道您将看到的所有分支都是远程分支(具有隐式git branch -r前缀)。所以Git会告诉你这些短名称;因为Git可以让你不精确,如果可以找出你所指的分支,就会遗漏掉部分。

指定remotes/时,Git会try the following refs until it finds one

  
      
  1. 如果<refname>存在,那就是您的意思(这通常仅适用于$GIT_DIR/<refname>HEADFETCH_HEADORIG_HEAD和{{1 }});
  2.   
  3. 否则,MERGE_HEAD如果存在;
  4.   
  5. 否则,CHERRY_PICK_HEAD如果存在;
  6.   
  7. 否则,refs/<refname>如果存在;
  8.   
  9. 否则,refs/tags/<refname>如果存在;
  10.   
  11. 否则,refs/heads/<refname>如果存在。
  12.   

该列表已经显示了引用的实际全名:

  • refs/remotes/<refname>代码
  • 分行
  • refs/remotes/<refname>/HEAD
  • refs/tags/<name>用于远程分支

所以你所做的就像只指定refs/heads/<name>一样只是Git允许你做的快捷方式,所以你不必将它指定为refs/remotes/<name>(你仍然可以)。对于遥控器,通常,非远程分支不会使用master之类的前缀,因此指定heads/master通常是您正在谈论远程分支的安全保证。


通过示例明确回答您的一个问题:*“为什么不让origin/ 预先origin/branch?”*

拥有一个存储库是完全没问题的,git branch -a返回以下输出,其中只有最后一个是实际的远程分支:

remotes/

至于使用git branch -a指定远程跟踪分支,您需要知道您指定某个远程分支。您确实在设置远程跟踪分支,这就是您需要在那里引用该远程跟踪分支的原因。

除了惯例之外,实际上没有任何东西要求远程跟踪分支被称为$ git branch -a * master origin/master remotes/origin/master 。将它们命名为git branch --set-upstream绝对是可能的,它们仍将使用remotes/<remote>/<branch>进行更新。因为重要的是存储在存储库配置文件中的远程配置。通常,这样的部分看起来像这样:

foo/bar/baz/<branch>

这实质上告诉Git在git fetch更新远程本地分支列表中找到的每个分支的远程分支。正如我上面所说,你可以改变它并将它们存储在其他地方。

答案 1 :(得分:0)

我知道这已经回答了,但我会尝试一些不同的东西。

这里的基本问题是git pull是一个非常古老的命令,是在远程跟踪分支的整个概念完整且常见之前编写的。

背景

使用git(或者实际上任何现代分布式版本控制系统)要记住的第一件事是您的存储库是您的。您的存储库中确实没有任何&#34;远程分支&#34;,只有本地的分支。那些名为&#34; remote&#34; -or,一个略好的名称,&#34;远程跟踪&#34; - 存储在你的存储库中;当有机会时,他们只是更新,以匹配你的git在某个远程存储库中看到的内容。

也就是说,remotes/origin/master是&#34;上次我打电话master时我的,你的git在origin看到的内容的副本,并问他的git他有什么在master&#34;。所以,这是您最近一次检查时最近的(或曾经)的副本。要再次检查,你只需运行git fetch origin:你的git使用它的网络电话来调用他们的git,看看他们有什么,并带来他们没有的东西。这些内容也会在您git push时更新,因为您的git也会调用他们的git来查看他们拥有的内容,并向他们提供他们没有的内容。

(自git以来大约1.8.2,情况确实如此;对于旧版本, git fetch的某些调用无法更新您的副本。令人讨厌的是,它已经由git pull脚本运行的特别调用。但如果你的git比那个更新,那么这个小皱纹就会消失,远程跟踪分支真的会尽可能地保持最新状态。 )

历史

有了这个,让我们回到git pull,以及这背后的历史。具体来说,有一个时间点甚至没有&#34;遥控器&#34;一点都不如果你是Linus Torvalds,或者和他一起工作,你就跑git fetch git://some.host.name/some/path develop,因为你知道谁在做什么,他们的主机名是什么,以及他们使用了什么分支机构。这将连接到命名主机并获取命名分支,并将所有信息转储到名为FETCH_HEAD的文件中。然后你查看FETCH_HEAD并看看他们一直在做什么,也许可以使用旧的,更原始的合并命令将它合并到你自己的存储库中。

事实证明这很常见,所以有人写了pull脚本来进行获取然后合并。并且仍然没有&#34;遥控器&#34;,所以你刚刚命名了你知道Bob用于开发的分支:你的git叫他起来,用你输入的分支名称询问他,然后你的git将他的东西从FETCH_HEAD文件中git fetch转移到你当前的分支中。

因此,作为git pull的参数给出的分支名称实际上是不是本地分支名称,几乎每个都严重违反关于git分支名称的其他规则。这些名字被交给git fetch,然后通过互联网电话(或任何传输)将它们交给被叫的git。生成的SHA-1 ID会被带到您的本地FETCH_HEAD文件中(再次带有名称)。

演进

一次&#34;遥控器&#34;发明了,远程跟踪分支的想法&#34;存储在你的本地仓库中的所有旧东西应该立即被抛弃,除非人们习惯了它,并且正在使用它并依赖于这种行为。所以git pull origin master仍然按照它的方式工作多年,但仍违反规则。

幸运的是git pull只是弄清楚了上游遥控器是什么,以及该遥控器上的分支是什么,因此运行而不使用额外参数会使用跟踪信息并做正确的事情自动。您可以在适当的远程名称下存储一次URL - 通常git会在初始克隆上为您执行此操作 - 从那时起,您永远不需要重新键入长URL。

问题

您仍然可以使用额外的参数运行git pull,因为向后兼容性实际上很重要。唉,git pull origin master develop并不代表大多数人的期望:pull脚本告诉fetch带来远程master和{{1}并将两者放入develop,然后运行FETCH_HEAD进行&#34;章鱼合并&#34;,合并两个带来的SHA -1与您当前分支的ID(不必是git merge master)。

Refspecs

值得添加的是,在某些情况下, 需要同时指定本地分支名称和远程分支名称。具体来说,如果您(本地)命名了一个分支develop,当您修复fix-bug-123分支上的错误#123时这是一件好事且明智的事情,您可能想要推动直接从那里修复到遥控器上的develop(评论将在哪里或产品的构建地点)。为此,您指定一个遥控器,然后给出一个&#34; refspec&#34;。

简而言之,refspec是 1 只是一对分支名称。要将develop推送到fix-bug-123,请执行以下操作:

develop

您的本地分支名称位于左侧,其远程分支名称位于右侧。

您可以在抓取时执行相同的操作(请记住,$ git push them fix-bug-123:develop 的反面是push不是 fetch - pull是历史记录执行pull的脚本 - 然后 - fetch!),但这里的名称是相反的。假设你有自己的merge分支,但是你已经听说琼斯先生有一些不错的东西。您希望从mrjones.com快速develop获取他的fetch分支并在您的存储库中调用feature,而不是设置正确的远程:

jones-feature

它可能更聪明来创建一个真正的遥控器,然后取出所有东西:&#34;不太明智的&#34;方法只是为了说明。在这里,他的分支名称在左边,而你的分支名在右边,因为它总是&#34; source:destination&#34;。使用fetch,源是远程的,目标是本地的;通过推送,源是本地的,目的地是远程的。

&#34;更聪明&#34;方式可以获得$ git fetch git://mrjones.com/path/to/repo.git feature:jones-feature [fetch stuff happens here] $ git log jones-feature

remotes/mrjones/feature

当您这样做时,git仍会使用提取参考规范,但它会将其隐藏在$ git remote add mrjones git://mrjones.com/path/to/repo.git $ git fetch mrjones $ git log remotes/mrjones/feature 文件的.git/config remote条目下。您可以使用mrjones

查看它们
git config get-all

$ git config get-all remote.mrjones.fetch 变体用于设置多个get-all行;默认情况下,git只创建一个提取行,但我想我应该在这里说明最复杂的情​​况。)


1 稍微过短:例如,这掩盖了标签如何工作的细节。不合格的ref-specs根据需要进行匹配,或者创建为分支。要强制某些内容成为标记,请拼写出来:例如fetch。使用refs/tags/sometag拼写的任何内容都会使git在该名称空间内工作。