TL;DR
答案的简短版本归结为不,但没关系,不用担心,只需手动操作即可;这很容易。如果您有一个经常使用的特定分支,请编写脚本或 Git 别名来执行此操作。
中等
要手动执行此操作,对于您想知道 origin/feature 上是否有新内容的分支 B 与上游设置为 origin/feature_my_tweaks 的您自己的分支 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/feature 或 git checkout feature_my_tweaks; git merge origin/feature。
是否以及何时使用git rebase 取决于您,但在变基之后,您需要git push --force origin feature_my_tweaks(或git push --force-with-lease origin feature_my_tweaks)在origin 上获取Git,以丢弃您的@ 987654335@ 在将您的提交复制到新的和改进的提交时被丢弃。
长
这里最大的问题可能是术语。 跟踪这个词对您意味着什么? Git 以至少三种不同的方式使用这个词,1 所以其中最多有一种可以与您所想的相匹配。 (可能没有一个完全匹配,这取决于您在这里的想法。)
无论您使用哪个词,以下是正确的思考方式:
重要的是提交。每个提交都有一个唯一的哈希 ID。任何地方的每个 Git——这个存储库的每个克隆——都使用 that 哈希 ID 进行提交。如果您有一个带有 that 哈希 ID 的提交,则它是相同的提交。如果你不这样做,你就没有那个提交。
-
Git 中的
Names 采用多种形式。每个名称都有一个哈希 ID——只有一个!
您使用的三种形式是:
分公司名称: master、develop、feature 或 feature/one 等等。这些是你的,随你的便。 (不过,您可能希望自己的名字与其他人的名字相匹配,至少在不同的时间是这样。)
标签名称: v2.1 等等。虽然你是你的,但你的 Git 会尝试与其他 Git 存储库共享它们:如果你的 Git 看到他们的有 v2.1 而你没有,你的 Git 很可能会将他们的复制到你的.
-
远程跟踪名称: origin/master、origin/feature 等等。 Git 将这些 remote-tracking 分支名称 称为 remote-tracking 分支,但它们与 branch 名称不太一样。您的 Git 将这些从属于其他 Git 的分支名称。你让你的 Git 调用他们的 Git 并从他们那里获得任何新的提交。然后,您的 Git 会更新您的远程跟踪名称,使其与他们的匹配。
远程跟踪名称是通过将 remote 名称(在本例中为 origin)粘贴在其 branch 名称前面,并用斜线保留它们来构建的分开。这就是为什么您的origin/master“跟踪”他们的master,每次运行git fetch origin 时都会更新。2
所有这些名称的工作方式都类似。它们都有长格式:refs/heads/master 是 master 的完整拼写,例如,refs/remotes/origin/master 是 origin/master。这就是 Git 知道哪个是哪个名称的方式。 Git 通常会缩短显示给你的名称,去掉 refs/heads/ 部分的分支名称,或 refs/remotes/ 部分的远程跟踪名称。
请注意,git fetch 与 git push 的对面一样接近。看起来这些应该是push 和pull,但由于历史事故3,它是push 和fetch。拉取只是意味着:运行 fetch,然后运行第二个 Git 命令,默认情况下 git merge,以与当前分支的上游合并。
Fetch 和 Push 非常相似,但有两个关键区别:
-
获取获取东西。你告诉你的 Git:调用你存储在名称 origin 下的 Git(或者你在这里使用的任何远程名称)。您的 Git 在该 URL 处调用服务器,该服务器必须作为 Git 存储库进行响应。然后,该服务器会告诉你它的分支名称和它们的提交,你的 Git 会检查你是否有这些提交。如果没有,您的 Git 会向他们的 Git 询问这些提交,如果您没有提交,则向其父级提交,如果需要,则向其父级提交,依此类推。他们为您提供了他们拥有的所有提交,而您没有,您的 Git 需要完成这些提交。
获得提交后,git fetch 然后通过重命名分支来更新您的远程跟踪名称。
-
推送发送东西。和以前一样,您的 Git 调用另一个 Git,其远程名称为 origin。然后你的 Git 给他们提交,而不是从他们那里得到提交。但在这里,情况略有不同:
-
您的 Git 提供的提交是您正在推送的任何分支的提示提交。 (如果你只是推送一个分支,那只是一个提交。)如果他们没有这些提交,你的 Git 必须提供这些提示提交的父级。 (大多数提交只有一个父级,所以这是一个多提交。)如果他们没有那些,你的 Git 必须提供更多的父级,依此类推。通过这个过程,您的 Git 会找到他们的 Git 所需的所有提交,以便全面了解您发送的 tip 提交:它的所有历史记录。
当你取物时,他们提供了所有他们的分支。不同之处:您只推送您指定的任何分支。
-
在您的 Git 发送了您有的任何提交后,他们没有,他们需要为您正在推送的分支完成提示提交,您的 Git 会向他们发送礼貌的请求设置他们的分支名称。
当您获取数据时,您的 Git 设置了您的远程跟踪名称。您现在要求他们设置他们的分支名称。
总结这些关键点:
- fetch gets(所有,默认情况下,除非你限制它)从它们提交和分支,并将它们的分支重命名为你的远程跟踪名称
- push sends(一个,默认情况下)4 分支提示提交(以及它的祖先,如果/根据需要),然后要求他们设置他们的分支名称(s )
您可以让git push 要求他们设置一个不同的名称,而不是您用来选择要发送的提交的名称。例如:
git push origin test-xyz:new-feature
发送您的test-xyz 分支的提示提交(以及它的父母和其他祖先,如果/根据需要),但要求他们设置或创建他们的 分支名称new-feature。
所以:
... 似乎如果任何 branch_A 正在跟踪远程 branch_B,则任何推送都将转到 branch_B ...
这是完全错误的,至少在默认情况下是这样。 (不过,push.default 有一个设置确实会实现。)
这里还有很多东西需要了解,特别是 git rev-list --left-right --count 正在做什么以及提交“开启”(或者更准确地说,可从分支)的提交意味着什么名字,但在这一点上,我在这个答案中有点用完了时间和空间。
1特别是,文件可以跟踪或不跟踪,有些名称是远程跟踪名称,并且具有上游集的分支被称为跟踪它的上游。在前两种情况下,动词(以其现在分词形式)变成形容词,修饰 name 或 file。
2有一些方法可以运行有限的git fetch,不会更新您的所有远程跟踪名称。例如,使用 git pull 有时会这样做。我更喜欢将git fetch 和其他命令分开,而不是使用git pull fetch-then-run-another-Git-command 命令。
3在获取后想要整合你获取的内容是很常见的,所以起初,git fetch 是一个后端“管道”命令,并不意味着用户运行,git pull 运行git fetch,然后git merge。这是在 remotes 作为概念存在之前,因此在远程跟踪名称存在之前,因此用户没有任何理由运行 git fetch。
随着时间的推移,Git 增加了远程和远程跟踪名称,现在 pull(获取和组合)和 fetch 之间的区别没有组合(或者至少,没有这样做还) 变得既有用又重要。但是名称 pull 已经被用来表示获取和合并,因此这是一个特殊的历史事故。
4即这是 Git 2.0 及更高版本中的默认设置。你可以用push.default更改它,2.0之前的Git版本默认为matching。
当使用matching 时,您的 Git 会向他们的 Git 询问他们的分支名称,匹配您匹配的分支名称,并默认从您的匹配名称推送到它们的匹配名称。
如果您将此设置更改为 upstream,您的 Git 会要求他们的 Git 根据您的分支的上游设置来设置他们的分支,这就是您在问题中所假设的。
现代默认设置是simple,这要求上游设置为同名的分支,这样如果你的上游是设置为他们身边的不同名称。但是,您可以通过输入 git push origin <em>branch</em> 轻松覆盖它,这与 git push origin <em>branch</em>:<em>branch</em> 的含义相同:要求他们的 Git 使用与您在 Git 中使用的相同的分支名称。