Reputation: 632
We have multiple developers working on a shared git repository(they push to this).
We found that some of the commits done by a developer are lost.
We can see those commit history using gitk
command(using in windows).
But when we go that the file specified in the commit shown in the gitk and see the history using git log filepath
we don't see that commit at all.
We don't know how this can happen, and don't know how to recover.
We think more than 10 commits from different developers are lost in this way.
One of the strange thing is, we checked out some old commits using git checkout 034534fd
and done git cherry-pick 234234321
one by one commit. While doing this we got our lost commits, but nothing is shown in the commit log of '234234321' about the affected files.
Upvotes: 5
Views: 9795
Reputation: 79
As long as you have not run garbage collection in your local repository and have git reflog present, creating a new branch based on the most recent SHA-1 will work. If not, there are extensions to enterprise Git servers like Gerrit that will do what will version your branch history. If a branch gets deleted or updated in a non fast forward way (push -f) it will back the previous version under a special ref so that they can be restored if needed and will not be pruned by garbage collection. Gerrit administrators can still remove selected commits if needed for legal reasons.
Upvotes: 1
Reputation: 54273
I'm a little confused by your question. Are you saying that you can see the commits in gitk
but not with git log -- filepath
?
If so, your commits aren't lost; git log
's history simplification is hiding them from you because it thinks they're uninteresting. If you pass the --full-history
argument to git log
you should see them.
By default, when you do git log -- filepath
, Git will not show you changes to that file if Git believes the change is uninteresting. This is called "history simplification". This often happens with cherry-picks.
The documentation on history simplification (see git help log
) is not very well written (extremely hard to understand), but here are the key parts:
Default mode
Simplifies the history to the simplest history explaining the final state of the tree. Simplest because it prunes some side branches if the end result is the same (i.e. merging branches with the same content)
[...]
Commits are included if they are not TREESAME to any parent (though this can be changed, see
--sparse
below). If the commit was a merge, and it was TREESAME to one parent, follow only that parent. (Even if there are several TREESAME parents, follow only one of them.) Otherwise, follow all parents.
In other words, when Git is walking the history looking for commits that change filepath
and encounters a merge commit, it doesn't always walk all parents of the merge commit. It often only picks one parent and walks only that parent's ancestors. This means that you won't see a commit modifying that file if the commit is in one of the other branches.
The --full-history
argument tells git log
to walk all parents, thus showing every commit that modified filepath
whether Git believes it is interesting or not.
Upvotes: 13
Reputation: 90496
This can have happened either by committing in a detached HEAD, or deleting the branch the commits were on.
If you see the lost commits in reflog or rev-list, then the simplest is to re-create a branch whose tip is on last commit:
git branch recovered <most-recent-SHA1>
It is important to provide the SHA1 of the very last commit you want to retrieve, or later ones won't show.
Now commits are in a branch named recovered
, so you can see them in your log. You'll most likely want to merge or rebase the recovered
branch then.
Upvotes: 2
Reputation: 12906
check if the lost commit appears in the output of git reflog.
Upvotes: 5