0

Origin of repo I'm working on has hundreds of branches.

I ran a git fetch by accident once and now I have hundreds of remote tracking branches.

I want to delete all the remote tracking branches. I don't want to delete the branches on origin, only the remote tracking branches on my local environment. I also have local branches which I'm managing and don't want the remote tracking branches of my local branches to be deleted.

How do I do this?

syclee
  • 697
  • 7
  • 18
  • Note that for your Git to remember, say, 1000 branches from the remote, whose names average 17 characters long (`origin/` plus 10 more characters), requires only about 72,000 bytes of storage in the `.git/packed-refs` file (40 bytes of SHA-1, a space, `refs/remotes/origin/`, newline). On the other hand the `git branch -r` output is eye-watering. :-) – torek Feb 15 '18 at 01:09
  • @torek yes it is mainly for my git log to look more manageable – syclee Feb 15 '18 at 17:50

2 Answers2

1
{ git for-each-ref refs/heads --format='delete %(upstream)';
  git for-each-ref refs/remotes --format='delete %(refname)';
} | grep ^delete\ refs/remotes | sort | uniq -u | git update-ref --stdin

So that generates delete-the-ref commands for every branch's upstream and for every remote-tracking ref. Any duplicate remotes are some branch's upstream, don't want to delete those (edit: and don't want to delete local upstreams!), so grep ^refs/remotes | sort | uniq -u outputs only the remotes that don't show up in both lists. git update-ref --stdin actually has a little command language to handle monster batches of updates like this efficiently.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • I'd use `(...) | grep ...` rather than `{ ...; } | grep ...` since it saves a few characters of typing and the pipe is going to force the brace-sequence to fork at least once anyway. Many `sort` commands can do `uniq -u` directly as well, as `sort -u`. But overall, that looks like the way to do this. – torek Feb 15 '18 at 17:56
  • @torek sort's `-u` will print one record for each distinct key encountered, `uniq -u` only prints lines that occur exactly once. – jthill Feb 15 '18 at 18:29
  • np, two heads better because stuff like this, thanks. – jthill Feb 15 '18 at 19:21
0

On MacOS the following shell script deletes all the remote tracking branches if a corresponding local branch does not exist. (modified script from this answer)

branch_not_delete=( "master" "develop")

for branch in `git for-each-ref refs/remotes/origin --format '%(refname:short)' | grep -v HEAD`;  do
    branch_name="$(awk '{gsub("origin/", "");print}' <<< $branch)"
    local_exists="$(git rev-parse --verify $branch_name 2> /dev/null)"

    if [[ -z "${local_exists// }" ]]; then
      if ! [[ " ${branch_not_delete[*]} " == *" $branch_name "* ]]; then
        git branch -d -r origin/$branch_name
      fi
    fi
done
syclee
  • 697
  • 7
  • 18