【问题标题】:Can Git track an ancestor branch as well as its own branch?Git 可以跟踪祖先分支以及它自己的分支吗?
【发布时间】:2020-06-23 22:14:36
【问题描述】:

对不起,如果这是一个菜鸟问题,但我一直在寻找一个小时以上,但无法得到明确的答案。

我想做的是:

  • 签出远程分支git checkout origin/feature
  • 基于该分支创建一个本地分支git checkout -b feature_my_tweak
  • 所以现在我有一个名为 feature_my_tweakfeature 的本地副本,我可以使用它
  • 进行一些更改和commit -m "added my tweak",所以现在我的本地feature_my_tweakfeature 不同了
  • 现在执行git push --set-upstream origin feature_my_tweak 将我的本地分支推送到远程服务器
  • 现在同事将更改推送到远程服务器上的feature

此时,我希望能够 git pull 并让 git 看到 feature 的更改并将其拉入(获取/合并)到我的本地 feature_my_tweak 分支。有没有办法自动做到这一点?还是我必须手动执行git merge feature 才能将所有更改从该分支获取到我的本地feature_my_tweaks 分支?我想我认为有一种方法可以让一个分支跟踪另一个分支。

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

有没有办法做到这一切?据我所知,如果任何分支_A 正在跟踪远程分支_B,任何推送都将转到分支_B,这是我不想要的。

我希望这是有道理的。

【问题讨论】:

    标签: git git-track


    【解决方案1】:

    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/featuregit 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——只有一个!

      您使用的三种形式是:

      • 分公司名称: masterdevelopfeaturefeature/one 等等。这些是你的,随你的便。 (不过,您可能希望自己的名字与其他人的名字相匹配,至少在不同的时间是这样。)

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

      • 远程跟踪名称: origin/masterorigin/feature 等等。 Git 将这些 remote-tracking 分支名称 称为 remote-tracking 分支,但它们与 branch 名称不太一样。您的 Git 将这些从属于其他 Git 的分支名称。你让你的 Git 调用他们的 Git 并从他们那里获得任何新的提交。然后,您的 Git 会更新您的远程跟踪名称,使其与他们的匹配。

        远程跟踪名称是通过将 remote 名称(在本例中为 origin)粘贴在其 branch 名称前面,并用斜线保留它们来构建的分开。这就是为什么您的origin/master“跟踪”他们的master,每次运行git fetch origin 时都会更新。2


      所有这些名称的工作方式都类似。它们都有长格式:refs/heads/mastermaster 的完整拼写,例如,refs/remotes/origin/masterorigin/master。这就是 Git 知道哪个是哪个名称的方式。 Git 通常会缩短显示给你的名称,去掉 refs/heads/ 部分的分支名称,或 refs/remotes/ 部分的远程跟踪名称。

    请注意,git fetchgit push 的对面一样接近。看起来这些应该是pushpull,但由于历史事故3,它是pushfetch。拉取只是意味着:运行 fetch,然后运行第二个 Git 命令,默认情况下 git merge,以与当前分支的上游合并。

    Fetch 和 Push 非常相似,但有两个关键区别:

    1. 获取获取东西。你告诉你的 Git:调用你存储在名称 origin 下的 Git(或者你在这里使用的任何远程名称)。您的 Git 在该 URL 处调用服务器,该服务器必须作为 Git 存储库进行响应。然后,该服务器会告诉你它的分支名称和它们的提交,你的 Git 会检查你是否有这些提交。如果没有,您的 Git 会向他们的 Git 询问这些提交,如果您没有提交,则向其父级提交,如果需要,则向其父级提交,依此类推。他们为您提供了他们拥有的所有提交,而您没有,您的 Git 需要完成这些提交。

      获得提交后,git fetch 然后通过重命名分支来更新您的远程跟踪名称

    2. 推送发送东西。和以前一样,您的 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特别是,文件可以跟踪不跟踪,有些名称是远程跟踪名称,并且具有上游集的分支被称为跟踪它的上游。在前两种情况下,动词(以其现在分词形式)变成形容词,修饰 namefile

    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 中使用的相同的分支名称。

    【讨论】:

    • 哇,太棒了!谢谢。是的,我认为我对“跟踪”这个词的理解不正确,或者更确切地说,我认为它的含义不止于此。我想我在想跟踪意味着〜'跟随另一个分支并将更改合并到您的当前分支'..但似乎跟踪只是意味着''您从本地分支拉/推到的单个远程分支'。再次感谢您的大力响应。
    • @Atom999: 好吧,git pull 使用你设置的上游 do git merge(或者 git rebase 如果你告诉它使用 rebase合并)。所以从这个意义上说,它确实意味着你在想什么......但仅限于git pull 本身。如果将 fetch 和后续操作分开,git mergegit rebase 都使用上游设置作为默认操作数:例如,如果分支 X 的上游是 origin/X,则 git mergeX 签出意味着git merge origin/X.
    • 因为我喜欢分别使用这两个命令,所以我得到了更多的控制权和更多的选择:我可以git fetch 然后git merge origin/Y 代替,如果我想这样做的话。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 2014-02-04
    • 2012-03-03
    • 2010-10-05
    • 2013-04-25
    • 2012-03-05
    相关资源
    最近更新 更多