0

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

我想做的是:

  • 签出远程分支git checkout origin/feature
  • 根据该分支创建本地分支git checkout -b feature_my_tweak
  • 所以现在我有一个 call 的本地副本featurefeature_my_tweak我可以玩
  • 做一些改变,commit -m "added my tweak"所以现在我的本地人feature_my_tweak已经偏离了feature
  • 现在做一个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,这是我不想要的。

我希望这是有道理的。

4

1 回答 1

3

TL;博士

答案的简短版本归结为否,但没关系,不用担心,只需手动完成;这很容易。如果您有一个经常使用的特定分支,请编写脚本或 Git 别名来执行此操作。

中等的

要手动执行此操作,对于您想知道是否有新内容的分支Borigin/feature,与您自己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/featureor 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)让 Git放弃旧的提交,当它将您的提交复制到新的和改进的提交时origin丢弃这些旧提交。git rebase

可能这里最大的问题是术语。跟踪这个词对您意味着什么?Git以至少三种不同的方式使用这个词,其中一种最多可以与您正在考虑的那个匹配。(可能没有一个完全匹配,这取决于您在这里的想法。)

无论您使用哪个词,以下是正确的思考方式:

  • 重要的是提交。每个提交都有一个唯一的哈希 ID。任何地方的每一个 Git——这个存储库的每一个克隆——都使用那个哈希 ID 来进行那个提交。如果您有一个具有哈希 ID 的提交,则它是相同的提交。如果你不这样做,你就没有那个提交。

  • Git 中的名称有多种形式。每个名称都有一个哈希 ID——只有一个!

    您使用的三种形式是:

    • 分支名称: master、或develop,等等。这些是你的,随你的便。(不过,您可能希望自己的名字与其他人的名字相匹配,至少在不同的时候。)featurefeature/one

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

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

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


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

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

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

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

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

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

    • 您的 Git 提供的提交是您正在推送的任何分支的提示提交。(如果你只是推送一个分支,那只是一个提交。)如果他们没有这些提交,你的 Git 必须提供这些提示提交的父级。(大多数提交只有一个父级,所以这是多一个提交。)如果他们没有这些,你的 Git 必须提供更多的父级,依此类推。通过这个过程,您的 Git 会找到他们的 Git 需要的所有提交,以完整了解您发送的提示提交:所有历史记录。

      你取的时候,他们把所有的树枝都献上了。不同之处:你只推你指定的任何分支。

    • 在你的 Git 发送了你有的任何提交之后,他们没有,他们需要为你正在推送的分支完成提示提交,你的 Git 会发送一个礼貌的请求,让他们设置他们的分支姓名。

      当您获取数据时,您的 Git 设置了您的远程跟踪名称。您现在要求他们设置他们的分支名称。

总结一下这些关键点:

  • fetch获取(所有,默认情况下,除非你限制它)提交和分支,并将它们的分支重命名为您的远程跟踪名称
  • push发送(一个,默认情况下)4个分支提示提交(以及它的祖先,如果/根据需要),然后要求他们设置他们的分支名称

可以要求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特别是,文件可以被跟踪或不被跟踪,一些名称是远程跟踪名称,并且具有上游集的分支被称为跟踪其上游。在前两种情况下,动词(以其现在分词形式)变成形容词,修饰名称文件。

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

3 fetch 之后想要整合你fetch 的东西是很常见的,所以一开始git fetch是一个后端“管道”命令,不是为了让用户运行,然后git pull运行。这是在远程作为一个概念存在之前,因此在远程跟踪名称存在之前,因此用户没有任何理由运行.git fetchgit mergegit fetch

随着时间的推移,Git 增加了 remotes 和 remote-tracking 的名称,现在pull——fetch 和 combine——和只是fetch不结合(或者至少,还没有结合)之间的区别变得既有用又重要。但是这个名字 pull已经被用来表示fetch 和 combine,因此这个特殊的历史事故。

4也就是说,这是 Git 2.0 及更高版本中的默认设置。您可以使用 更改它push.default,并且低于 2.0 的 Git 版本默认为matching.

使用 时matching,您的 Git 会向他们的 Git 询问他们的分支名称,匹配您匹配的分支名称,并默认从您的匹配名称推送到它们的匹配名称。

如果您将此设置更改为upstream,您的 Git 会要求他们的 Git 根据您的分支的上游设置来设置他们的分支,这就是您在问题中所假设的。

现代默认设置是simple,它要求上游被设置为同名的分支,这样git push如果你的上游被设置为他们一方的不同名称,你的一端就会立即失败。但是,您可以通过输入 轻松覆盖它,这与以下含义相同:要求他们的 Git 使用与您在 Git 中使用的相同的分支名称。git push origin branchgit push origin branch:branch

于 2020-03-11T21:58:55.237 回答