Reputation: 8965
Git says this:
On branch f-dbmailer
Your branch and 'origin/DBmailer' have diverged,
and have 7 and 43 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
But that information is now out-of-date: I deleted the remote branch altogether, and have confirmed that it is really gone. (So, it doesn't have "43 commits.") The actual remote branch now has the name f-dbmailer
... but Git hasn't forgotten about the old branch, nor apparently the commit count that it used to have.
How do I clear this up?
Upvotes: 1
Views: 1855
Reputation: 14743
The issue you describe certainly comes from the fact a branch has been removed in the remote, while the corresponding remote-tracking branch is still part of your local repository.
As I mentioned in my comment, this situation can be spotted by running the command git fetch
git fetch -p
then git branch -vv
(with two v
, see the example below), but instead of needing to run git branch -d …
manually for each similar branch, the procedure to "cleanup" your local repo can just as well be automated using a Git alias.
git deldone
(relying on Perl)$ git config --global alias.deldone '!f() { git fetch -p && git branch -vv | \
perl -wne '\''print "$1\n" if m/^\s*(\S+)\s+[0-9a-f]+\s+\[\S+: gone\]/;'\'' | \
xargs git branch -d; }; f'
Note that the git fetch
option -p
(for --prune
) is necessary in this alias; see also @torek's answer for more details on this option.
$ git branch -vv
feature 12d22c1 [origin/feature] README.md
fix 275e548 [origin/fix] Fix .gitignore
* master 49b6c4a [origin/master: ahead 2] Merge branch 'fix'
# let's remove branches feature and fix in the remote:
$ git push origin :feature
To github.com:erikmd/demo-branch.git
- [deleted] feature
$ git push origin :fix
To github.com:erikmd/demo-branch.git
- [deleted] fix
# due to the commands above a `git fetch -p` was implied,
# and you then get:
$ git branch -vv
feature 12d22c1 [origin/feature: gone] README.md
fix 275e548 [origin/fix: gone] Fix .gitignore
* master 49b6c4a [origin/master: ahead 2] Merge branch 'fix'
$ git deldone
error: The branch 'feature' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature'.
Deleted branch fix (was 275e548).
$ git branch -vv
feature 12d22c1 [origin/feature: gone] README.md
* master 49b6c4a [origin/master: ahead 2] Merge branch 'fix'
$ git branch -D feature
Deleted branch feature (was 12d22c1).
Note that unlike the fix
branch, the feature
branch was properly detected to be gone upstream, but not removed automatically as Git knew it could lead to data loss, given the branch at stake had not been integrated. (see doc)
Upvotes: 2
Reputation: 489113
Use git fetch --prune
(or set fetch.prune
in a Git configuration file: I set mine globally some years ago and never have to think about it now).
When you run git fetch
or git fetch origin
, your Git calls up another Git, using a remote name such as origin
. That other Git lists out its branch names and their corresponding hash IDs. (It also lists tag names and other names, but the ones we're interested in here are branch names.)
Your Git takes those branch names and renames them, to make your remote-tracking names. This renaming is actually under the control of the remote.origin.fetch
setting in your Git configuration:
$ git config --get remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
The leading plus sign is a force flag: these refs are updated as if you had used git fetch --force
(but other updates aren't, unless you do use git fetch --force
or they too are flagged). The left side of the colon, refs/heads/*
, matches all of the other Git's branch names. The right side of the colon, refs/remotes/origin/*
, provides the renaming: their refs/heads/master
becomes your refs/remotes/origin/master
, for instance.
Now, suppose that you run git fetch
twice, with some time interval in between during which branch names get created and/or deleted in that other Git. The first time you have your Git call their Git, the listing includes:
refs/heads/master
refs/heads/br1
refs/heads/br2
The second time you have your Git call them, the listing doesn't have br2
in it but does have br3
in it:
refs/heads/master
refs/heads/br1
refs/heads/br3
If the commit hash ID for any of these is updated, your Git updates your corresponding remote-tracking name. But br2
just doesn't exist any more. So your refs/remotes/origin/br2
has no new value.
By default, your refs/remotes/origin/br2
keeps its old value. With --prune
in effect, your Git says: Aha, the thing that would create or update origin/br2
is gone, so I should delete origin/br2
entirely ... and it does.
The --prune
option probably should be the default, but it isn't. You can make it your default with:
git config --global fetch.prune true
and now your Git will automatically delete any remote-tracking name that no longer has a corresponding branch name on the remote.
Upvotes: 1