Home > Software engineering >  git: How to delete local branches that do not exist in remote repo interactively branch by branch?
git: How to delete local branches that do not exist in remote repo interactively branch by branch?

Time:01-16

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
  • Related