1027

I work from two different computers (A and B) and store a common git remote in the dropbox directory.

Let's say I have two branches, master and devel. Both are tracking their remote counterparts origin/master and origin/devel.

Now while on computer A, I delete branch devel, on local and remote.

git push origin :heads/devel git branch -d devel 

Running git branch -a on computer A, I get the following list of branches.

  • master
  • origin/HEAD
  • origin/master

Running git fetch on computer B, I can remove the local devel branch with git branch -d devel, but I can't remove the remote devel branch.

git push origin :heads/devel returns the following error messages.

error: unable to push to unqualified destination: heads/proxy3d
The destination refspec neither matches an existing ref on the remote nor begins with refs/, and we are unable to guess a prefix based on the source ref.
fatal: The remote end hung up unexpectedly

git branch -a still lists origin/devel in the remote branches.

How can I clean up the remote branches from computer B?

4
  • 5
    I've been told by one who tried it, that git repositories in Dropbox folders are a bit fragile (but without additional details). Commented Apr 19, 2013 at 9:23
  • 5
    @ThorbjørnRavnAndersen probably because you have to wait to ensure it syncs completely whenever you commit, before you can be sure it's safe to use on the other machine (and another sync required even then). Commented Aug 1, 2013 at 14:54
  • 1
    I also had lots of issues with OneDrive when my company added it automatically. Don't have git repo on OneDrive folder! Commented Jan 3, 2022 at 10:18
  • This question has a great answer but the question should be renamed. Commented May 30 at 18:57

10 Answers 10

1732

First, what is the result of git branch -a on machine B?

Second, you have already deleted heads/devel on origin, so that's why you can't delete it from machine B.

Try

git branch -r -d origin/devel 

or

git remote prune origin 

or

git fetch origin --prune 

and feel free to add --dry-run to the end of your git statement to see the result of running it without actually running it.

Docs for git remote prune and git branch.

Sign up to request clarification or add additional context in comments.

14 Comments

git remote prune origin worked for me => * [pruned] origin/my-old-branch
git remote prune origin --dry-run shows you what would be deleted w/o actually doing it.
git fetch origin --prune was perfect to remove deleted branches
If you have a local branch tracking a remote that's gone, this won't delete anything. For those, it appears git branch -vv followed by git branch -D branchname and finally the prune is the best way.
You can configure pruning to happen automatically on pull/fetch by setting the following option: git config remote.origin.prune true
|
203

Consider to run :

git fetch --prune 

On a regular basis in each repo to remove local branches that have been tracking a remote branch that is deleted (no longer exists in remote GIT repo).

This can be further simplified by

git config remote.origin.prune true 

this is a per-repo setting that will make any future git fetch or git pull to automatically prune.

To set this up for your user, you may also edit the global .gitconfig and add

[fetch] prune = true 

However, it's recommended that this is done using the following command:

git config --global fetch.prune true 

or to apply it system wide (not just for the user)

git config --system fetch.prune true 

3 Comments

equally, git fetch -p
running these commands, then git branch still shows old branches ... also run with git fetch -p -vv shows it doesn't "touch" any old branch
I think you didn't understand the documentation. git fetch --prune only removes remote branches in your local repository. They don't remove local branches that point to a remote branch
62

I'll have to add an answer here, because the other answers are either not covering my case or are needlessly complicated. I use github with other developers and I just want all the local branches whose remotes were (possibly merged and) deleted from a github PR to be deleted in one go from my machine. No, things like git branch -r --merged don't cover the branches that were not merged locally, or the ones that were not merged at all (abandoned) etc, so a different solution is needed.

Anyway, the first step I got it from other answers:

git fetch --prune 

A dry run of git remote prune origin seemed like it would do the same thing in my case, so I went with the shortest version to keep it simple.

Now, a git branch -v should mark the branches whose remotes are deleted as [gone]. Therefore, all I need to do is:

git branch -v|grep "\\[gone\\]"|awk '{print $1}'|xargs -I{} git branch -D {} 

As simple as that, it deletes everything I want for the above scenario.

