Git lost commits cannot be found in history
We have a couple of developers working on a shared git repository (they push this).
We found that some of the commits made by the developer are lost.
We can view the commit history using the command gitk
(using on Windows).
But when we go that the file indicated in the commit shown in gitk and view the history with git log filepath
, we don't see that commit at all.
We do not know how this can happen, and we do not know how to recover.
We think over 10 commits from different developers are lost this way.
One of the weird things, we checked out some old commits using git checkout 034534fd
and committed git cherry-pick 234234321
one at a time. With this we got our lost commits, but nothing shows up in the commit log "234234321" about the affected files.
source to share
I am a little confused by your question. Are you saying that you can see commits in gitk
, but not with git log -- filepath
?
If so, your commits are not lost; git log
simplifying the story hides them from you because it thinks they are not interesting. If you pass an argument --full-history
to git log
, you should see them.
Description
By default, when you execute git log -- filepath
, Git will not show you the changes in that file if Git thinks the change is uninteresting. This is called "history simplification". This often happens with cherries.
The documentation on simplifying history (see git help log
) is not well written (extremely difficult to understand), but here are the key parts:
Default mode
Simplifies the story to the simplest story, explaining the final state of the tree. Easiest because it truncates some side branches if the end result is the same (i.e. merging branches with the same content)
[...]
Entries are included if they are not a TREESAME for either parent (although this can be changed, see below
--sparse
). If the commit was a merge and it was a TREESAME for a single parent, only that parent follows. (Even if there are multiple TREESAME parents, follow only one of them.) Otherwise, follow all parents.
In other words, when Git walks through history looking for commits that change filepath
and encounter a merge commit, it doesn't always go through all the parents of the merge. He often chooses only one parent and only walks with those parental ancestors. This means that you will not see a commit modifying that file if the commit is on one of the other branches.
The argument --full-history
tells it git log
to walk through all the parents, thus displaying every commit that modified filepath
, whether Git finds it interesting or not.
source to share
This could have happened either by committing to a separate head, or by deleting the branch on which the commits were committed.
If you see lost commits in the reflog or rev-list, the simplest is to recreate the branch whose hint is on the most recent commit:
git branch recovered <most-recent-SHA1>
It's important to provide the SHA1 of the most recent commit you want to get, or the more recent ones won't show up.
The commits are now on a named branch recovered
, so you can see them in your log. You will most likely want to merge or rebase the branch recovered
.
source to share
Until you run garbage collection on your local repository and have a git reflog, a new branch is created based on the latest SHA-1. If not, there are extensions for enterprise git servers like Gerrit that will do things that will use your branch history. If a branch is deleted or updated in a non-transient way (push -f), it returns the previous version under a special ref so that they can be reclaimed if needed and will not be garbage collected. Gerrit admins can still remove selected commits if needed for legal reasons.
source to share