git reflog
is one of those commands that I've tried to use many
times with no success. Usually something goes horribly wrong with one
of git's more advanced commands (ex rebase, cherry-pick, reset), I
then search for something to recover my mistake, someone online says
it is so easy with a simple reflog, I try it, make my problem worse,
and eventually give up. But, a few days ago I had success!
Play-by-play
I opened a pull request and was resolving comments left on it. I fixed a group of related comments, made a commit for the changes, and started to run the tests. While the tests were running I went on to fix other comments. I stacked on two more commits. I then went to the tests and saw that they failed. My changes in the first commit since opening the pull request weren't quite right.
Here is what my commit history looked like
$ git log --abbrev-commit --pretty=oneline | head -n 5
64f97aac7 move checking for mpi to sim_data
5e95a50e3 simplify
a565074a0 mpi abort is needed; share between common-header.py.jinja and sirepo.mpi
688fd1c92 Fix #4038: Always call python parameters.py from slurm
688fd1c92
was the original commit where I opened the pull
request. a565074a0
was the first commit resolving pull request
comments. 5e95a50e3
and 64f97aac7
were more fixing of pull request
comments.
So, I wanted to make some changes but they are relevant to 688fd1c92
since that was the commit I was running the tests for. My normal
workflow for this sort of thing is to:
# make some changes
$ git stash
$ git rebase -i master
# select edit for the commit I want to edit (in this case 688fd1c92)
$ git stash pop
$ git commit --all --amend --no-edit
$ git rebase continue
I did just that and here is what I saw:
$ git status
On branch 4038-nersc-prepare-slurm
Your branch and 'origin/4038-nersc-prepare-slurm' have diverged,
and have 4 and 4 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Shoot! I did git rebase -i master
. Rebasing on master means that my
original commit for the pull request, 688fd1c92
, was modified from
the rebase because I set the base to be master. I had broken the golden
rule of rebase - never rebase on a public
branch.
The correct syntax would've been git rebase -i a565074a0^
. Which
means rebase on the commit one before the commit I want to edit.
Ugh, now to recover from my mistake. Thankfully I hadn't pushed anything so recovery shouldn't be too bad.
Off to Google how to recover. I searched for "how to undo a git
rebase". The first
answer, as expected, says
to use git reflog
.
Here is what I saw:
$ git reflog | head
c152af107 HEAD@{0}: rebase (finish): returning to refs/heads/4038-nersc-prepare-slurm
64f97aac7 HEAD@{1}: rebase (pick): move checking for mpi to sim_data
c7e8b67af HEAD@{2}: rebase (pick): simplify
df5260920 HEAD@{3}: commit (amend): mpi abort is needed; share between common-header.py.jinja and sirepo.mpi
a56507a40 HEAD@{4}: rebase: fast-forward
688fd1c92 HEAD@{5}: rebase (start): checkout master
9fc121349 HEAD@{6}: reset: moving to HEAD
9fc121349 HEAD@{7}: commit: move checking for mpi to sim_data
5e95a50e3 HEAD@{8}: commit: simplify
a56507a40 HEAD@{9}: commit: mpi abort is needed; share between common-header.py.jinja and sirepo.mpi
688fd1c92 HEAD@{10}: commit: Fix #4038: Always call python parameters.py from slurm
Alright, I must be getting better as a programmer because this looks
10x less initmidating than the last time I remember looking at it. I
see that for HEAD@{5}
it says rebase (start)
. I probably want to
move to the commit just before that. So I tried that:
$ git checkout HEAD@{6}
$ git diff
I did the git diff
to make sure that things look ok. They do so I
think this is where I want to be. Let's do it for real:
$ git switch -
$ git reset --hard HEAD@{6}
$ git status
On branch 4038-nersc-prepare-slurm
Your branch is behind 'origin/4038-nersc-prepare-slurm' by 2 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
A git diff
confirmed that I was back to where I was before the botched
rebase! The only bummer is that I lost the work that I wanted to
apply to 688fd1c92
. I'm sure there is a way I could've saved it but no big deal. It was easy to write again.
Editing a commit the right way
Now that git reflog
saved my skin I wanted to edit the commit with
my changes. Here is what I did:
# make the changes
$ git stash
$ git rebase -i 688fd1c92^ # ^ means one commit before 688fd1c92
# select edit for 688fd1c92
$ git stash pop
$ git commit --all --amend --no-edit
$ git rebase continue
$ git status
On branch 4038-nersc-prepare-slurm
Your branch is ahead of 'origin/4038-nersc-prepare-slurm' by 3 commits.
(use "git push" to publish your local commits)
Nice, 3 commits and not in conflict with the upstream. Thanks git
reflog
!