使用本地分支更新远程跟踪分支
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 只是一对引用(如 master
或 origin/master
,或它们的完整拼写版本,分别为 refs/heads/master
和 refs/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 fetch
和 git push
之间变化。我不打算完全描述这一点,足以涵盖此处感兴趣的案例。)
通过 git fetch
和 git push
更新
自 Git 版本 1.8.4 起,git push
和 git 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
,从那时起,有人 删除了 分支 xyz
在 origin
?
今天发生的事情是,您的 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 push
或 git 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
没有明显的标志来验证引用名称是否有效并将其转换为完全限定,但不将符号名称扩展为其目标。
我知道可以根据 当前 存储库的 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 只是一对引用(如 master
或 origin/master
,或它们的完整拼写版本,分别为 refs/heads/master
和 refs/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 fetch
和 git push
之间变化。我不打算完全描述这一点,足以涵盖此处感兴趣的案例。)
通过 git fetch
和 git push
更新
自 Git 版本 1.8.4 起,git push
和 git 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
,从那时起,有人 删除了 分支 xyz
在 origin
?
今天发生的事情是,您的 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 push
或 git 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
没有明显的标志来验证引用名称是否有效并将其转换为完全限定,但不将符号名称扩展为其目标。