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开发者_Go百科 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?
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
.
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
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'
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.
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
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.
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
Here is how to do it with SourceTree (v2.3.1):
1. Click Fetch
2. Check "Prune tracking branches ..."
3. Press OK
4.
精彩评论