Rose Perrone
Rose Perrone

Reputation: 63546

How should I move changes from one commit to another?

I have two commits on the same branch, one right after another. I added changes to file A to the first commit, and then I made some changes to other files and then made another commit. Now I want the changes to file A to be on the second commit rather than the first. What's the most elegant way?

Upvotes: 51

Views: 33089

Answers (5)

Loic
Loic

Reputation: 530

I know this is an old question but I had the exact same request and I just figured out the best way to resolve this issue: you need to use interactive rebase and choose "edit" for the two commits you want to move a change from and to.

For instance, let say you have 3 commits:

$ git log -3 --oneline
97e9d62 Commit C, editing file2.txt
34b066b Commit B, creating file2.txt + editing file1.txt
73ff1bb Commit A, creating file1.txt

Now, if you want the Commit B to only contain the file2.txt creation but not the file1.txt edition which should be in Commit C, git rebase -i will display this:

pick 73ff1bb Commit A, creating file1.txt
pick 34b066b Commit B, creating file2.txt + editing file1.txt
pick 97e9d62 Commit C, editing file2.txt

# ...

If I replace "pick" with "edit" or "e" for Commit B and Commit C and close my editor, git will stop on the second commit and let me amend my changes:

pick 73ff1bb Commit A, creating file1.txt
edit 34b066b Commit B, creating file2.txt + editing file1.txt
edit 97e9d62 Commit C, editing file2.txt
Stopped at 34b066b... Commit B, creating file2.txt + editing file1.txt
You can amend the commit now, with

    git commit --amend

Once you are satisfied with your changes, run

    git rebase --continue

$ vi file1.txt    # edit of file1.txt to remove the updated line
$ git commit --amend file1.txt
$ git rebase --continue

# -- git continues rebasing and stops on the Commit C to edit it

$ vi file1.txt   # edit of file1.txt to put the removed line
$ git commit --amend file1.txt
$ git rebase --continue

And that's it.

Take care to save somewhere the line(s) you're removing from first commit to put them in the second one. It can be in clipboard, text file, etc. I guess it should be possible to rely on git stash too but if it's a simple change it's easier to keep it in the clipboard.

Upvotes: 32

Berik
Berik

Reputation: 8143

Another solution to this problem

  • Find the commit just before the two commits (likely this is the master branch)
  • Run git rebase -i <commit before commits to be reordered> (git rebase -i master in most cases)
  • In the text editor, swap the order of the commits (for vim, use the sequence ddp while on the line that should move down)
  • Save, quit, and let git rebase do the rest

Upvotes: 1

Mikhail Golubtsov
Mikhail Golubtsov

Reputation: 6653

I wrote a script to meet this purpose. You can checkout out it here.

Using the script it would be as simple as:

mv-changes HEAD~ HEAD fileA

Upvotes: 27

David Culp
David Culp

Reputation: 5480

In the, probably unlikely, event you have just created those commits, undo the second commit with git reset HEAD^ and then add the changes to the first commit with git commit --amend.

In the more likely event you have moved on and the commits were at some point in the past, rebasing is your best option. Without knowing your exact situation, citing a reference that explains it well is probably best.

In both the first and second event, the Pro Git book's section on rewriting history explains the options well -- both when they should be used and when caution should be used.

6.4 Git Tools - Rewriting History

Upvotes: 0

Ryan Stewart
Ryan Stewart

Reputation: 128829

If they're small commits, and commits should always be small in git, the simplest way is to git reset HEAD^^ and then just do them again. Note that any solution to this involves rewriting history, and if you've already pushed these commits somewhere, you shouldn't do this unless you know what you're doing.

Upvotes: 7

Related Questions