gitgit-rebasegit-pullgit-reflogreflog

Why git commit can be lost in this case?


My colleague did a series of careless pull/push operations. He end up in a situation where his local commit becomes missing

I recovered his commit using git reflog. But I couldn't figure out why his operations lead to the situation. Can someone shed some lights?

See git reflog output and comments below:

#######
# reflog is in reverse manner, most recent operation first
# test is like our "develop" branch, MTX-65 is the feature branch
# Both are remote-tracking
#######
39261b7 (HEAD -> MTX-65, origin/feature/MTX-65) HEAD@{0}: checkout: moving from test to MTX-65
7f66c72 (test) HEAD@{1}: checkout: moving from MTX-65 to test
39261b7 (HEAD -> MTX-65, origin/feature/MTX-65) HEAD@{2}: pull: Fast-forward
d51c1be HEAD@{3}: rebase finished: returning to refs/heads/MTX-65
d51c1be HEAD@{4}: rebase: Add Notification
c33d31f HEAD@{5}: pull --tags -r origin feature/MTX-65: checkout c33d31f4d0109396dea6d6bb78f47ba56097e4ac

#######
# This is the key commit that got lost
# It's not in `git log` out any more
#######
a6a7a7e HEAD@{6}: commit (merge): Warning message
3c8113c HEAD@{7}: commit (amend): Add Notification
7f551e4 HEAD@{8}: commit: Add Notification
96bcf99 HEAD@{9}: pull --tags -r origin feature/MTX-65: Fast-forward
b79bee0 HEAD@{10}: commit: personal & institution page
3cfb1aa HEAD@{11}: commit: Institution:
7f66c72 (test) HEAD@{12}: checkout: moving from test to MTX-65
7f66c72 (test) HEAD@{13}: merge MTX-65: Fast-forward
0733fd2 HEAD@{14}: checkout: moving from MTX-65 to test
7f66c72 (test) HEAD@{15}: commit (merge): Merge test
ebfaeea HEAD@{16}: checkout: moving from test to MTX-65
0733fd2 HEAD@{17}: pull: Fast-forward
1043c35 HEAD@{18}: checkout: moving from MTX-65 to test

#######
# This is a commit that still exists after the disaster
#######
ebfaeea HEAD@{19}: commit: institution 认证信息

Solution

  • Let's take a look at a6a7a7e HEAD@{6}: commit (merge): Warning message.

    commit (merge) indicates the merge encounters conflicts. After resolving conflicts, your colleague changes the default commit message to Warning message. The default message is like Merge made by the 'recursive' strategy.

    Then your colleague runs git pull --tags -r origin feature/MTX-65. With -r, git rebase is used instead of git merge after the fetch is done.

    As the manual says,

    By default, a rebase will simply drop merge commits from the todo list, and put the rebased commits into a single, linear branch.

    There are many debates about which is better, git merge or git rebase. One of the pros for git rebase is that we can use it to create a linear history in a convenient way. As designed, merge commits are dropped by default, although git rebase provides -r and -p to preserve them in some situations.

    During git rebase, the conflicts are expected to occur again. In theory, the changes can't be lost if your colleague resolves them the same way as he does in the previous git merge. You can try git log --reflog -S <keywords> -p to find out in which commit the changes including the keywords get lost.