Reputation: 12458
I have performed a git command on my repository that wasn't appropriate and I'm trying to figure out how to reverse the effect of my actions.
My "pre-error" state (i.e. the state to which I am trying to revert) looked as shown here when logged with git log --oneline --graph --decorate --all
(with my own extra comments added after-the-fact for clarity):
* 9aaaaaa (HEAD -> master) commit message 9
* 8aaaaaa commit message 8 <=== note that this...
| * 7aaaaaa (branchB) commit message 7
|/
| * 6aaaaaa (branchA) commit message 6
| * 5aaaaaa commit message 5
| * 4aaaaaa commit message 4, i.e. branchA~2
| * 3aaaaaa commit message 3
|/
* 2aaaaaa commit message 2 <=== ...descends from this
* 1aaaaaa commit message 1
I wanted to reword a commit in the branchA
branch. So I entered the following command: git rebase -i branchA~2
intending to use the reword
command and finishing. Once in the rebase
window I decided against making any changes and quit. However, I suspect that I did not cancel the operation and quit as I should have, but rather saved the file and quit. The problem, I believe, is that to attempt what I was doing I should have checked myself into branchA
first and then performed the git rebase -i branchA~2
. However, instead, I inappropriately started from the master
branch. Thus, I think I somehow told git that I now wanted my master
branch to be connected in a new way to commit branchA~2
, i.e. commit 4aaaaaa
, which I do NOT want.
So, after the save-and-quit, my commit tree now looks like the following:
* 9bbbbbb (HEAD -> master) commmit message 9
* 8bbbbbb commit message 8 <=== now, instead, this...
| * 7aaaaaa (branchB) commit message 7
| | * 6aaaaaa (branchA) commit message 6
| | * 5aaaaaa commit message 5
| |/
|/|
* | 4aaaaaa commit message 4, i.e. branchA~2 <=== ...descends from this...
* | 3aaaaaa commit message 3
|/
* 2aaaaaa commit message 2
* 1aaaaaa commit message 1
Note that, as shown in the comments above, in the original state, commit 8aaaaaa
directly descends from commit 2aaaaaa
, but after my rebase
command, the corresponding commit 8bbbbbb
now descends from commit 4aaaaaa
, i.e. from commit branchA~2
.
So, how to I get back to my original state?
I haven't tried anything, because I'm very nervous about screwing things up further. Here are some possibilities:
master
branch and do git rebase -i 2aaaaaa
.projectHome/.git/refs/heads
.Any suggestions?
Upvotes: 3
Views: 115
Reputation: 104145
git reflog
. You should see the previous tips of your branches: 9aaaaaa
, 7aaaaaa
, 6aaaaaa
.git checkout master && git reset --hard 9aaaaaa
, etc.The important point here is that whenever you rewrite history, the old commits are not changed in place or deleted. Before rewrite:
...--A--B <-- branch
After rewrite:
...--A--B
\
\--A'--B' <-- branch
As you can see, nothing points to B, so the whole branch is “lost”, but it’s not deleted (unless you run git gc
or something like that) and all you have to do to recover it is to flip the branch
pointer back to B.
Upvotes: 4
Reputation: 8656
I'm not sure I entirely undertand what's happened from the graph, but my usual "panic button" in case of a borked rebase or change, is to inspect the reflog using git reflog
.
Reference logs, or "reflogs", record when the tips of branches and other references were updated in the local repository. Reflogs are useful in various Git commands, to specify the old value of a reference.
Essentially, you should be able to see where the tip of your current branch was before your rebase attempt. You can then use git reset <commit hash>
to reset your branch to the state it was in, essentially ignoring your changes. It's often more straightforward than attempting to undo whatever your just did (and dealing with potential implications for people who have copies of the branch).
The reflog output may look something like (generated from a local repo):
75d2e74 HEAD@{0}: rebase -i (finish): returning to refs/heads/master
75d2e74 HEAD@{1}: rebase -i (reword): I was trying to do something with a change here.
3b7e664 HEAD@{2}: cherry-pick: fast-forward
16180cd HEAD@{3}: <some other git operation>
You can see the prior operation to the rebase attempt was a cherry-pick, for you it will likely be something different. Inspect it with git show
and see if it's an appropriate commit to use as your reset point.
Even if your reset goes wrong (e.g. you reset too far back), you can again inspect the reflog and have another go.
Upvotes: 2