Why does git log —all show removed commits?

Viewed 55

I used git reset —-hard sha on a commit to strip/remove several commits, then did git gc --prune=now. When I do a git log --pretty=oneline --abbrev-commit it returns commits with the latest at the sha I used in the reset command. This is what I’m expecting.

However, I then did git log --pretty=oneline --abbrev-commit —-all and it is returning commits I thought I stripped. Why is this history still here?

ETA: None of these commits exist on a master repo

2 Answers

This is one of those cases where splitting hairs may actually be important.

When you say you "stripped" some commits, that's imprecise. To be more specific, you removed those commits from the history of the branch that was checked out when you gave the reset command. If any other ref (another branch, a tag, the current stash, various other things) could reach those commits, then it still can.

The --all option to git log says to show the history of all refs - not just the current branch (from which you removed the commits). You might be able to use the output of git log --graph --all to sort out which ref(s) still reach your commits. If you can use gitk in your environment, that may be a better visualization.

As an additional note, your gc attempt would've failed even if no refs could still reach the commits in question, because the reflogs can still reach them. After moving all refs so that nothing "knows" of those commits any more, you'll also have to expire any affected reflogs.

The git log command works by starting from some particular commit or set of commits, whose IDs are eventually raw OIDs,1 and then working backwards through the commit graph.2 The OIDs come from arguments given to git log; with no OID arguments and no substitutes for them, the default is to look up HEAD as an OID. So this:

When I do a git log --pretty=oneline --abbrev-commit it returns commits with the latest at the sha I used in the reset command. This is what I’m expecting.

is fine. (Note by the way that --oneline is short for --pretty=oneline --abbrev-commit, so you might want to use this to shorten your command line sequence.)

However, I then did git log --pretty=oneline --abbrev-commit —-all and it is returning commits I thought I stripped. Why is this history still here?

The --all option pretends that all refs/ entries (all references: all branch names, tag names, and other special names that are not the HEAD or *_HEAD special names) were specified on the command line. One or more of those refs must resolve to, or lead to, the hash you thought you stripped.

It's not unusual for refs/stash to do this, for instance, or for some other branch name to do this.

You can run git for-each-ref with no arguments at all to list out all the refs that --all implies.


1It's best not to call these "SHA" now as other hash algorithms are allowed, at least in theory. It's true that the upcoming change is to use SHA2-256, which is still an SHA hash, but the internal Git term is now OID, or Object ID.

2With -g (--walk-reflogs), the walk is through the reflog rather than the commit graph. With --no-walk the walk itself is suppressed, so that you get only the initially-selected OIDs.

Related