使用本地分支更新远程跟踪分支

Usage of updating a remote-tracking branch by a local branch

我知道可以根据 当前 存储库的 local branch 的内容创建、更新或删除 remote-tracking branch。例如:

$ git push . :refs/remotes/origin/master

删除 remote-tracking branch。但是由本地分支机构更新 remote-tracking branch 是一个好习惯吗?如果是,该作品还有其他用途吗?

虽然我不太确定你在问什么。如果你想要像这样删除远程分支的替代方法,那就是:

git push origin --delete branchName

当我通过本地更新远程时,我确保 git 历史记录对齐,因此没有强制推送。

当我本地删除remote的时候,是branch的feature已经实现,pull request到master刚刚完成的时候。远程分支的所有更改现在都在 master 中,因此我们可以安全地删除分支。

首先,让我们定义术语远程跟踪分支。远程跟踪分支只是一个引用,其完整拼写以 refs/remotes/ 开头,例如您示例中的 refs/remotes/origin/master。在与 Git 的大多数正常交互中,我们删除 refs/remotes/ 部分而只写 origin/master,但有时——如较低级别、面向脚本的 Git 命令,或者在执行像你的例子一样奇怪——有必要把它完整地拼出来。

现在,远程跟踪分支的 目的 是保持 track 存储在 中的 ID branch 在你的一个 remote 上(因此得名)。因此,如果我们在这里仔细查看您的问题:

... is updating remote branch by local branch a good practice?

我们需要注意一些事情:这不是更新 "remote branch"(我们还没有真正定义),而是更新 remote-tracking 分支,即名称以 refs/remotes/ 开头的那些本地实体之一。我们还要在这里注意,您专门 删除 一个远程跟踪分支(这是一种相当严重的更新形式 :-))。

不过,假设您只是漏掉了一个词并且确实是这个意思 "remote-tracking branch":以这种方式更新它是一种好的做法吗?一般不会,不会。

不过,让我添加更多背景知识。我还需要在这里定义术语 refspec。 refspec 只是一对引用(如 masterorigin/master,或它们的完整拼写版本,分别为 refs/heads/masterrefs/remotes/origin/master),由冒号 : 字符。左边的引用称为源或src,右边的引用称为目标或dst ].或者,您可以在该对前面加​​上加号 +,并最多省略 src and/or [ 中的一个=26=]。如果您省略 dst,您也可以并且可能应该省略冒号:例如,git fetch origin master 是没有目的地的来源。虽然省略 src 时需要冒号:git push origin :foo 不能拼写为 git push origin foo.

(当您省略一半 refspec 时, 意味着 git fetchgit push 之间变化。我不打算完全描述这一点,足以涵盖此处感兴趣的案例。)

通过 git fetchgit push

更新

自 Git 版本 1.8.4 起,git pushgit fetch 都会适时更新远程跟踪分支。也就是说,如果您有 Git 联系远程 R 并获取或设置其分支 B,并且您的配置显示要跟踪B refs/remotes/<em>R</em>/<em>B</em>(与正常设置一样),您的 Git 将(自 1.8.4 起)更新该远程跟踪分支。 (在 1.8.4 之前,Git 对 push 进行了机会性更新,但对 fetch 没有。)

删除分支和--prune

只需 运行ning git fetch origin(没有额外的 refspec)将更新所有 refs/remotes/origin/ 远程跟踪分支。但是假设你早些时候做了这个并且有一个 xyz 分支你的 Git 已经复制到 refs/remotes/origin/xyz,从那时起,有人 删除了 分支 xyzorigin?

今天发生的事情是,您的 Git 保留了您的 origin/xyz(假设您仍在使用它)。要告诉你的 Git 它应该自动 p运行e 你拥有的任何远程跟踪分支,远程不再有,只需添加 --prune(或-p)到你的命令:

$ git fetch --prune origin

您的 Git 现在将 删除 您在 origin 下列出的任何远程跟踪分支,这些分支仍在跟踪远程上的实际分支名为 origin.

你也可以这样拼写:

git remote update --prune origin

并且 Git 的某些版本中存在一些错误,其中两个命令之一有效而另一个无效(我不确定哪个版本,也不知道哪个版本成功)。

手动更新

作为一般规则,您应该让 Git 自动更新远程跟踪分支。但是,在某些特定情况下,您可能希望手动更新它们,例如在手动修改配置以更改远程名称后,或更改应用于远程的映射(remote. <em>remote</em>.fetch 行),或者遇到像我刚才提到的错误。或者,例如,如果您刚刚使用无源 git pushgit push --delete 来删除分支 - git push origin :foo - 并且您的网络连接速度极慢,您可能太不耐烦了运行git fetch -p origin等着

在这种情况下,虽然 git push . :refs/remotes/origin/foo 可以从您的存储库中删除 origin/foo,但您不妨使用更直接的命令:

$ git branch -r -d origin/foo
Deleted remote-tracking branch origin/foo (was 5ace313).

事实上,任何对远程跟踪分支的更新都可以通过git branch -r(或底层"plumbing"命令,git update-ref)完成,就像对本地分支的更新一样通过 git branch 完成(没有 -r)。我认为唯一有充分理由使用 git push . 更新分支的地方是在不实际检查分支的情况下实现 git merge --ff-only 的结果。1


1具体来说,git 推送。 <em>x</em>:<em>y</em> 尝试快进本地 ID x——这可以是解析为有效对象 ID 的任何内容——引用 y。当y为本地分支时,相当于:

git checkout y && git merge --ff-only x && git checkout -

除了它根本不触及工作树。除了原子性和类型检查问题以及可能的符号引用问题外,它也等同于以下 shell 命令序列:

x="" y=""
# resolve x to an object ID
xid=$(git rev-parse $x) || exit
# resolve y to a reference
yref=$(git rev-parse --symbolic-full-name $y) || exit
[ -z "$yref" ] && { echo "fatal: $y: not a valid reference"; exit 1; }
# make sure the current value of y is an ancestor of (resolved) x
git merge-base --is-ancestor $yref $xid || { echo 'not a fast forward'; exit 1; }
# ok, it is a fast forward: update
git update-ref -m "fast forward" $yref $xid

请注意,--symbolic-full-ref 将像 origin/HEAD 这样的符号引用解析为它所引用的名称,例如 refs/remotes/origin/master。这在这里可能是不可取的,但是 git rev-parse 没有明显的标志来验证引用名称是否有效并将其转换为完全限定,但不将符号名称扩展为其目标。