Question

I have two consequential commits, somewhere in the local history, and one file was mistakenly added into the second. I want to fix the situation.

I do not understand how should I use the interactive rebase. I did git rebase -i HEAD~10 and choosen to edit the commit with file in order to check it out from there. I use git guit but, see no files in the commit area. I can choose to amend the previous commit then I see the files. But, I cannot add the misplaced file to that previous commit since I do not see the file in the current commit to start with.

Était-ce utile?

La solution 2

If I don't get it wrong, what you want is move some change that was included commit 2 to commit 1.

I find the easiest way to do that is doing two consecutive interactive rebases.

In the first one, you split commit 2 into two commits: the first including just the change you want to move, and the second including all the rest. We have now commits 1, 2.1, and 2.2.

Then you rebase again, and this time choose to squash commit 2.1 into 1.

Autres conseils

So, when rebasing, choose to edit both the commit where you added the file by mistake, and the one you want to add it to in that order. If the file is in a later commit, but should be in an earlier one, you will have to reorder the lines. For example, I start with

pick 8de731b Commit with missing file.
pick bbef925 Commit with too many files.
pick 52490ce More history.

I need to change it to

edit bbef925 Commit with too many files.
edit 8de731b Commit with missing file.
pick 52490ce More history.

Then,

# In the commit containing an extra file
git reset HEAD^ badfile.c
git commit --amend
git rebase --continue

# Now in the commit to add it to
git add badfile.c
git commit --amend
git rebase --continue

Unfortunately, when editing history in one branch, I don't know of any way to avoid editing history in all branches. Rebasing should be done as early as possible to avoid problems like this. In my simple case here, I can merge master and the other branch, but the commits don't merge, then I have to rebase in master, and reorder and squash the commits, like this:

pick 7cd915f Commit with missing file.
fixup 8de731b Commit with missing file. #This was the higher of the two entries
pick 8b92c5a Commit with too many files.
fixup bbef925 Commit with too many files. #This was the higher of the two entries
pick 94c3f7f More history.
fixup 52490ce More history. #This was the higher of the two entries

Late edit: I just noticed I was accidentally reordering the commit history as a carryover from my original answer. Swapping the lines in the rebase changes the order you commit; after editing, you can rebase again and swap them back to go back to the original commit order.

As I often stumble upon this issue, I wrote a script for this. It works fully automatically. You can find it on Github. Copy it to the local filesystem, add it to PATH and you'll be able to run it as:

mv-changes <source-commit> <destination-commit> <path>...

You can also run the script in Git-Bash shell on Windows.

Note that, if there are changes of <path> in intermediate commits between source-commit and destination-commit, it will not work.

First take info on short history

> git log --oneline -n 3 --decorate=short
333333  (HEAD -> work_AAA) added test              /*file is updated here*/
222222  corrected bug 
111111  (origin/master, origin/HEAD, master) version XXX 

so we can rebase and stop on commit 22222

> git rebase -i master 
pick 22222 corected bug 
pick 33333 added test

change to :

edit 22222 corected bug 
pick 33333 added test

then you will be in update mode in commit 22222 it shows something like this:

Stopped at 22222... corrected bug
You can amend the commit now, with
   git commit --amend 
Once you are satisfied with your changes, run
   git rebase --continue

here copy file from commit 3 to commit 2

git show 33333:path/to/file  >  path/to/file

amend commit 2 and continue rebase

git commit --amend --no-edit path/to/file
git rebase --continue

Done !

I had the same problem and want to explain what I did.

In commit A I added a file f that I had to remove in the following commit B.

Now I wanted to get rid of the file in both commits but also wanted to avoid splitting the commit because there were many other files involved. I did this

  • recover the file
  • add it again in commit ADD
  • remove it in commit REM - now there is the history A - B - ADD - REM
  • squash commit A with REM - then the file vanishes out of A and B
  • drop commit ADD - now the file is gone as it should be

Perhaps this is a quirky solution but for me it worked.
Please comment if you feel this is bad for some reasons.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top