Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Missing git commit

Tags:

It happens all the time at work, that someone accidentally commits something to master instead of to the intended feature branch, the person then tries to resolve it, only to have the changes suddenly disappear. I have searched thick and thin, and can find no documentation to shed light on why this happens, or how to remedy the situation.

Here are steps to reproduce:

$ git init
$ echo hello world > testfile
$ git add testfile
$ git commit -m 'init'
$ git branch A
$ echo abc >> testfile
$ git commit -am 'append abc'
$ git revert HEAD --no-edit
$ git checkout A
$ echo fff > secondfile
$ git add secondfile
$ git commit -m 'Add second file'
$ git cherry-pick master^

At this point the git history looks like this:

$ git log --oneline --all --graph --decorate
* ac6f9b4 (HEAD -> A) append abc
* 54be952 Add second file
| * 9ba1f16 (master) Revert "append abc"
| * ef7c8d6 append abc
|/  
* 65a885d init

Watch then what happens when I rebase branch A on top of master:

$ git rebase master
$ git log --oneline --all --graph --decorate
* 9d08739 (HEAD -> A) Add second file
* 9ba1f16 (master) Revert "append abc"
* ef7c8d6 append abc
* 65a885d init

What happened to the commit that was at the head of A, commit ac6f9b4? Where did it go? why wasn't it reapplied?

While this was just a small example with a single commit missing on the end, but sometimes we end up losing several commits from the middle of a long commit chain, and then they seem practically invisible :(

like image 821
Born2Smile Avatar asked Jul 05 '17 23:07

Born2Smile


1 Answers

Rebase doesn't re-apply commits that have already been applied in the new base -- here, it's your append abc change. It's already in the master history. This is so often right that git does this without comment. It's arguably at least worth mentioning in the presence of subsequent reverts.

To see whether anything you're rebasing is already part of the new base history (master, here),

git log --oneline --cherry ...master

and look for =-marked commits. Those are commits in master that match commits in your branch; rebase won't re-apply them. Swap master... for ...master to see the local equivalents.

If you want an effectively blinded rebase, a first cut is

git checkout -B A master
git cherry-pick ..A@{1}      # < added the very important `..` by edit

which just moves A onto master and then cherry-picks everything you just left behind. To ignore merges (which you probably should), add --no-merges to the cherry-pick, it turns out when you ask cherry-pick for a series it just passes the whole set to git rev-list so you can use the machinery directly:

git cherry-pick --no-merges ..A@{1}  # just learned now that cherry-pick takes this
like image 143
jthill Avatar answered Oct 11 '22 13:10

jthill