【问题标题】:Understanding .git/config's 'remote' and 'branch' sections了解 .git/config 的“远程”和“分支”部分
【发布时间】:2017-09-05 04:25:55
【问题描述】:

这是我的.git/config 文件的remotebranch 部分的内容。

[remote "origin"]  
    url = https://EvanAad@bitbucket.org/EvanAad/bitbucketstationlocations.git  
    fetch = +refs/heads/*:refs/remotes/origin/*  
[branch "master"]  
    remote = origin  
    merge = refs/heads/master

这些部分内容的含义和目的是什么,尤其是fetchmerge 子部分? Git 如何使用这些信息来指导其操作?

【问题讨论】:

  • 您可以在文档中阅读所有这些内容...git-scm.com/docs/git-config
  • @Stony:我不懂文档。我希望得到更清楚的解释。
  • @Rene:在我看来,git-config 上的文档说明了您可以使用 git-config 列出和操作 git config 文件的所有方法——但没有关于各种内容在参考中的原因到 git 行为。

标签: git git-merge git-remote git-config git-fetch


【解决方案1】:

TL;DR 总结

总的来说,我们对两三件事感兴趣:

  1. 如果您在没有其他参数的情况下运行 git fetch,会发生什么?
  2. 如果您在没有其他参数的情况下运行 git mergegit rebase,会发生什么?
  3. 如果您在没有其他参数的情况下运行 git pull,会发生什么?

对问题 #1 的简短回答是:Git 选择您的一个遥控器 进行获取,然后从该遥控器获取。远程 Git 选择来自 [branch] 部分下的 remote = <em>name</em> 设置。如果没有这样的设置,Git 使用origin

问题 #2 的答案是:Git 选择一些要使用的名称,就像您运行过 git merge <em>name</em>git rebase <em>name</em> 一样。 name 基于 merge = <em>ref</em> 设置在[branch] 部分下,但其工作方式有些模糊:例如,如果同一部分说、remote = originbranch = refs/heads/master,Git 选择使用的名称不是master,而是origin/master。如果它显示remote = originbranch = develop,则Git 选择的名称是origin/develop,依此类推。

(虽然这看起来很简单,但 Git 内部的实际映射相当棘手:例如,如果该部分显示 remote = .branch = master,则名称是 master,而不是 ./master。如果您设置不寻常的 fetch refspecs,甚至可能发生更奇怪的事情。这个答案根本不包括最后一种情况。)

问题#3的答案在某些方面是最简单的:git pull首先运行git fetch,然后——如果成功的话——其他两个命令之一,git mergegit rebase,所以你真的只需要看问题 1 和 2。

我认为每个branch 部分下的merge 条目是最不明显的。 Git 文档使它有点晦涩难懂。让我们先介绍其他的。

[remote "..."] 部分下的设置

有许多可能的设置。通常,您不必直接使用git config 设置它们中的任何一个——几乎所有它们都有包装器命令以更“用户友好”的方式设置它们。这包括您在此处看到的两个设置。也很少想要改变这些。

每个命名远程的remote 部分(例如origin)列出了git fetch 的URL(以及可选的git push 的单独推送URL,以及其他remote.* 配置项为described in the git config documentation) .它还有一个或多个 fetch 行,它们为来自该远程的 git fetch 提供默认 refspec 参数。

也就是说,如果你运行:

git fetch origin

Git 将查找 remote.origin.url 以查看连接位置,然后在那里连接,然后根据所有 remote.origin.fetch 条目检索引用。您在此处看到的默认值:

+refs/heads/*:refs/remotes/origin/*

告诉 Git 从远程复制所有个分支1,将它们重命名为origin/-前缀远程跟踪分支2你自己的存储库,所以:

git fetch origin

基本上获取所有内容。 (前面的+表示无论远程跟踪分支更新是否是快进操作,Git都应该这样做。也就是说,它就像使用--force,但不必指定--force。)

另一方面,如果你运行:

git fetch origin a:b c:d

Git 将完全忽略所有fetch = 行,仅从远程检索引用ac,将它们写入您的存储库中的引用bd。 (而且由于这既没有+ 也没有--force,所以这些都不会被强制更新——尽管在大多数情况下这并没有什么区别。)


1, 2reference 是一个通用术语,涵盖分支 标签(以及更多内容)。像master 这样的分支名称只是以refs/heads/ 开头的引用的简写。像origin/master 这样的远程跟踪分支名称只是以refs/remotes/ 开头的引用的简写。请注意,origin/ 部分来自 fetch = 行,但要使所有这些按预期方式工作,该行必须与方括号中的遥控器名称匹配。


[branch "..."] 部分下的设置

有许多可能的设置。通常,您不必直接使用git config 设置它们中的任何一个——几乎所有它们都有包装器命令以更“用户友好”的方式设置它们。这包括您在此处看到的两个设置。使用我们稍后会看到的命令来更改其中一个或两个并不少见。

remote 部分本身非常清楚:这意味着如果您在分支 master 上并运行 git fetch 根本没有提供远程名称,Git 应该从名为 @987654389 的远程获取@。

merge 部分是棘手的部分。它列出了一个分支的名称​​在遥控器上可以看到。请注意,当我们运行 git fetch origin 时,我们告诉我们的 Git 调用另一个 Git,找到 另一个 Git 的 master,并将其复制到我们的存储库中,但将其命名为 origin/master。然而......这merge 行说merge = refs/heads/master。不应该说:merge = refs/remotes/origin/master吗?

它可能应该——但这种设置一开始就早于遥控器的发明。所以它没有;相反,它会列出参考的全名它出现在遥控器上

如果您运行 git mergegit rebase 而不提供要合并或重新设置的分支名称,则会使用此设置。例如,Git 通过fetch = 行为远程提供的映射运行名称,以确定它应该与origin/master 合并。

git pull 便捷命令也使用此设置,这与运行 git fetch 后运行 git merge 的效果相同3

您可能希望更改其中一项或两项。例如,如果您创建一个新的本地分支feature/tall,它可能根本没有branch.feature/tall.remotebranch.feature/tall.merge 设置。

由于你刚刚创建了这个分支,所以没有origin/feature/tallorigin 的 Git 还没有 feature/tall,所以你没有它的副本。

然后你 git push origin feature/tall:feature/tall 让你的 Git 调用 origin 的 Git 并让他们的 Git 创建那个分支,这样你现在有 @987654412 @。您可能希望您的 Git 记住这一点。

可以运行两个git config 命令,但是,您可以运行一个更高级别的包装器命令:

git branch --set-upstream-to=origin/feature/tall feature/tall

这告诉你的 Git 将 branch.feature/tall.remote 设置为 origin,并将 branch.feature/tall.merge 设置为 refs/heads/feature/tall(这是 origin 上的名称)。

您可以使用git push -u 组合git pushgit branch --set-upstream-to 步骤,这样会更好,但这里的重点仍然存在:您使用包装器同时设置两个值,因为只设置一个值并没有那么有用。4

特殊的远程名称. 表示此存储库(相对于某些远程存储库)。如果[branch "xyzzy"] 部分显示remote = .branch = refs/heads/whatever,则分支xyzzylocal 分支whatever 作为其上游,而不是将origin/whatever 作为其上游。


3这故意掩盖了很多繁琐的细节。

4只设置remote 部分确实会影响未来的git push,但git mergegit rebase 将无法进行远程操作- 跟踪没有两个条目的分支映射。

【讨论】:

  • branch 部分下的设置对fetch 没有影响;仅在 mergepull 上,对吗?
  • 对。 (而且它们只影响git pull,因为它运行git merge,或者如果您将其配置为git rebase,尽管配置git pull to 运行git rebase 的东西是另一个@ 987654443@-section 条目!)
  • @torek 但是您写道:“remote 部分本身就很清楚了:[...] Git 应该从名为 origin 的远程获取”...如果你能把它弄清楚就好了。
  • @philipp2100:我猜对了:这里有什么困惑?如果我在此处包含实际文本 remote = origin 会有帮助吗?
  • 不,令人困惑的部分是您描述remote,它位于branch 部分下,以某种方式影响git fetch,但在cmets 中你们都同意下面的设置branch 部分不会影响git fetch
【解决方案2】:

它被称为 refspec。 它是 git 用来与远程服务器“对话”并将本地分支映射到远程分支的机制。

参考规范

refspec 将本地存储库中的分支映射到远程存储库中的分支。
这使得使用本地 Git 命令管理远程分支和配置一些高级 git push 和 git fetch 行为成为可能。

一个 refspec 被指定为[+]&lt;src&gt;:&lt;dst&gt;&lt;src&gt; 参数是本地仓库中的源分支,&lt;dst&gt; 参数是远程仓库中的目标分支。
可选的+ 符号用于强制远程仓库执行非快进更新

Refspecs 可以与 git push 命令一起使用,为远程分支提供不同的名称。例如,以下命令将 master 分支推送到 origin 远程 repo,就像普通的 git push 一样,但它使用 qa-master 作为 origin repo 中分支的名称。这对于需要将自己的分支推送到远程仓库的 QA 团队很有用。

git push origin master:refs/heads/qa-master

通过在 Git 配置文件中添加几行,您可以使用 refspecs 来改变 git fetch 的行为。

默认情况下,git fetch 获取远程存储库中的所有分支。原因是.git/config 文件的以下部分:

[remote "origin"]
    url = https://git@github.com:mary/example-repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*

fetch 行告诉 git fetch 从原始存储库下载所有分支
但是,有些工作流程并不需要全部。例如,许多持续集成工作流只关心主分支。要仅获取 master 分支,请更改 fetch 行以匹配以下内容:

[remote "origin"]
    url = https://git@github.com:mary/example-repo.git
    fetch = +refs/heads/master:refs/remotes/origin/master

你也可以用类似的方式配置 git push。例如,如果您想始终将 master 分支推送到源远程中的 qa-master(如我们上面所做的那样),您可以将配置文件更改为:

[remote "origin"]
    url = https://git@github.com:mary/example-repo.git
    fetch = +refs/heads/master:refs/remotes/origin/master
    push = refs/heads/master:refs/heads/qa-master

Refspecs 让您可以完全控制各种 Git 命令如何在存储库之间传输分支

它们让你重命名删除分支从本地存储库fetch/push 到具有不同名称的分支,并将 git push 和 git fetch 配置为仅使用你想要的分支。

【讨论】:

  • 假设fetch 参考规范是fetch = +refs/heads/*:refs/remotes/origin/*。如果远程仓库有一个名为mybranch的分支,而我的本地仓库没有同名的远程跟踪分支,是否会创建同名的远程跟踪分支,还是会报错?
  • 如果它不存在,它将创建新分支,但如果您使用的是 git v2.X 并且您没有更改默认的 fetch refspec,您将只能 push到同一个分支。
  • 如果相反,我的本地存储库有一个名为 origin/mybranch 的远程跟踪分支,它是由以前的 fetch 创建的,但同时分支 mybranch 已被删除在遥控器上。鉴于我之前评论中提到的 refspec,fetch 之后会发生什么?本地的origin/mybranch会被删除吗?
  • 如果一个分支被删除,你可以用git fetch --all --prune更新你的本地仓库,它将删除本地未删除的分支。如果您尝试将已删除的分支推送到远程,它将再次在远程创建
  • @CodeWizard 能否请您格式化这一行 - fetch = +refs/heads/master:refs/remotes/origin/master?我不能,因为它没有足够的字符。
猜你喜欢
  • 1970-01-01
  • 2012-10-22
  • 2016-04-12
  • 2020-04-04
  • 1970-01-01
  • 2012-03-21
  • 2013-11-21
  • 2014-03-17
相关资源
最近更新 更多