3

I have branches Branch-Master, Branch-A, Branch-B, Branch-C on GitHub. I usually merge into master and delete the merged branch. This leaves a bunch of branches on my local machine, but not GitHub.

How do I automatically remove my local branches automatically? I want to create a git hook to do this.

When I try

git remote prune origin

and then run git branch, I still see all my branches, even the ones merged and deleted into master.

I know I can do

git branch -d {the_local_branch}

manually, but this does not help when doing a githook or I have multiple branches to remove systematically.

What I don't like about the answers given here: How can I delete all Git branches which have been merged?

Is that they are based off names, and inferring the deleted branch, rather than somehow explicitly passing a branch id, specific to that branch. What I understand in the link provided, is that if I create a branch name that is the same as the deleted branch, it will also be deleted, even though they are different branches.

How do I delete a Git branch locally and remotely?

Does not address my inquiry, as it's solution is already stated above.

I would rather have some type of compare function using branch uid's if they exist.

user2012677
  • 4,475
  • 4
  • 27
  • 70
  • Updated question, to show difference from both links – user2012677 May 09 '19 at 14:56
  • 1
    There is no way to do that automatically. There are no hooks for `git fetch/pull`. There is no such thing as *branch uid*: branch is a name and a pointer to a commit and nothing more. – phd May 09 '19 at 15:45
  • The only way this can be done is with a script. Are you using Linux or Windows? I will hate to create the script for the wrong OS! :) – Antoan Milkov May 09 '19 at 17:22

2 Answers2

0

You can delete all branches at one go (except the one which is checked out) by one single command:

git branch --list | xargs git branch -D

If you want to specify some pattern to match the branch name, you can do that too:

git branch --list k* | xargs git branch -D

And with the help of

git remote prune origin

you can delete remote branches in your system that are no longer referenced.

Hope this helps !

Krantisinh
  • 1,357
  • 8
  • 13
0

As phd noted in a comment, there is no underlying ID for branches. A branch name is simply a local name in your repository, created by you or at your request, that identifies one specific commit. You can change this name any time, to any string you like as long as it meets the requirements for a branch name. Git won't remember that it used to have some other name.

Now, there are a few additional bits of information: your .git/config file can, and usually will, have in it, for each branch, some annotations such as:

[branch "master"]
    remote = origin
    merge = master

[branch "develop"]
    remote = another-remote
    merge = develop

These settings define the upstream setting of the branch. A branch can have no upstream at all—in which case the two settings are non-existent—or one upstream, in which case the two settings exist and describe the upstream, using the two parts from the old historical method of dealing with this before remote-tracking names were invented.

These configuration sections will automatically get renamed if you use standard Git commands to rename the branch. For instance, after git branch -m develop xyz, you will have:

[branch "xyz"]
    remote = another-remote
    merge = develop

which means that the upstream of your local branch xyz is another-remote/develop. (This assumes a standard fetch = setting for remote another-remote.)

It's possible, with some effort, to read through the upstream setting (if any) of each branch: use git for-each-ref to enumerate all branches, and then, for each branch, use git rev-parse --symbolic-full-name <branch>@{upstream} to see if it has an upstream, and if so, what the upstream name is. Note that you must be a little bit careful here as the "remote" can be set to ., indicating that the upstream of some local branch is another local branch.

Combining this kind of programmatic test ("does branch X have an upstream, and if so, is it actually a remote-tracking name, and what remote-tracking name is it?") with a second test ("after using git remote <remote> prune or git fetch <remote> --prune, does the remote-tracking name exist?") may get you what you want. You'll need to do some coding (bash scripting, for instance). Making it optimal, or work from within a hook, is hard, but the overall task is pretty straightforward:

git for-each-ref --format='%(refname:short)' refs/heads |
while read branch; do
    # make sure it has an upstream set -- if not, ignore
    upstream=$(git rev-parse --symbolic-full-name ${branch}@{upstream}) || continue
    # make sure the upstream is a remote-tracking name
    case $upstream in
    refs/remotes/*) ;;
    *) continue;;
    esac
    # get the name of the remote
    remote=${upstream#refs/remotes/}
    remote=${remote%%/*}
    # prune remote-tracking branches
    git remote $remote prune
    # and test whether the upstream still exists
    git rev-parse $upstream && continue

    # $branch has upstream $upstream which is gone, so:
    echo git branch -D $branch
done

This is quite untested, and is missing important bits like keeping it quiet about branches it's not going to delete (each rev-parse will spew messages to stdout and/or stderr). It also doesn't actually delete any branches: since that can be rather irrecoverable, so one would want to test it thoroughly first, and only then remove the echo.

torek
  • 330,127
  • 43
  • 437
  • 552
  • I thought you could undelete a branch? I noticed in Github that undelete was an option of a merged branch, so why is a delete irrecoverable? – user2012677 May 09 '19 at 19:22
  • @user2012677: You can create a *new* branch, pointing to the same commit as before, but you lose the `[branch "..."]` section from the `.git/config` *and* the reflog. There's progress (slowly) in Git to add "branch undelete" but it's not there yet. GitHub's interface is not Git's. – torek May 09 '19 at 19:26
  • so is GitHub not actually deleting my branch? – user2012677 May 09 '19 at 19:28
  • @user2012677: GitHub's web interface does whatever they've programmed it to do. Who knows what that is! (Well, GitHub know, of course ... they just don't *tell* us.) In any case they don't offer reflogs, nor upstream settings, so they have a simpler task. – torek May 09 '19 at 19:30