I was resolving merge conflicts and needed to get back to the old codebase to figure out how it worked before.
I intuitively stashed my working copy, checked what I wanted to and applied the stash back.
Now I'm in a lot of trouble because my code has been saved but I no longer see |MERGING
next to the branch name in the terminal and I have lost all the commits form the other branch. For git it doesn't look like a merge commit any longer, but simply a new code change.
What have I done wrong and how can I avoid the same issue in the future?
NOTE: Committing it as is is not an option, because we are working on 2 different repos and we need to merge one into another from time to time. If we change the checksum during one of our merges, we will face a massive amount of conflicts, because on the next merge git will not recognise the previously merged code. Merging the same repo over and over again looks like merging the same branch several times. Checksums should stay the same.
Something does not quite add up, because git stash
works by making commits. You said:
I was resolving merge conflicts ... I intuitively stashed my working copy
If you're in the middle of a conflicted merge, you cannot make commits, and therefore you cannot use git stash
:
... [set up some conflicts; get onto branch b2, with b1 ready to conflict]
$ git add README && git commit -m 'b2-readme'
[b2 c548973] b2-readme
1 file changed, 1 insertion(+)
$ git merge b1
Auto-merging README
CONFLICT (content): Merge conflict in README
Automatic merge failed; fix conflicts and then commit the result.
$ git status
On branch b2
You have unmerged paths.
(fix conflicts and run "git commit")
Changes to be committed:
new file: file1
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README
$ git stash
README: needs merge
README: needs merge
README: unmerged (af8a7b1af61c4d6a71415c41d0f19a418d5a1e3c)
README: unmerged (1eafc235a9f2cb59959d554ba9b9e11877c88349)
README: unmerged (7616840fd1336b8bcae3f33e2c6c69890e563121)
fatal: git-write-tree: error building trees
Cannot save the current index state
To make a stash actually happen, you must resolve the conflicts. Git doesn't care how you resolve them, of course:
$ cat README
We put a dummy README file into the base,
to get an initial commit.
<<<<<<< HEAD
conflicting b2 change
||||||| merged common ancestors
=======
conflicting change in b1
>>>>>>> b1
$ git add README # Yuck! "resolve" conflicts by leaving markers
$ git status --short
M README
A file1
$ git stash
Saved working directory and index state WIP on b2: c548973 b2-readme
HEAD is now at c548973 b2-readme
If this is what you did—perhaps while doing something sensible with the conflicts, rather than my silly example here—and then you did this:
$ git stash pop # NB: better to "git stash apply" really
On branch b2
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: file1
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README
Dropped refs/stash@{0} (8a947fcd34b3259fbb2fbf667bc0b99cc139a88c)
you're sort-of in trouble, but not too much. The problem is that you now have, in your index and work-tree, the state you had when you did the (successful, this time) git stash
, but you've lost the merging state files (.git/MERGE_HEAD
and .git/MERGE_MSG
).
NOTE: Committing it as is is not an option, because we are working on 2 different repos and we need to merge one into another from time to time.
Committing, like failure, is always an option! In this case, for instance, the trick is to commit the result now, and go back and restart the merge.
Because of the confusing nature of branches in Git, it's possible to commit this right now on b2
and then make b2
(the name) no longer contain the commit. But it's just as easy, or even easier, and definitely less confusing, to create a new branch name first. Then you can make the commit there, not on b2
.
$ git checkout -b save-merge-result
M README
A file1
Switched to a new branch 'save-merge-result'
# NOTE: use "git status" (not shown here) to see what you
# still need to "git add" (which is `README` in my case)
$ git add README
$ git commit -m 'save merge result on temp branch'
[save-merge-result f8b2251] save merge result on temp branch
Date: Tue Oct 18 05:58:14 2016 -0700
2 files changed, 20 insertions(+)
create mode 100644 file1
Now you can go back to b2
and redo the git merge
, which will of course fail with conflicts again:1
$ git checkout b1
Switched to branch 'b1'
$ git merge b2
Auto-merging README
CONFLICT (content): Merge conflict in README
Automatic merge failed; fix conflicts and then commit the result.
Now you can extract results from the temporary merge. For instance:
$ git checkout save-merge-result -- .
$ git status
On branch b1
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: README
new file: file2
At this point you can modify and git add
files more as needed/desired.
Note that if you have not already done a git pop
on the stash you made, you can use git stash branch
to convert the stash to a branch of its own, all in one step. Since git stash save
simply makes commits, you never need to use git stash
: just make a branch and commit there. All that git stash
does is give you commits that are remembered by the name stash
, instead of by a branch name.
(Incidentally, don't name a branch stash
and start using git stash
. Git won't have any trouble with this, but you will confuse the heck out of yourself. :-) )
1Assuming you have not enabled git rerere
.