Reputation: 1391
I seem to have lost a few files worth of edits, so I'm trying to figure out what I did wrong. It certainly seems like a git merge affected both the source and target branches. I'm not worried about finding the lost edits, just fixing my understanding of git.
I have a develop
branch. I created a feature-x
branch, did some work, and made a single commit affecting 8 files (call that commit "WIP"). Then I switched back to develop
, did some other work on other features (since merged), and today I needed to get a some pieces from feature-x
into develop
:
git checkout develop
git merge feature-x --no-commit --no-ff
So now develop
has my feature-x
changes on top, uncommitted/unstaged. I staged and committed two of the files (call that commit "Two Files"), but decided I wasn't ready to commit the rest to develop
. I wanted to leave them in feature-x
, but figured it was worth rebasing feature-x
onto the current develop
branch. At this point, I thought feature-x
should still be unchanged - the merge should have only changed develop
. So I cleaned up the uncommitted changes from the merge:
git reset --hard HEAD; git clean -f -d
And tried to rebase feature-x
onto develop:
git checkout feature-x
git rebase develop
I expected my history now to show all my older develop
commits, then the new "Two Files" commit, and then the "WIP" commit from feature-x
rebased on top. But all I see is "Two Files"... the changes from the "WIP" commit seem to be gone.
So where did I go wrong? I forgot to check the commit log after checking out feature-x
right before the rebase, but I have to assume the "WIP" commit was already gone since it was gone after the rebase. Did the merge --no-commit --no-ff
onto develop
also change feature-x
?
Upvotes: 0
Views: 1130
Reputation: 489678
Let me start by saying that I recommend working through the concepts at Think Like (a) Git. They are crucial to understanding how Git works.
As to what happened, well, I made a small repository and repeated some of your commands as best I could given what you've told us here:
git checkout develop git merge feature-x --no-commit --no-ff
So now develop has my feature-x changes on top, uncommitted/unstaged.
No: You are now in the middle of an unfinished merge. The --no-commit
option suppresses the commit, leaving you in that merge.
$ git merge feature-x --no-commit --no-ff
Automatic merge went well; stopped before committing as requested
Moreover, Git automatically copies all the successfully-merged files into the staging area. The staging area—also called the index, and I tend to use that name more—holds all the files that get committed. Each commit is a complete snapshot of every file, so that it can be extracted fully intact later.
$ git status
On branch develop
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: README
new file: new.1
new file: new.2
If you use git reset
(in one of its many various modes—the command does too many different things, in my opinion, so it can be tricky to talk about it), you can copy files from one of the commits back into the staging area, so that the staging area version of some file matches the develop
version of the file, or no copy of the file at all (if the file was new), rather than containing the result of some merging action.
I staged and committed two of the files (call that commit "Two Files") ...
No, at this point you simply finished the merge. Git now knows that the correct combination of the series of commits on the two branches is the result of this particular commit.
Note that git commit --only
cannot be used at this point:
$ git commit --only README
fatal: cannot do a partial commit during a merge.
On the other hand, git commit --include
can, but that's equivalent to running git add
followed by git commit
, so that it commits the merge.
$ git commit
At this point, one's editor open on a text file reading:
Merge branch 'feature-x' into develop
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch develop
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
# modified: README
# new file: new.1
# new file: new.2
#
Writing this file out and exiting produces:
[develop 2313673] Merge branch 'feature-x' into develop
I conclude that either you ran a command you're not showing—which could be crucial—and/or that you committed the merge, which would explain the behavior you're seeing. In particular:
Did the
merge --no-commit --no-ff
ontodevelop
also changefeature-x
?
No: but committing a merge changes the merge base of future operations, and changes which sets of commits are reachable from various branch names. This affects git rebase
. In particular, the WIP commit you made on feature-x
is now reachable from—and hence contained in—develop
, so making feature-x
extend from the tip of develop
no longer requires that feature-x
contain a copy of the WIP commit, as it's already in the develop
branch. Rebase will therefore not bother to copy the commit: it's going to be in both branches from now on.
Upvotes: 1
Reputation: 6721
I would do this the following way:
I realised that I need some part of the last (WIP) commit of feature-x
. I checkout to feature-x
.
git checkout feature-x
I reset my last commit:
git reset --soft HEAD~1
I unstage all and I stage only the desired changes of the two files (it is possible at least in my VSCode to stage only selected part of file). After this I commit:
git commit -m "Two files" // git will generate a commit with hash `a1b2c3d4`
And I stage the rest and commit:
git add .
git commit -m "WIP rest"
Now I can cherry-pick my desired changes on develop:
git checkout develop
git cherry-pick a1b2c3d4
The advantage of using cherry-pick
is that it will not cause problem later when I rebase or merge my feature-x
branch with develop, cause git will recognise that this is exactly the same change in both branches.
Upvotes: 1