首页 文章

删除跟踪分支不再在远程

提问于
浏览
672

是否有一种简单的方法可以删除远程等效不再存在的所有跟踪分支?

例:

分支机构(本地和远程)

  • 大师

  • origin / master

  • origin / bug-fix-a

  • origin / bug-fix-b

  • origin / bug-fix-c

在本地,我只有一个主分支 . 现在我需要处理bug-fix-a,所以我检查它,处理它,并将更改推送到远程 . 接下来我用bug-fix-b做同样的事情 .

分支机构(本地和远程)

  • 大师

  • bug-fix-a

  • bug-fix-b

  • origin / master

  • origin / bug-fix-a

  • origin / bug-fix-b

  • origin / bug-fix-c

现在我有本地分支机构master,bug-fix-a,bug-fix-b . Master分支维护者将我的更改合并到master中并删除他已经合并的所有分支 .

那么现在的状态是:

分支机构(本地和远程)

  • 大师

  • bug-fix-a

  • bug-fix-b

  • origin / master

  • origin / bug-fix-c

现在我想调用一些命令删除分支(在本例中为bug-fix-a,bug-fix-b),这些分支不再在远程存储库中表示 .

它将类似于现有命令 git remote prune origin ,但更像是 git local prune origin .

26 回答

  • 53

    git remote prune origin prunes跟踪分支机构不在遥控器上 .

    git branch --merged 列出已合并到当前分支的分支 .

    xargs git branch -d 删除标准输入上列出的分支 .

    小心删除 git branch --merged 列出的分支 . 该列表可能包含 master 或您不想删除的其他分支 .

    要在删除分支之前给自己编辑列表的机会,可以在一行中执行以下操作:

    git branch --merged >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches

  • 43

    命令之后

    git fetch -p
    

    运行时删除远程引用

    git branch -vv
    

    它将显示为“已离开”作为远程状态 . 例如,

    $ git branch -vv
      master                 b900de9 [origin/master: behind 4] Fixed bug
      release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
      release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
      bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug
    

    所以你可以编写一个简单的脚本来删除已经远程的本地分支:

    git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done
    
  • 0

    在大多数其他解决方案中,"gone"的模式匹配对我来说有点吓人 . 为了更安全,它使用 --format 标志来提取每个分支的上游跟踪状态 .

    我需要一个Windows友好版本,因此这将使用Powershell删除列为“已消失”的所有分支:

    git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
        ? { $_ -ne "" } | 
        % { git branch -D $_ }
    

    第一行列出了上游分支“已消失”的本地分支的名称 . 下一行删除空白行(对于未“消失”的分支输出),然后将分支名称传递给命令以删除分支 .

  • 10

    这些答案中的大多数实际上并未回答原始问题 . 我做了一堆挖掘,this是我找到的最干净的解决方案 . 这是一个稍微更全面的答案:

    • 查看您的默认分支 . 通常 git checkout master

    • 运行 git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

    Explanation:

    通过修剪跟踪分支然后删除显示在 git branch -vv 中的"gone"的本地分支来工作 .

    Notes:

    如果您的语言设置为英语以外的其他语言,则需要将 gone 更改为相应的单词 . 不会触及仅限本地的分支 . 已在远程删除但未合并的分支将显示通知但不会在本地删除 . 如果要删除它们,请将 -d 更改为 -D .

  • 3

    我通常不回答已经有16个答案的问题,但所有其他答案都是错误的,正确的答案是如此简单 . 问题是,“是否有一种简单的方法可以删除远程等效不再存在的所有跟踪分支?”

    如果“简单”意味着不脆弱,不危险,并且不依赖于并非所有读者都会拥有的工具,那么正确答案是:不 .

    有些答案很简单,但他们没有按照要求做 . 其他人做了所要求的,但并不简单:所有人都依赖于通过文本操作命令或脚本语言解析Git输出,这些语言可能不会出现在每个系统上 . 最重要的是,大多数建议使用瓷器命令,其输出不是设计为由脚本解析(“瓷器”是指用于人工操作的命令;脚本应使用较低级别的“管道”命令) .

    进一步阅读:


    如果你想安全地做到这一点,对于问题中的用例(垃圾收集跟踪分支已经在服务器上删除但仍然作为本地分支存在)和仅使用高级Git命令,你必须

    • git fetch --prune (或 git fetch -p ,这是别名,或 git prune remote origin ,它在没有提取的情况下执行相同的操作,并且可能不是您想要的大部分时间) .

    • 注意报告为已删除的任何远程分支 . 或者,稍后查找它们, git branch -v (任何孤立的跟踪分支都将标记为"[gone]") .
      每个孤立的跟踪分支上的

    • git branch -d [branch_name]

    如果你想编写一个解决方案的脚本,那么 for-each-ref 就是你的起点,就像Mark Longair's answer这里和this answer to another question一样,但是我没有办法在没有编写shell脚本循环或使用xargs之类的情况下利用它 .


    背景说明

    要了解正在发生的事情,您需要了解的是,在跟踪分支的情况下,您没有一个分支,而是三个分支 . (并且回想一下“分支”仅仅意味着指向提交的指针 . )

    给定跟踪分支 feature/X ,远程存储库(服务器)将具有此分支并将其命名为 feature/X . 您的本地存储库有一个分支 remotes/origin/feature/X ,这意味着"This is what the remote told me its feature/X branch was, last time we talked,",最后,本地存储库有一个分支 feature/X ,它指向您的最新提交,并配置为"track" remotes/origin/feature/X ,意思是你可以拉动并推动它们保持对齐 .

    在某些时候,有人删除了遥控器上的 feature/X . 从那一刻开始,你留下你的本地 feature/X (你可能不再需要了,因为功能X上的工作可能已经完成了),你的 remotes/origin/feature/X 肯定是无用的,因为它的唯一目的是记住状态服务器的分支 .

    并且Git会让你自动清理多余的 remotes/origin/feature/X - 这就是 git fetch --prune 所做的 - 但由于某种原因,它不会让你自动删除自己的 feature/X ......即使你的 feature/X 仍然包含孤立的跟踪信息,所以它具有识别已完全合并的以前跟踪分支的信息 . (毕竟,它可以为您提供让您自己手动操作的信息 . )

  • 0

    似乎解决方案在这里 - https://stackoverflow.com/a/1072178/133986

    简而言之, git remote prune 就是神奇的

  • -3

    我在这里找到了答案:How can I delete all git branches which have been merged?

    git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
    

    确保我们保持主人

    您可以通过在第一个之后添加另一个 grep 来确保不会删除 master 或任何其他分支 . 在那种情况下你会去:

    git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d
    

    因此,如果我们想保留 masterdevelopstaging ,我们会去:

    git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d
    

    将其设为别名

    由于它有点长,您可能想要为 .zshrc.bashrc 添加别名 . 我叫 gbpurgegit branches purge ):

    alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'
    

    然后重新加载 .bashrc.zshrc

    . ~/.bashrc
    

    要么

    . ~/.zshrc
    
  • 759

    删除已合并为master的所有分支,但不要尝试删除master本身:

    git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

    或添加别名:

    alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

    说明:

    git checkout master 结帐主分行

    git pull origin master 确保本地分支已合并所有远程更改

    git fetch -p 删除对已删除的远程分支的引用

    git branch -d $(git branch master --merged | grep master -v) 删除已合并为master的所有分支,但不要尝试删除master本身

  • 16
    git fetch -p
    

    这将删除未远程跟踪的所有分支 .

  • 10

    Windows解决方案

    对于Microsoft Windows Powershell:

    git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}

    解释

    git checkout master 切换到主分支

    git remote update origin --prune 修剪远程分支

    git branch -vv 获取所有分支的详细输出(git reference

    Select-String -Pattern ": gone]" 仅获取已从远程删除的记录 .

    % { $_.toString().Trim().Split(" ")[0]} 获取分支名称

    % {git branch -d $_} 删除分支

  • 0

    我认为没有内置命令可以执行此操作,但执行以下操作是安全的:

    git checkout master
    git branch -d bug-fix-a
    

    当您使用 -d 时,git将拒绝删除分支,除非它完全合并到 HEAD 或其上游远程跟踪分支 . 因此,您可以始终循环 git for-each-ref 的输出并尝试删除每个分支 . 这种方法的问题是我怀疑你可能不希望 bug-fix-d 被删除只是因为 origin/bug-fix-d 包含它的历史 . 相反,您可以创建类似以下内容的脚本:

    #!/bin/sh
    
    git checkout master &&
    for r in $(git for-each-ref refs/heads --format='%(refname:short)')
    do
      if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
      then
        if [ "$r" != "master" ]
        then
          git branch -d "$r"
        fi
      fi
    done
    

    警告:我没有测试过这个脚本 - 只能小心使用...

  • 10

    这将删除除本地主引用和当前正在使用的引用之外的所有合并本地分支:

    git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d
    

    这将删除已从“origin ", but are still locally available in " remotes / origin”引用的远程存储库中删除的所有分支 .

    git remote prune origin
    
  • 12

    可能对某些简单的一行有用,可以清除除master和develop之外的所有本地分支

    git branch | grep -v "master" | grep -v "develop" | xargs git branch -D
    
  • 10

    根据上面的信息,这对我有用:

    git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`
    

    它会删除远程 ': gone] ' 的所有本地分支 .

  • 5

    还有另一个答案,从https://stackoverflow.com/a/48411554/2858703(我喜欢它,因为它似乎消除了 gone] 将在 git branch 输出中匹配的任何模糊性),但添加* nix弯曲:

    git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" \
      | sed 's,^refs/heads/,,;/^$/d' \
      | xargs git branch -D
    

    我把这个包裹在我路径上的 git-gone 脚本中:

    #!/usr/bin/env bash
    
    action() {
      ${DELETE} && xargs git branch -D || cat
    }
    
    get_gone() {
      git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" \
        | sed 's,^refs/heads/,,;/^$/d'
    
    }
    
    main() {
      DELETE=false
      while [ $# -gt 0 ] ; do
        case "${1}" in
          (-[dD] | --delete) DELETE=true ;;
        esac
        shift
      done
      get_gone | action
    }
    
    main "${@}"
    

    NB - --format选项似乎相当新;我需要将git从2.10.something升级到2.16.3才能获得它 .

  • 25
    grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d
    

    上面的命令可用于获取在远程中合并和删除的分支,并删除远程不再可用的本地分支

  • 0

    这些都不适合我 . 我想要一些东西可以清除跟踪远程分支的所有本地分支,在 origin 上,远程分支已被删除( gone ) . 我不想删除从未设置过跟踪远程分支的本地分支(即:我的本地开发分支) . 此外,我想要一个简单的单行程序,只使用 git 或其他简单的CLI工具,而不是编写自定义脚本 . 我最终使用了一些 grepawk 来制作这个简单的命令 .

    这最终导致了我的 ~/.gitconfig

    [alias]
      prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D
    

    这是一个 git config --global ... 命令,可以轻松地将其添加为 git prune-branches

    git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'
    

    注意:在config命令中,我使用 -d 选项来 git branch 而不是 -D ,就像我在实际配置中一样 . 我使用 -D 因为我不想听到Git抱怨未合并的分支 . 您可能也想要这个功能 . 如果是这样,只需在该config命令的末尾使用 -D 而不是 -d .

  • 1

    我想出了这个bash脚本 . 它总是保留分支 developqamaster .

    git-clear() {
      git pull -a > /dev/null
    
      local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
      branches=(${branches//;/ })
    
      if [ -z $branches ]; then
        echo 'No branches to delete...'
        return;
      fi
    
      echo $branches
    
      echo 'Do you want to delete these merged branches? (y/n)'
      read yn
      case $yn in
          [^Yy]* ) return;;
      esac
    
      echo 'Deleting...'
    
      git remote prune origin
      echo $branches | xargs git branch -d
      git branch -vv
    }
    
  • 0

    这对我有用:

    git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
    
  • 214

    我不确定多久,但我现在使用git-up来处理这个问题 .

    我做 git up 并开始跟踪新分支并删除旧分支 .

    为了说清楚,它不是开箱即用的git命令 - https://github.com/aanand/git-up

    顺便说一句,它还存放了肮脏的树,并且只使用 git up 进行了折扣 .

    希望它对某人有用

  • -3

    这是我用于鱼壳的解决方案 . 在 Mac OS X 10.11.5fish 2.3.0git 2.8.3 上测试过 .

    function git_clean_branches
      set base_branch develop
    
      # work from our base branch
      git checkout $base_branch
    
      # remove local tracking branches where the remote branch is gone
      git fetch -p
    
      # find all local branches that have been merged into the base branch
      # and delete any without a corresponding remote branch
      set local
      for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print $1}')
        set local $local $f
      end
    
      set remote
      for f in (git branch -r | xargs basename)
        set remote $remote $f
      end
    
      for f in $local
        echo $remote | grep --quiet "\s$f\s"
        if [ $status -gt 0 ]
          git branch -d $f
        end
      end
    end
    

    几点说明:

    确保设置正确的 base_branch . 在这种情况下,我使用 develop 作为基本分支,但它可以是任何东西 .

    这部分非常重要: grep -v "\(master\|$base_branch\|\*\)" . 它确保您不删除主分支或基本分支 .

    我使用 git branch -d <branch> 作为额外的预防措施,以便不删除任何尚未与上游或当前HEAD完全合并的分支 .

    一种简单的测试方法是将 git branch -d $f 替换为 echo "will delete $f" .

    我想我还应该补充一点:使用自己的风险!

  • 1

    我用一个简短的方法来做这个伎俩,我建议你做同样的事情,因为它可以节省一些时间,并提供更多的可见性

    只需将以下代码段添加到.bashrc(macos上的.bashprofile)即可 .

    git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
    

    获取所有遥控器只从git获取合并的分支从此列表中删除“protected / important”分支删除其余分支(例如,干净和合并的分支)

    您必须编辑grep正则表达式才能满足您的需求(这里,它会阻止master,preprod和dmz的删除)

  • 2

    基于Git Tip: Deleting Old Local Branches,看起来类似于jason.rickman's solution我使用Bash实现了一个名为git gone的自定义命令:

    $ git gone
    usage: git gone [-pndD] [<branch>=origin]
    OPTIONS
      -p  prune remote branch
      -n  dry run: list the gone branches
      -d  delete the gone branches
      -D  delete the gone branches forcefully
    
    EXAMPLES
    git gone -pn    prune and dry run
    git gone -d     delete the gone branches
    

    git gone -pn 结合了修剪和列出"gone"分支:

    $ git gone -pn
      bport/fix-server-broadcast         b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
      fport/rangepos                     45c857d15 [origin/fport/rangepos: gone] Bump modules
    

    然后,您可以使用 git gone -dgit gone -D 来触发触发器 .

    注意事项

    • 我使用的正则表达式是 "$BRANCH/.*: gone]" ,其中 $BRANCH 通常是 origin . 如果您的Git输出已本地化为法语等,这可能不起作用 .

    • Sebastian Wiesner也将它移植到Rust用户身上 . 那个也被称为git gone .

  • 59

    只需再次删除项目和git clone .

  • 5

    这将删除本地不存在的所有远程分支(在ruby中):

    bs = `git branch`.split; bs2 = `git branch -r | grep origin`.split.reject { |b| bs.include?(b.split('/')[1..-1].join('/')) }; bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }
    

    解释:

    # local branches
    bs = `git branch`.split
    # remote branches
    bs2 = `git branch -r | grep origin`.split
    # reject the branches that are present locally (removes origin/ in front)
    bs2.reject! { |b| bs.include?(b.split('/')[1..-1].join('/')) }
    # deletes the branches (removes origin/ in front)
    bs2.each { |b| puts `git  push origin --delete #{b.split('/')[1..-1].join('/')}` }
    
  • 338

    我使用这种方法,所以我可以有更多的控制权 .

    git branch -D $(git branch | grep -v "master" | grep -v "develop")

    这将删除任何未命名的分支: masterdevelop .

相关问题