Antimony
Antimony

Reputation: 39451

Git branch not showing [gone] for missing remotes

I've been trying to find a way to delete local git branches with no upstream branch, but none of the answers in the linked question worked for me. It seems that they all rely on git branch -vv outputting gone] for branches with no remote, but it does not do so for me, and I can't figure out why.

For example, after running get fetch --prune, git branch -vv shows the branch rsg/revert with no [gone] tag.

  rsg/revert                       af2c4ac81e Remove temporary debug logging

However, there is no corresponding origin/rsg/revert branch (I already deleted it on Github). Does anyone know why this isn't working?

Edit: I'm using git 2.15.0 on a Mac. I've never had issues with it before.

Upvotes: 9

Views: 1807

Answers (3)

Anutrix
Anutrix

Reputation: 273

As mentioned in other answers, the word gone does not show up if there's no upstream set for the branches.

I fixed this by detecting ] instead of gone.

NOTE: This will also delete branches whose commit messages have ]. So make sure none of the branches you want to keep have it.

git branch -vv | grep -v ']'|  grep -v "\*" | awk '{ print $1; }' | xargs git branch -d

Change -d in the command to -D if you want to delete unmerged branches too:

git branch -vv | grep -v ']'|  grep -v "\*" | awk '{ print $1; }' | xargs git branch -D

Upvotes: 0

Jonathan Simonney
Jonathan Simonney

Reputation: 665

In case anyone here needs it, the solution I used was a combination of several others answers found on SO.

For the branch that DO have an upstream, the question linked in current question works perfectly.

As for the branch that LACK such upstream, I went with a variation of this answer.

Here is the modified code snippet which I used :

#! /bin/sh
#
# rm-if-gone: remove branches that have a configured upstream
# where the configured upstream no longer exists.  Run with
# -f to make it work, otherwise it just prints what it would
# remove.
force=false
case "$1" in
-f) force=true;;
esac

for branch in $(git for-each-ref --format='%(refname:short)' refs/heads); do
    # find configured upstream, if any
    remote=$(git config --get branch.$branch.remote) || true
    # if tracking local branch, skip
    if [ "$remote" = . ]; then continue; fi
    # if the upstream commit resolves, skip
    ucommit=$(git rev-parse "${branch}@{u}" 2>/dev/null) && continue
    # upstream is invalid - remove local branch, or print removal
    $force && git branch -D $branch || echo "git branch -D $branch"
done

The modification that was done occurs in the first ||, when we get the remote. In case no remote is found, the linked answer leaves the branch AS IS. That's exactly the case we're interested in, we want to SUPPRESS thewse branch. Therefore, we output true, so the line doesn't end up in an exit code.

Be warned that this solution will suppress ANY branch on local that isn't linked to a remote (this includes branches you started but didn't push yet), so use accordingly, and don't hesitate to run first without the -f option.

Hoping this helps someone.

Upvotes: 2

torek
torek

Reputation: 487755

Your Git is new enough and you've run git fetch --prune, so there's only one conclusion left: rsg/revert has the wrong upstream or no upstream at all.

To see the upstream setting—or get an error if there is none—use git rev-parse like this (note that some shells may require quoting the curly braces):

git rev-parse --abbrev-ref rsg/revert@{u}

For example:

$ git rev-parse --abbrev-ref master@{u}
origin/master
$ git rev-parse --abbrev-ref dev@{u}
fatal: no upstream configured for branch 'dev'

The upstream of my master here is origin/master, but there is no upstream set for my dev.

The git branch -vv output will include the word gone in square brackets if and only if:

  • the branch has an upstream set, and
  • the upstream that is set for that branch no longer refers to a valid name.

So if I somehow delete origin/master from my own Git repository (which I can do with various Git maintenance commands, or with git branch -d -r origin/master) I will get:

$ git branch -d -r origin/master
Deleted remote-tracking branch origin/master (was 08da6496b6).
$ git branch -vv
  dev             9c9b961d7e The sixth batch
* master          08da6496b6 [origin/master: gone] Eighth batch

(I then ran git fetch to pick up new commits and re-create my origin/master, which is now f21f8f5d35 instead of 08da6496b6.)

Given that you had GitHub delete rsg/revert and then ran a git fetch -p that deleted origin/rsg/revert, your rsg/revert branch must something else, or nothing, as its upstream.

Upvotes: 7

Related Questions