ChatGPT解决这个技术问题 Extra ChatGPT

git remote prune、git prune、git fetch --prune 等有什么区别

我的情况是这样的......在同一个仓库工作的人已经从他的本地和远程仓库中删除了一个分支......

大多数在 Stack Overflow 或其他网站上询问过此类问题的人都会在底部的远程跟踪分支列表 git branch -a 中显示分支问题:

* master
  develop
  feature_blah
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah
  remotes/origin/random_branch_I_want_deleted

但是,在我的情况下,不应该存在的分支是本地的:

* master
  develop
  feature_blah
  random_branch_I_want_deleted
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah

当我执行以下任何操作时,它不会在本地删除:

$ git prune

我也试过:

$ git remote prune origin
$ git fetch --prune

更有用的信息:当我检查 git remote show origin 时,它是这样的:

* remote origin
Fetch URL: utilities:homeconnections_ui.git
Push  URL: utilities:homeconnections_ui.git
HEAD branch: master
Remote branches:
 master                        tracked
 develop                       tracked
 feature_blah                  tracked
 other123                      tracked
 other444                      tracked
 other999                      tracked
Local branches configured for 'git pull':
 develop                      merges with remote develop
 feature_blah                 merges with remote other999
 master                       merges with remote master
 random_branch_I_want_deleted merges with remote random_branch_I_want_deleted
Local refs configured for 'git push':
 develop         pushes to develop     (local out of date)
 master          pushes to master      (up to date)
 feature_blah    pushes to feature_blah(up to date)

请注意,它仅在标题为 Local branches configured for 'git pull': 的部分中

为什么?

