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


358

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

大多数在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':

为什么?


git branch -d the_local_branch
krsteeve

1
谢谢,但是我很好奇为什么会发生。
gogogadgetinternet

处理分支层次结构(x/y)时有细微的差别:它已得到修复(请参见下面的答案
VonC 2014年

Answers:


664

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

  1. 对远程仓库的实际分支
    (例如,远程回购在https://example.com/repo.gitrefs/heads/master
  2. 您在本地(存储在refs/remotes/...)下的该分支的快照
    (例如本地回购,refs/remotes/origin/master
  3. 还有一个可能正在跟踪远程分支的
    本地分支(例如,本地仓库,refs/heads/master

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

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

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


22
通过解释相关差异,这样做可以更好地解决整个问题。它还回答了我从上述问题中获得的其他问题。
gogogadgetinternet

14
此命令将显示没有相应远程分支的所有本地分支的列表。您可以将其传送到xargs git branch -D,但是请注意,您创建但从未推送到服务器的所有新分支都将被删除,因此请谨慎行事: git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}'
Jason Walton 2014年

4
@种子不,不是。:-(它仅删除本地远程追踪裁判我只是2.7.0版本再次检查这个。
约翰Szakmeister

1
@ BlueRaja-DannyPflughoeft注意这种方法。例如,根据您如何执行稳定的分支,它们可能似乎已合并到master分支中,最终您将其删除。这并不是很大的损失,因为您没有从服务器中删除它们,但是如果您为它设置了任何特殊的配置,那么当删除分支时,它将丢失。
John Szakmeister

1
@Cloud并非完全正确。引用可以打包(请参见该区域中的packed-refs文件.git),因此通过文件资源管理器删除引用不一定是简单的事情。最好使用命令来确保两个命令均已正确处理。
John Szakmeister '19

55

git remote prunegit fetch --prune执行相同的操作:如您所说,删除对远程站点上不存在的分支的引用。第二个命令连接到远程并在修剪之前获取其当前分支。

但是,它不会影响您已签出的本地分支,您只需使用

git branch -d  random_branch_I_want_deleted

如果分支未在其他位置合并-d-D则替换为

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


1
我知道它似乎很明显,但git prune不仅查找分支和标签,还查找所有其他引用。

因此,以我为例,为什么git prune无法正常工作?因为它不在乎本地分支,而是远程引用?感谢您的简要信息。
gogogadgetinternet

@hvd除了分支和标签以外,还有哪些类型的引用?
CharlesB

@gogogadgetinternet是的。(假设您的意思是git remote prune
CharlesB

4
IMO的混淆命名方式就是同时使用“ prune”进行对象收集引用清除的git命名约定。但这只是git中许多UI难题之一。:-)
torek

14

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

如果你们对此有任何疑问,请告诉我,我会解决(等)。

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

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 $@

谢谢!彩色输出效果不错;-)
BVengerov

2
$(git branch -d $ i)仅删除合并的分支会更安全吗?
user2012677

非常有帮助,非常感谢!!!
罗宾·哈特兰


13

请注意,Tom Miller(通过提交10a6cc8修复了git remote --prune和之间的一个差异(对于git 1.9 / 2.0,2014年第一季度):git fetch --prunetmiller

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

因此:当上游仓库中有一个分支(“ frotz”)的名称与分支层次结构(“ frotz / xxx”,可能的分支命名约定)同名时,git remote --prune就成功了(从仓库中清除了远程跟踪分支) ,但git fetch --prune失败了。

不再:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.