Git 跟踪远程分支但推送到不同的分支?

Ton*_*alo 5 git bitbucket

假设我有一个名为“my-local-changes”的分支,它是一个本地分支,它是从一个名为“some-remote-branch”的分支创建的,它是一个远程分支。

我们还假设有一个名为“develop”的第三个分支,它是从多个分支中提取代码的远程分支(“some-remote-branch”是其中之一,我还有一个名为“develop”的本地分支跟踪远程开发分支)

我的问题是如何设置“my-local-changes”来跟踪“develop”分支,但推送到“some-remote-branch”分支?

对于那些好奇的人,对于我为什么要这样做,我希望能够运行 git status 并查看我是否落后于“开发”而不必切换到该分支,并且仍然可以轻松地推送到“某个远程分支'

我目前的流程如下(我也希望有任何改进建议)

git checkout -b my-local-branch some-remote-branch
Run Code Online (Sandbox Code Playgroud)

(进行一些更改并添加它们)

git fetch origin 
git checkout develop
git status
Run Code Online (Sandbox Code Playgroud)

(这样做是为了查看是否有任何我需要合并的开发更改,如果没有运行)

git push origin my-local-branch some-remote-branch
Run Code Online (Sandbox Code Playgroud)

tor*_*rek 7

(不知道为什么这个问题被否决了,1反正你几乎自己回答了......)

您就快到了:只需配置push.defaultsimpleor nothing,以便您必须为此情况指定推送目标,然后对于您的最终命令,请使用:

git push origin my-local-branch:some-remote-branch
Run Code Online (Sandbox Code Playgroud)

这种工作方式是git pushorigin(遥控器的名称)之后采用一系列refspecs。refspec 并不是很复杂:它只是一对名称,例如master:master, or develop:develop, or develop:foo,可选地带有前导加号+,并可选地省略第一个或第二个名称::fooor develop

当您省略两个名称之一时,Refspecs 会变得稍微复杂,因为它们在git fetch和 中的工作方式不同git push。如果您每次都使用这两个名称,则它们保持简单:左侧的名称是存储库上的名称,右侧的名称是目标存储库上的名称。对于fetch,源是远程,目标是您自己的存储库。对于push,源是您的存储库,目标是远程。

省略源名称仅适用于push,在这种情况下,它意味着delete。因此git push origin :foo意味着在 remote 上删除fooorigin。(这不是你想要的,所以要避免。)

省略目的地名称对两者都适用fetchpush但对它们来说意味着不同的东西。让我们忽略fetch这里。使用push,这意味着在本地和远程使用相同的名称。既然你希望在这里,这里不使用它。(或者,对于那些您确实需要它的情况,请继续使用它。)

前导+符号(如果存在)的含义与 相同--force。(实际上--force只是添加了+所有内容。)

如果您运行git push origin, 或git push(甚至没有remote参数),Git 会查找push.default要推送的内容。将其设置为nothing意味着失败/错误输出,因此我必须输入 refspec。将其设置为simple意味着仅将一个分支(当前分支)推送到当前分支的上游,但还要求上游名称匹配。由于my-local-branchsome-remote-branch不匹配,对于您的本地分支foo正在跟踪远程跟踪分支的origin/develop情况,这将失败:名称foodevelop不匹配。

无论哪种方式,Git 都会强制您为此推送输入 refspec。

通过nothing配置,Git 将强制您为每次推送输入一个 refspec 。(我已经使用过这个并且它有效,但它不是非常方便。)通过simple配置,Git 将允许您轻松地将您的推develop送到上游develop,并允许您将您的推foo送到上游develop(或上游jazzy,或任何其他name but foo) 显式,但不会推foo送到,foo因为这不是它在上游定义的。(我用过这个,效果更好。)

