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

Git track a remote branch but push to a different branch?

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

我们还假设有第三个分支叫做'develop',它是代码从多个分支拉入的远程分支('some-remote-branch'是其中之一,我也有一个本地分支称为 'develop' 跟踪远程开发分支)

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

对于那些好奇的人,至于我为什么要这样做,我希望能够 运行 git status 看看我是否落后于 'develop' 而没有切换到那个分支,仍然可以轻松地推送到 'some-remote-branch'

我目前的流程如下(我也很乐意提出任何改进建议)

git checkout -b my-local-branch some-remote-branch

(进行一些修改并添加)

git fetch origin 
git checkout develop
git status

(执行此操作以查看是否有任何我需要合并的开发更改,如果不需要 运行)

git push origin my-local-branch some-remote-branch

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

你就快完成了:只需将push.default配置为simplenothing,这样你必须为此指定推送目标案例,然后对于您的最终命令,请使用:

git push origin my-local-branch:some-remote-branch

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

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

省略源名称仅适用于 push,在本例中,这意味着 删除。因此 git push origin :foo 意味着 删除远程 origin 上的 foo。 (这不是你想要的,所以请避免。)

省略目的地名称对 fetchpush 都有效,但对它们意味着不同的事情。让我们在这里忽略 fetch 。对于 push,这意味着 在本地和远程上使用相同的名称。既然你想要它,就不要在这里使用它。 (或者,对于您 需要的情况,请继续使用它。)

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

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

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

使用 nothing 配置,Git 将强制您为 每个 推送输入一个 refspec。 (我用过这个并且它有效,但它不是很方便。)使用 simple 配置,Git 将允许你轻松地将你的 develop 推到上游 develop ,并将允许您将 foo 明确地推送到上游 develop(或上游 jazzy,或除 foo 之外的任何其他名称),但不会推送 foofoo 因为那不是它定义的上游。 (我用过这个,效果更好。)

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

为了完整起见,其他三个可能的值是:currentupstreammatchingcurrent 值表示使用当前分支的名称: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的术语有点乱。

  • A local branch (or just "a branch" or "a branch name"), like master, is a name in refs/heads/ 名字-space。它指向一个提交 ID。当您在该分支上进行新提交时,Git 读取提交 ID,使用该 ID 作为新提交的父项进行新提交,然后将新提交的 ID 写入分支名称,以便branch 现在指向新的提交(它又指向以前的分支提示,依此类推)。

    你可以 git checkout 一个本地分支,它会把你放在 "on the branch" 上,这样 git status 就会说 On branch master。正如我在上面提到的那样,这会进行设置,以便新提交推进分支。

  • A remote-tracking branch like origin/masterrefs/remotes/ name-space中的一个名字。在 refs/remotes/ 之后,我们找到遥控器本身的名称,origin,然后是另一个斜杠,最后是在该遥控器上看到的分支名称(当然没有 refs/heads/)。这些名称存储在本地,在您自己的存储库中:它们实际上根本不是远程的。当您的 Git 通过 git fetch 和(在更有限的范围内)通过 git push.[=108 联系遥控器时,它们只是 自动更新 =]

    您可以 git checkout 远程跟踪分支,但如果您这样做,git checkout 会将您置于 "detached HEAD" 模式,因此 git statusgit branch 声称你不在任何分支上(或者在 "no branch" 或类似的分支上,有时使用 "detached HEAD" 措辞)。当这种情况发生时,你实际上是在(单一的,特殊的)anonymous 分支上。当您回到正常分支时,您在匿名分支上所做的任何工作最终都会消失。 (所以如果你想保留工作,设置一个名字,这样它就不再是匿名的——或者在你做那项工作之前使用 git checkout 回到常规分支。)

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

    因此本地分支 B 正在跟踪上游 U 如果它配置了这两项。 U 本身通常是一个远程跟踪分支,它是一个本地实体(refs/remotes/ 名称-space 名称之一)。您必须 git fetchgit push 才能更新远程跟踪分支,之后 git statusgit branch -vv 将报告正在跟踪远程跟踪分支的本地分支,领先 and/or 落后于同行。

    本地分支 B 可以改为跟踪另一个本地分支作为其上游。在这种情况下,由于所有内容都是本地更新的,因此 git statusgit branch -vv 将是最新的,而不需要任何 git fetch

    A 本地分支 B 当然不需要跟踪任何东西。命令 git branch --set-upstream-to <em>upstream</em>git branch --unset-upstream 将设置或取消设置上游当前分支。您还可以使用 git config 设置、更改和检查上游的两个单独部分(branch.$branch.remotebranch.$branch.merge 部分),尽管使用 git branch 通常更好并且更方便。


1可能是因为 Git 2.0 默认值 push.default