How can I move changes to a file from one commit to another?

620 Views Asked by At

How can I directly edit git history as to "drag 'n drop" changes from one commit to another?

Within a branch I have three commits:

A--B--C

The contents of which are:

A -- add file_a
B -- add file_b
     mod file_a
C -- mod file_b

Currently I can manage to split the changes via interactive rebase:

A   -- add file_a
B'  -- mod file_a
B'' -- add file_b
C   -- mod file_b

The end result is then:

A   -- add file_a (changes from B' squashed into A)
B'' -- add file_b (changes from C squashed into B'')

I have been experimenting with git filter-branch (or git filter-repo which is recommended instead) in an attempt to accomplish this task but don't seem to be landing on the correct set of arguments.

It would be entirely acceptable to "drag 'n drop" file_a changes from commit B into commit A in one command and then squash commit C into commit B.

What I am looking to avoid is the manual work brought on by interactively rebasing. The act of going back in time to effectively redo the work in the desired steps feels too clunky (up to ~7 steps in command line from my approach, mileage may vary). A script would alleviate the number of commands needing to be executed (see Mikhail's posted answer to this question), but is what has been described possible with respect to directly editing the history?

There are arguments for better commit practices (or best practices in general) as to avoid this scenario in the first place but I would like to subvert these for the sake educational of pursuit.

1

There are 1 best solutions below

3
On

I don't really understand what the problem is but I will try to tackl the case in point. You can do this:

git checkout A
git restore --worktree --staged --source=C -- file_a
git commit --amend -m "Final version of file_a, file_b does not exist over here"
git restore --worktree --staged --source=C -- file_b
git commit -m "Final version of file_b, no changes on file_a"