Git 可以跟踪祖先分支以及它自己的分支吗?

Can Git track an ancestor branch as well as its own branch?

抱歉,如果这是一个菜鸟问题,但我已经搜索了一个多小时,但无法得到明确的答案。

我想做的是:

在这一点上,我希望能够 git pull 并让 git 看到 feature 有变化并拉取它 (fetch/merge)进入我当地的 feature_my_tweak 分支机构。有没有办法自动做到这一点?或者我是否必须手动执行 git merge feature 才能将所有更改从该分支获取到我的本地 feature_my_tweaks 分支?我想我认为有一种方法可以让一个分支跟踪另一个分支。

另一部分是我仍然希望能够对 feature_my_tweaks 进行本地更改并且仍然能够 git push 并且只将其推送到远程 origin/feature_my_tweak 分支并且不污染 origin/feature 分支。

有办法做到这一切吗?据我所知,似乎如果任何 branch_A 正在跟踪远程 branch_B,任何推送都会转到 branch_B,这是我不想要的。

我希望这是有道理的。

TL;DR

答案的简短版本归结为否,但没关系,不用担心,只需手动完成即可;很简单。如果你有一个特定的 b运行ch,你经常用它来做这个,写一个脚本或一个 Git 别名来做它。

手动执行此操作,对于你的 b运行ch B,你想知道 origin/feature 上是否有新内容,与你自己的 b 运行ch feature_my_tweaks 上游设置为 origin/feature_my_tweaks,只是 运行:

git rev-list --count --left-right feature_my_tweaks...origin/feature

这会打印出两个数字。左边的数字是您在 feature_my_tweaks 上的提交数,但不属于您的 origin/feature。右边的数字是 origin/feature 上不在 feature_my_tweaks.

上的提交数

如果第二个数字不为零,而你想要,你现在可以 运行 git checkout feature_my_tweaks; git rebase origin/featuregit checkout feature_my_tweaks; git merge origin/feature.

是否以及何时使用 git rebase 由您决定,但在 rebase 之后,您将需要 git push --force origin feature_my_tweaks(或 git push --force-with-lease origin feature_my_tweaks)来获得 Git在 origin 丢弃你的 git rebase 将你的提交复制到 new-and-improved 提交时丢弃的旧提交。

这里最大的问题可能是术语。 tracking 这个词对您来说意味着什么? Git 至少以三种不同的方式使用这个词,1 因此最多其中一种可以与您想到的匹配。 (可能 none 它们完全匹配,具体取决于您的想法。)

不管你使用哪个词,下面是正确的思考方式:

  • 重要的是提交。每个提交都有一个唯一的哈希 ID。每个 Git 无处不在 - 这个存储库的每个克隆 - 使用 that 哈希 ID 用于该提交。如果您有一个带有 that 哈希 ID 的提交,则它是同一个提交。如果你不这样做,你就没有那个提交。

  • Names in Git 有很多形式。每个名称都有一个哈希 ID——只有一个!

    您使用的三种形式是:

    • B运行ch 名称: masterdevelopfeaturefeature/one,等等。这些都是你的,想怎么用就怎么用。 (不过,您可能希望自己的名字与其他人的名字相匹配,至少在不同的时候是这样。)

    • 标签名称: v2.1等等。虽然你的是你的,但你的 Git 会尝试 与其他 Git 存储库共享 它们:如果你的 Git 发现他们的 v2.1 而你不这样做,你的 Git 很可能会将他们的复制到你的。

    • Remote-tracking 姓名: origin/master, origin/feature, 等等。 Git 称这些 remote-tracking b运行ch names 有些人将其缩短为 remote-tracking b运行ch,但它们不太像 b运行ch 名称。您的 Git 将这些从属于其他 Git 的 b运行ch 名称。您让 Git 调用他们的 Git 并从他们那里获得任何 新提交 。然后你的 Git 更新你的 remote-tracking 名字,使它们与他们的名字相匹配。

      remote-tracking 名称是通过将 remote 名称(在本例中为 origin)粘贴在 b运行ch 名称,用斜线将它们分开。这就是为什么你的 origin/master "tracks" 他们的 master,每次你 运行 git fetch origin.2[=78= 都会更新的原因]


    所有这些名称的作用都相似。它们都有长形式:refs/heads/mastermaster 的完整拼写,例如,refs/remotes/origin/masterorigin/master 的完整拼写。这就是 Git 知道哪个是哪种名称的方式。 Git 通常然后 缩短 显示给你的名字,去掉 b运行ch 名字的 refs/heads/ 部分,或者 refs/remotes/ remote-tracking 个名字的一部分。

请注意 git fetchgit push 的对立面非常接近。看起来这些应该是 pushpull,但由于历史事故 3 它是 pushfetch。 pull just 表示:运行 fetch,然后运行第二个Git命令,默认git merge,与当前b运行合并ch 的上游。