The less common xargs syntax is so that it also works on Mac & BSD in addition to Linux. Careful, this command is not a dry run so it will force-delete all the branches marked as [gone]. Obviously, this being git nothing is gone forever, if you see branches deleted that you remember you wanted kept you can always undelete them (the above command will have listed their hash on deletion, so a simple git checkout -b <branch> <hash>.

Edit: Just add this alias to your .bashrc/.bash_profile, the two commands made into one and I updated the second to work on all shells:

alias old_branch_delete='git fetch -p && git branch -vv | awk "/: gone]/{print \$1}" | xargs git branch -D' 

Comments

19

This command will "dry run" delete all remote (origin) merged branches, apart from master. You can change that, or, add additional branches after master: grep -v for-example-your-branch-here |

git branch -r --merged | grep origin | grep -v '>' | grep -v master | xargs -L1 | awk '{sub(/origin\//,"");print}'| xargs git push origin --delete --dry-run 

If it looks good, remove the --dry-run. Additionally, you may like to test this on a fork first.

1 Comment

Nice. My tweak using perl instead of the 1st xargs + awk: git branch -r --merged | grep origin | grep -v '>' | grep -v master | perl -lpe '($junk, $_) = split(/\//, $_,2)' | xargs git push origin --delete
14

Here is bash script that can do it for you. It's modified version of http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git script. My modification enables it to support different remote locations.

#!/bin/bash current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/') if [ "$current_branch" != "master" ]; then echo "WARNING: You are on branch $current_branch, NOT master." fi echo -e "Fetching merged branches...\n" git remote update --prune remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$") local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$") if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then echo "No existing branches have been merged into $current_branch." else echo "This will remove the following branches:" if [ -n "$remote_branches" ]; then echo "$remote_branches" fi if [ -n "$local_branches" ]; then echo "$local_branches" fi read -p "Continue? (y/n): " -n 1 choice echo if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u` # Remove remote branches for remote in $remotes do branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'` git push $remote $branches done # Remove local branches git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'` else echo "No branches removed." fi fi 

2 Comments

This broke on a branch called "origin/feature/mybranch", I'm not sure why.
Problem is in the two seds. Replace sed 's/\(.*\)\/\(.*\)/\1/g' by sed 's/\([^/]*\)\/\(.*\)/\1/g'
13

If git branch -r shows a lot of remote-tracking branches that you're not interested in and you want to remove them only from local, use the following command:

git branch -r | grep -Ev 'HEAD|master|develop' | xargs -r git branch -rd 

A safer version would be to only remove the merged ones:

git branch -r --merged | grep -Ev 'HEAD|master|develop' | xargs -r git branch -rd 

This might be useful for large projects, where you don't need the feature branches of other teammates but there're lots of remote-tracking branches fetched upon the initial clone.

However, this step alone is not sufficient, because those deleted remote-tracking branches would come back upon next git fetch.

To stop fetching those remote-tracking branches you need to explicitly specify the refs to fetch in .git/config:

[remote "origin"] # fetch = +refs/heads/*:refs/remotes/origin/* ### don't fetch everything fetch = +refs/heads/master:refs/remotes/origin/master fetch = +refs/heads/develop:refs/remotes/origin/develop fetch = +refs/heads/release/*:refs/remotes/origin/release/* 

In the above example we only fetch master, develop and release branches, feel free to adapt as you need.

4 Comments

Thanks, first command worked for me. You can also fetch only one branch with git fetch origin branchname or create an alias like ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f" to fetch only the current branch (my personal favorite). Cheers.
Maybe OT but what does the -r flag means? I see xargs has a -R argument but didn't find anything about -r. I mean, in theory if I remember correctly how xargs works, even without -r it should work.
I like this answer. A couple of notes (stating the obvious really). It's possible to "preview" which branches are going to be deleted by removing the last pipe and last command | xargs git branch -d. Also, by removing the -r option (--remotes) from git branch -d we only clean the local branches (which may be enough considering that by default git branch doesn't show remote branches anyway).
Thanks! This was exactly what i needed. Other solutions suggest pushing pruned local branches to the remote to remove them there as well, but that doesn't help when the remote has been removed or no longer exists. This approach removed the local references to the remote branches i no longer have access to.
9

Answer using powershell

For anyone who is using powershell. The following made my life easier.

First, as suggested by other answers:

git fetch --prune 

Then to get the lines from branch -v that do not have a remote branch anymore:

git branch -v | findstr "gone" > .\branches.txt 

And finally to delete the branches (use it with -D on your own risk):

Get-Content .\branches.txt | ForEach-Object { git branch -d (($_.Trim() -split '\s+')[0]) } 

You can probably make a one liner, but I like the option to check which branches are going to be deleted.

(Powershell version: 7.3.6)

1 Comment

Thanks! Cleaned up dozens of local bugfix branches that have long been deleted on the server.
6

Deletion is always a challenging task and can be dangerous!!! Therefore, first execute the following command to see what will happen:

git push --all --prune --dry-run 

By doing so like the above, git will provide you with a list of what would happen if the below command is executed.

Then run the following command to remove all branches from the remote repo that are not in your local repo:

git push --all --prune 

8 Comments

This command appears to be dangerous... It managed to delete what I wanted (and could not do with at least four of the answers above). But it also deleted four other dev-branches. Git absolutely sucks...
Those branches must have not been on your local. However all is not lost. Git commit, Git reflog and then git reset --hard <checksum>. You can literally to any commit(aka save) and others with this. Branch is just a label, deleting the label does not delete the save... it will forever have a checksum. Let me know if I can help
Of course, you'll want to recover these pretty quickly since git's garbage collector will eventually remove commits not referenced by branches.
It's good to add -n (dry run) to this command so you can preview changes and then if everything is fine call it again without -n.
This is bad advice. ^^
|
4

Here is how to do it with SourceTree (v2.3.1):
1. Click Fetch
2. Check "Prune tracking branches ..."
3. Press OK
4. 😀

enter image description here

Comments

3
# First use prune --dry-run to filter+delete the local branches git remote prune origin --dry-run \ | grep origin/ \ | sed 's,.*origin/,,g' \ | xargs git branch -D # Second delete the remote refs without --dry-run git remote prune origin 

Prune the same branches from local- and remote-refs(in my example from origin).

1 Comment

combined into a shell alias alias git-prune-origin="git remote prune origin --dry-run | grep origin/ | sed 's,.*origin/,,g' | xargs git branch -D; git remote prune origin"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.