Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List and delete git branches without cloning

Tags:

git

branch

for k in $(git branch -r --merged origin/master | cut -d" " -f 3); do
    echo $k
done

I have a list of git projects that i want to clean up old branches in, what i want to do is list and delete all the branches that are merged to master.

Is there a way to do the above without cloning each repo locally?

like image 457
A.Jac Avatar asked Jan 31 '17 11:01

A.Jac


People also ask

How do you delete branches which are not on remote?

Remove All Local Branches not on Remote First we get all remote branches using the git branch -r command. Next, we get the local branches not on the remote using the egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) command, Finally we delete the branches using the xargs git branch -d command.

How do I delete unused branches in git?

Remove remote Git tracking branches Here is the Git command to remove a local tracking branch: git branch --remotes --delete origin/name-of-branch-to-remove. git branch -r -d origin/name-of-branch-to-remove.

How do I delete all branches?

Newer Git repositories have renamed the master branch to main. To delete all branches in Git except main, simply replace the grep for master with a grep for main: git branch | grep -v "main" | xargs git branch -D. git branch | grep -v " main$" | xargs git branch -D.


1 Answers

You need git ls-remote:

NAME

git-ls-remote - List references in a remote repository

SYNOPSIS

git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]
              [-q | --quiet] [--exit-code] [--get-url]
              [--symref] [<repository> [<refs>...]]

DESCRIPTION

Displays references available in a remote repository along with the associated commit IDs.

So it works like:

% git ls-remote origin
af51dfb080728117d898e1d0a10e3fe01ed67063        HEAD
6a60cc68a2953f1a62b0dca641eb29509b5b6e8c        refs/heads/expdate-fix
af51dfb080728117d898e1d0a10e3fe01ed67063        refs/heads/master
4c42e43b4ccfd37074d115f6e9a694ddb8b70d55        refs/heads/redux
fd18a67bbc5cbf8aa6cda136afa4e5c20ed2d522        refs/heads/rest
7ad17cdf8b0dcd1a29a1795a363279fb3c76ac66        refs/tags/test.key
be0b2d6881902600fb3d6686c10d0a47f1e6751a        refs/tags/test.pub

To get only branches (heads), you need to narrow the refspec down:

% git ls-remote origin 'refs/heads/*'
6a60cc68a2953f1a62b0dca641eb29509b5b6e8c        refs/heads/expdate-fix
af51dfb080728117d898e1d0a10e3fe01ed67063        refs/heads/master
4c42e43b4ccfd37074d115f6e9a694ddb8b70d55        refs/heads/redux
fd18a67bbc5cbf8aa6cda136afa4e5c20ed2d522        refs/heads/rest

Now you could script around this output like

git ls-remote origin 'refs/heads/*' | while read sha ref; do
  # test if $sha is merged
done

To delete a branch, you need to "push nothing" to it, like in

git push origin :refs/heads/feature-x

(notice an empty string to the left of ":" which defined what to push to what is on the right side).

So we get something like

#!/bin/sh
set -e -u
git ls-remote origin 'refs/heads/*' | while read sha ref; do
  # test if $sha is merged
  E=`git cat-file -t "$sha" 2>&1`
  test $? -ne 0 -a "${E#*git cat-file: *}" = "could not get object info" && continue
  git branch --merged "$sha" && printf ':%s\0' "$ref"
done | xargs -0 git push origin

Note that we're using printf shell builtin to delimit the names of the refs we output with the ASCII NUL character and then pass -0 to xargs to expect NUL-terminated input. This way we work around funky ref names (containing spaces etc).

Some explanations:

  • If git cat-file -t <object_sha1_name> fails to locate the object with the indicated SHA1 name in the local repository, it exits with a non-zero exit code and prints

    fatal: git cat-file: could not get object info

    to its stderr.

  • So to test whether the history a remote ref points at exists in the local repository we run git cat-file -t on the SHA1 name of the object it points at, grab the combined output of that command and then test whether it exited with a non-zero exit code ($? -ne 0) and whether its error message indicates a missing object (the ${VAR#PATTERN} removes the prefix matching PATTERN from the contents of the variable VAR and returns the resulting value).

  • If the history a remote ref points at does not exist in the local repository, it cannot be merged to any of the local refs by definition, so if we detect such a ref, we skip its further testing with git branch --merged.

like image 187
kostix Avatar answered Sep 19 '22 16:09

kostix