There are many threads on this website that discuss the advantages of
git fetch --prune
and I really like it. But I locally have several branches that I do not want to push as well, which means that there are branches which don't exist anymore on remote repo and there are branches which never existed there. The former I want to delete, the latter I want to keep. Of course git can not know which ones I want to keep. But I haven't found a (simple) interactive way to prune the branches branch by branch. I think about some simple mechanism like
rm -i
with which I can delete files via file by file in Linux shells
The only solution I can think of is to write a script to do a dry-run of git fetch prune, then ask me branch by branch to delete it manually with git branch delete command. Since I am not very good at writing safe and clean scripts (talking about Linux shells, not Windows here, but the general question is relevant for any OS where git is supported)
Yes, I could push all my local branches as well, but we already have a big number of branches (although we use the rebase and delete featurebranch mechanism) that clutter visual representations of our remote repo.
Any ideas appreciated, thanks in advance,
br
I tried:
git fetch --prune
and
git branch --delete
but git fetch prune deletes too many branches at once and git branch delete is rather slow and overly complicated to use for a bigger number of branches, since I need to know and delete all relevant branches manually.
CodePudding user response:
You can do a script First you get all branches without upstream
Then if y is pressed you deleted it else you skip it
#!/bin/bash
for branch in $(git for-each-ref --format='%(refname:short) %(upstream)' refs/heads | awk '$2 !~/^refs\/remotes/'); do
read -n 1 -r -s -p "Are you sure you want to delete $branch? <y/N>" prompt
if [[ $prompt == "y" ]]
then
echo -e "\r$branch \033[31mdeleting...\033[0m\033[0K"
git branch -d $branch
echo -e "$branch \033[31mdeleted\033[0m"
else
echo -e "\r$branch \033[32mkept\033[0m\033[0K"
fi
done
\r
is to go back to the line (erase the prompt question), delete actions are in red \033[31m
, kept in green \033[32m
\033[0m
to go back to normal color and \033[0K
to erase remaining stuff on the line (from the prompt)
CodePudding user response:
You want to make a difference between "the local branches that have an upstream branch" (which I'll call linked) and "the local branches that don't" (which I'll call unlinked).
The issue of running git fetch --prune
is: this action also cleans up the existing links, so after running git fetch --prune
, the linked branches that you want to delete will be seen as unlinked.
You would have to write a script that spots the branches about to be pruned without running git fetch --prune
.
You can get an up to date list of branches that exist on the remote using git ls-remote
:
git ls-remote origin "refs/heads/*"
# to get just the ref names:
git ls-remote origin "refs/heads/*" | awk '{ print $2 }'
# to print 'origin/[name]' instead of 'refs/heads/[name]':
git ls-remote origin "refs/heads/*" | awk '{ gsub("refs/heads/","origin/",$2); print $2 }'
There are several ways to get the list of your local branches that have an upstream branch, one would be to grep your way out of git branch -vv
, for scripting purposes git for-each-ref
is more indicated:
git for-each-ref --format="%(upstream:short) %(refname:short)"` | grep "^origin/"
Combining these in a script to get the list of "linked branches that need to be deleted":
#!/bin/bash
list_remote_branches () {
git ls-remote origin "refs/heads/*" | awk '{ gsub("refs/heads/","origin/",$2); print $2 }'
}
list_linked_local_branches () {
git for-each-ref --format="%(upstream:short) %(refname:short)" | grep "^origin/"
}
# details:
# - list local linked branches
# - use 'grep -v' to remove from that list the ones that are still linked
# - print only the local name
list_linked_local_branches | grep -v -f <(list_remote_branches) | awk '{ print $2 }'
You can either review the list of branches to delete, or use xargs
feed it directly to git branch --delete
:
# the '-r' option makes sure that nothing is run if the input is empty
./my_script.sh | xargs -r git branch --delete