谢谢,但我只是好奇它为什么会发生。
处理分支层次结构 (x/y) 时存在细微差别:已修复(参见 my answer below

J
John Szakmeister

我不怪你为此感到沮丧。最好的观察方法是这个。每个远程分支可能有三个版本:

远程存储库上的实际分支(例如,位于 https://example.com/repo.git、refs/heads/master 的远程存储库) 您在本地的该分支的快照(存储在 refs/remotes/... 下)(例如, local repo, refs/remotes/origin/master) 和一个可能正在跟踪远程分支的本地分支 (例如, local repo, refs/heads/master)

让我们从 git prune 开始。这将删除不再被引用的对象,它不会删除引用。就您而言,您有一个本地分支机构。这意味着有一个名为 random_branch_I_want_deleted 的 ref 引用了一些代表该分支历史的对象。因此,根据定义,git prune 不会删除 random_branch_I_want_deleted。实际上,git prune 是一种删除在 Git 中积累但未被任何东西引用的数据的方法。一般来说,它不会影响您对任何分支的看法。

git remote prune origingit fetch --prune 都对 refs/remotes/... 下的引用进行操作(我将它们称为远程引用)。它不影响本地分支机构。如果您只想删除特定遥控器下的远程引用,git remote 版本很有用。否则,两者做完全相同的事情。因此,简而言之,git remote prunegit fetch --prune 在上面的数字 2 上运行。例如,如果您使用 git web GUI 删除了一个分支,并且不希望它再出现在您的本地分支列表中 (git branch -r),那么这就是您应该使用的命令。

要删除本地分支,您应该使用 git branch -d(或 -D,如果它没有在任何地方合并)。 FWIW,如果远程分支消失,没有 git 命令可以自动删除本地跟踪分支。


通过解释相关差异,这可以更好地解决整体问题。它还回答了我从上述问题中提出的其他问题。
此命令将显示没有相应远程分支的所有本地分支的列表。您可以将其通过管道传送到 xargs git branch -D,但请注意,您创建但从未推送到服务器的任何新分支都将被删除,因此请谨慎行事:git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}'
@Seed 不,它没有。 :-( 它只删除了本地远程跟踪参考。我只是用 2.7.0 版仔细检查了这一点。
@BlueRaja-DannyPflughoeft 小心这种方法。例如,根据您如何处理稳定分支,它们可能会合并到主分支中,而您最终会删除它们。这并不是什么大损失,因为您没有从服务器中删除它们,但是如果您为它设置了任何特殊配置,那么当分支被删除时,这些配置就会丢失。
@Cloud 不完全正确。可以打包引用(请参阅 .git 区域中的 packed-refs 文件),因此通过文件资源管理器删除它们不一定是简单的事情。最好使用命令来确保两者都得到正确处理。
C
CharlesB

git remote prunegit fetch --prune 做同样的事情:如你所说,删除远程不存在的分支的引用。第二个命令连接到远程并在修剪之前获取其当前分支。

但是它不会触及您已签出的本地分支,您可以简单地删除

git branch -d  random_branch_I_want_deleted

如果分支未在其他地方合并,则将 -d 替换为 -D

git prune 做了一些不同的事情,它清除无法访问的对象,即那些在任何分支或标签中都无法访问的提交,因此不再需要。


我知道这看起来很明显,但 git prune 不仅查找分支和标签,还查找所有其他引用。
所以在我的情况下,为什么 git prune 不起作用?因为它不关心本地分支,而是远程引用?感谢您提供简洁的信息。
@hvd 除了分支和标签之外还有哪些参考?
@gogogadgetinternet 是的。 (假设您的意思是 git remote prune
IMO 对对象收集和引用清理都使用“修剪”的 git 命名约定是混淆的地方。但这只是 git 中许多 UI 难题之一。 :-)
P
Pomme.Verte

万一有人感兴趣。这是一个快速的 shell 脚本,它将删除所有未远程跟踪的本地分支。提醒一句:这将摆脱任何未被远程跟踪的分支,无论它是否被合并。

如果你们看到任何问题,请告诉我,我会解决它(等等)

将其保存在 PATH 上名为 git-rm-ntb(随便叫什么)的文件中,然后运行:

git-rm-ntb <remote1:optional> <remote2:optional> ...

clean()
{
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  RBRANCHES=()
  while read REMOTE; do
    CURRBRANCHES=($(git ls-remote $REMOTE | awk '{print $2}' | grep 'refs/heads/' | sed 's:refs/heads/::'))
    RBRANCHES=("${CURRBRANCHES[@]}" "${RBRANCHES[@]}")
  done < <(echo "$REMOTES" )
  [[ $RBRANCHES ]] || exit
  LBRANCHES=($(git branch | sed 's:\*::' | awk '{print $1}'))
  for i in "${LBRANCHES[@]}"; do
    skip=
    for j in "${RBRANCHES[@]}"; do
      [[ $i == $j ]] && { skip=1; echo -e "\033[32m Keeping $i \033[0m"; break; }
    done
    [[ -n $skip ]] || { echo -e "\033[31m $(git branch -D $i) \033[0m"; }
  done
}

clean $@

难道 $(git branch -d $i) 只删除合并的分支会更安全吗?
stackoverflow.com/questions/7726949/… 中讨论了更安全的选项
C
Community

请注意,Tom Miller (tmiller)(对于 git 1.9/2.0,2014 年第一季度)使用 commit 10a6cc8 修复了 git remote --prunegit fetch --prune 之间的一个区别:

当我们从之前的 fetch 中有一个名为“frotz/nitfol”的远程跟踪分支,而上游现在有一个名为“**frotz”** 的分支时,fetch 将无法使用“git fetch”删除“frotz/nitfol” --prune”从上游。 git 会通知用户使用“git remote prune”来解决问题。

所以:当 upstream repo 有一个与 branch hierarchy 同名的分支(“frotz”)时(“frotz/xxx”,可能的 branch naming convention ),git remote --prune 成功(从您的存储库中清除远程跟踪分支),但 git fetch --prune 失败。

不再:

通过在获取操作之前移动修剪操作来改变“fetch --prune”的工作方式。这样,它不会警告用户发生冲突,而是自动修复它。