Git ghost commits

A commit was reverted at work. The commit was present in the repository history, but there was no trace of it in the Github file history log.

A file history log (for a.txt as an example here) looked like that:

$ git log --oneline -- a.txt 
be9d26c (test-branch) 3 - test-branch
689ae1c 1

However we knew there were more commits on that file between 689ae1c and be9d26c, but we didn’t find it in Github or using git log

Finding the commit

At the time, the repository history looked like that (logs taken from the repository created below):

$ git log --oneline
0f0ad15 (HEAD -> main) Merge branch 'test-branch'
be9d26c (test-branch) 3 - test-branch
076dc52 Revert "2"
d779068 2
689ae1c 1

I expected the history to also have commits d779068 and 076dc52 in the file history, between commits 689ae1c and be9d26c.

Using git log --full-history --oneline -- a.txt (still using a.txt as the file name) didn’t list the commit, but using the --full-history option worked:

$ git log --full-history --oneline -- a.txt
0f0ad15 (HEAD -> main) Merge branch 'test-branch'
be9d26c (test-branch) 3 - test-branch
076dc52 Revert "2"
d779068 2
689ae1c 1

Reproducing the behavior

To try to understand the behavior, I tried to reproduce it by creating a fresh repository:

$ git init repo-test # Create an empty repository
$ cd repo-test
$ echo "1" > a.txt # Create a.txt with the content 1
$ git add a.txt
$ git commit -m "1" # Commit the file
$ echo "2" > a.txt # Update a.txt with the content 2
$ git add a.txt
$ git commit -m "2" # Commit the updated file
$ git revert HEAD # Revert previous commit

At this point, the file has all the commits, even without using --full-history:

$ git log --oneline -- a.txt      
c935f73 (HEAD -> titi) Revert "2"
d779068 2
689ae1c 1

However, in my case, the history also had a merge commit from another branch, let’s try it:

$ git checkout 689ae1c -b test-branch # Create a branch from the first commit
$ echo "3" >> a.txt # Append a.txt with 3
$ echo "3" > b.txt # Create a.txt with the content 3
$ git add a.txt b.txt
$ git commit -m "2" # Commit the updated files
$ git switch main # Going back to the main branch
$ git merge test-branch --no-ff # Create a merge commit from test-branch to main

The full history is available on Github.

And then let’s view the file history for a.txt:

git log --oneline -- a.txt
be9d26c (test-branch) 3 - test-branch
689ae1c 1

Ha! Commits d779068 and c935f73 are not listed! See on Github.

They appear as expected with --full-history:

$ git log --full-history --oneline -- a.txt
0f0ad15 (HEAD -> main) Merge branch 'test-branch'
be9d26c (test-branch) 3 - test-branch
076dc52 Revert "2"
d779068 2
689ae1c 1

The repository is available here.

Conclusion

It seems those “ghost commits” (I don’t have a better name for commits that are here but not displayed) are triggered when:

  • commits on a single file cancel each other
  • a merge commit is added after the revert, having an ancestor before the revert
  • the merge commit has to include a branch that also modifies the file itself, otherwise all the commits will be displayed

Git is tricky… I guess it just hides commits that amount to no changes after a merge commit (?), and I still don’t understand that behavior…