获取和推送非常相似,但有两个主要区别:

  1. 获取获取东西。你告诉你的 Git: 调出 Git 的 URL 你存储在名称 origin 下的 origin在这里使用)。您的 Git 调用位于 URL 的服务器,它必须作为 Git 存储库响应。该服务器然后告诉您它的 b运行ch 名称和它们的提交,并且您的 Git 检查您是否有这些提交。如果没有,您的 Git 会向他们的 Git 询问这些提交,如果您没有他们的 parent 提交,以及 parent 的 parent如果需要,等等。他们给你所有他们有的提交,你没有,你的 Git 需要完成这些。

    有得到提交,git fetch 然后更新你的 remote-tracking names 通过重命名他们的 b运行ches.

  2. 推送发送东西。和以前一样,您的 Git 通过远程名称 origin 调用另一个 Git。然后你的 Git 给他们提交,而不是从他们那里得到提交。但在这里,情况略有不同:

    • 您的 Git 提交是您正在推动的任何 b运行 的 提示提交 。 (如果您只是推送一个 b运行ch,那只是一次提交。)如果他们没有这些提交,您的 Git 必须提供这些提示提交的 parents。 (大多数提交只有一个 parent,所以这又是一个提交。)如果他们没有 那些 ,你的 Git 必须提供更多 parents,等等。通过这个过程,你的 Git 找到他们的 Git 需要的所有提交,需要有你发送的 tip 提交的完整图片:它的所有历史。

      当你取货时,他们提供了所有他们的b运行ches。不同点:你只推你指定的 b运行ches。

    • 在您的 Git 发送了您拥有的任何提交之后,他们没有,他们需要完成 b运行ch 的提示提交(es) 你在推动,你的 Git 礼貌地请求他们设置他们的 b运行ch 名称。

      当您获取时,您的 Git 设置了您的 remote-tracking 名称。您现在要求他们设置 b运行ch 名称。

总结这些要点:

  • fetch gets(所有,默认情况下,除非你限制它)从他们那里提交和 b运行ches 并将他们的 b运行ches 重命名为你的remote-tracking名字
  • push sends(一个,默认情况下)4 branch-tip 提交(及其祖先 if/as 需要) 然后要求他们设置他们的 b运行ch name(s)

可以git push要求他们设置一个与您select不同的名称] 要发送的提交。例如:

git push origin test-xyz:new-feature

发送您的 test-xyz b运行ch(及其 parents 和其他需要的祖先 if/as)的提示提交,但要求他们设置或创建他们的b运行频道名new-feature.

所以:

... it seems that if any branch_A is tracking a remote branch_B, any pushes will go to branch_B ...

这是完全错误的,至少在默认情况下是这样。 (但是 push.default 的设置 确实 实现了这一点。)

这里还有很多东西需要了解,特别是 git rev-list --left-right --count 正在做什么以及提交 "on" 或更准确地说 可访问意味着什么from—一个 b运行ch 的名字,但我有点 运行 没时间了,在这个答案中 space,在这一点上。


1特别是,文件可以 trackeduntracked,一些名称是 remote-tracking names,而带有上游集的 b运行ch 据说是 tracking 其上游。动词(现在分词形式)变成形容词,在前两种情况下修饰 namefile

2有一些方法可以 运行 有限的 git fetch 不会 更新您所有的 remote-tracking 名字。例如,使用 git pull 有时会这样做。我更喜欢将 git fetch 和其他命令分开,而不是使用 git pull fetch-then-run-another-Git-command 命令。

3抓取之后想要整合你抓取的内容是很常见的,所以一开始,git fetch是一个back-end "plumbing" 命令,并不意味着用户要 运行,然后 git pull 运行 git fetch,然后 git merge。这是在 remotes 作为一个概念存在之前,因此在 remote-tracking 名称存在之前,所以用户没有任何理由 运行 git fetch.

随着时间的推移,Git 增加了遥控器和 remote-tracking 名称,现在 pull 之间的区别 - 获取和组合 - 只是 fetch 没有组合(或在至少,不这样做 yet) 变得既有用又重要。但是 name pull 已经被用来表示 fetch and combine,因此这个特殊的历史事故。

4也就是说,这是 Git 2.0 及更高版本中的默认设置。可以改成push.default,Git 2.0以前的版本默认为matching.

当使用 matching 时,你的 Git 询问他们的 Git 关于他们的 b运行ch 名字,匹配你匹配的 b运行ch 名字,并默认从您的匹配名称推送到他们的匹配名称。

如果您将此设置更改为 upstream,您的 Git 会要求他们的 Git 根据您的 b[= 的上游设置设置他们的 b运行ch 399=]ch,这是你在问题中假设的。

现代默认设置是simple,这要求上游设置为b运行ch同名,因此如果您的上游设置为他们一方的不同名称,那么您这边的 git push 会立即失败。但是,您可以通过输入 git push origin <em>b运行ch</em> 轻松覆盖它,这意味着同样的事情作为 git 推送原点 <em>b运行ch</em>:<em>b运行ch</em>:要求他们的 Git 使用与您在 Git.

中使用的相同的 b运行ch 名称