从 Git 2.0 版开始,simple是默认配置。 因此,如果您拥有 Git 2.0 或更高版本,那么您已经可以开始使用了。如果没有,请查看您是否可以升级您的 Git 版本,但push.default可以追溯到 Git 版本 1.6。(我不确定它可以采用什么值。我认为,如果不是更早,当前的 5 组值可以追溯到 1.7.11。)

为了完整起见,其他三个可能的值是:currentupstream,和matching。该current值表示使用当前分支的名称:当前分支git push origin $branch:$branch在哪里$branch。该upstream值表示使用当前分支的上游名称:git push origin $branch:$merge,其中$merge来自git config --get branch.$branch.merge

matching值是最难描述的,在 Git 2.0 版本之前是默认值:它意味着获取远程上每个分支的列表,并将它们的名称与我们本地的分支名称相匹配,然后对所有分支进行整体推送我们本地分支到远程同名分支,只要两个名称匹配。 这不是一个非常安全的设置,尽管只要您不使用--force,它实际上在实践中效果很好,这就是它可以使用这么多年的原因。

旁注:术语

Git 的术语有点乱。

  • 一个当地的分支机构(或只是“分支”或“分支名称”),就像master是在一个名称refs/heads/命名空间。它指向一个提交 ID。当您在该分支上进行新提交时,Git 读取提交 ID,使用该 ID 作为新提交的父级进行新提交,然后将新提交的 ID 写入分支名称,以便分支现在指向新提交(依次指向前一个分支提示,依此类推)。

    您可以git checkout使用本地分支,它会将您置于“在分支上”,例如这样git statusOn branch master。正如我上面刚刚提到的,这会进行设置,以便新的提交推进分支。

  • 一个远程跟踪分支就像origin/master是在一个名称refs/remotes/命名空间。在refs/remotes/我们找到遥控器本身的名称之后origin,然后是另一个斜杠,最后是在该遥控器上看到的分支名称(refs/heads/当然是sans )。这些名称存储在本地,在您自己的存储库中:它们实际上根本不是远程的。它们只是在您的 Git 通过和(在更有限的范围内)通过联系远程时自动更新git fetchgit push

    您可以git checkout使用远程跟踪分支,但如果这样做,则会git checkout将您置于“分离的 HEAD”模式,因此git statusgit branch声称您不在任何分支上(或在“无分支”或类似的地方,有时使用“分离的 HEAD” ”的说法)。当这种情况发生时,您实际上是在(单一的、特殊的)匿名分支上。当您回到普通分支时,您在匿名分支上所做的任何工作最终都会消失。(因此,如果您想保留这项工作,请设置一个名称,使其不再是匿名的——或者git checkout在您进行这项工作之前用于返回常规分支。)

  • 本地分支可以跟踪另一个分支(本地远程)。当本地分支B正在跟踪另一个分支U 时,Git 将其称为本地分支的“上游”。这个上游由两部分组成:远程的名称,如origin,以及在远程上看到的分支的名称,如master。要将本地分支跟踪为分支B的上游,Git 只需将远程设置为.

    因此,如果本地分支B配置了这两个项目,则它 正在跟踪上游U。U本身通常是一个远程跟踪分支,它是一个本地实体(这些refs/remotes/命名空间名称之一)。您必须git fetchgit push要更新远程跟踪分支,git status然后git branch -vv将跟踪远程跟踪分支的本地分支报告为领先和/或落后于其对应分支。

    本地分支B可以改为跟踪另一个本地分支作为其上游。在这种情况下,由于所有内容都是本地更新的,git status并且git branch -vv无需任何更新即可保持最新状态git fetch

    当然,本地分支B不需要跟踪任何内容。命令和将设置或取消设置当前分支的上游。您还可以使用 设置、更改和检查上游的两个独立部分(the和 the part),尽管使用通常更好更方便。git branch --set-upstream-to upstreamgit branch --unset-upstreambranch.$branch.remotebranch.$branch.mergegit configgit branch


1可能投反对票是因为 Git 2.0 默认push.default