If you want to fold two or more commits into one, replace the command "pick" for the second and subsequent commits with "squash" or "fixup". If the commits had different authors, the folded commit will be attributed to the author of the first commit.
The short answer is that you'll go ahead and commit your "middle" changes as usual, then run git rebase -i HEAD~4 . It'll bring up a list of the last 3 commits in a text editor. Simply reorder the commits where the newest commit is put in the middle, and then save and exit the editor.
Normally, rebase drops merges entirely, but you have to have a starting commit on which to rebase. Here there are two potential starting points and both are root commits; rebase is not prepared to handle this.
It's even easier than in OP's answer.
git rebase -i <any earlier commit>
. This displays a list of commits in your configured text editor.a1b2c3d
). In your editor, for that line, change pick
to edit
.a1b2c3d
) as if it has just been committed.git commit
(NOT amending, unlike most edit
s). This creates new a commit after the one you chose.git rebase --continue
. This replays the successive commits, leaving your new commit inserted in the correct place.Beware that this will rewrite history, and break anyone else who tries to pull.
Turns out to be quite simple, the answer found here. Suppose you're on a branch branch
. Perform these steps:
create a temporary branch from the commit after you want to insert the new commit (in this case commit A
):
git checkout -b temp A
perform the changes and commit them, creating a the commit, let's call it N
:
git commit -a -m "Message"
(or git add
followed by git commit
)
rebase the commits you want to have after the new commit (in this case commits B
and C
) onto the new commit:
git rebase temp branch
(possibly you need to use -p
to preserve merges, if there were any - thanks to a no longer existing comment by ciekawy)
delete the temporary branch:
git branch -d temp
After this, the history looks as follows:
A -- N -- B -- C
It is of course possible that some conflicts will appear while rebasing.
In case your branch is not local-only this will introduce rewriting history, so might cause serious problems.
Even easier solution:
Create your new commit at the end, D. Now you have:
A -- B -- C -- D
Then run:
$ git rebase -i hash-of-A
Git will open your editor and it will look like this:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Just move D to the top like this, then save and quit
pick 74096b9 D
pick 8668d21 B
pick 650f1fc C
Now you will have:
A -- D -- B -- C
Here's a strategy that avoids doing an "edit hack" during the rebase seen in the other answers I've read.
By using git rebase -i
you obtain a list of commits since that commit.
Just add a "break" at the top of the file, this will cause the rebase to break at that point.
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
Once launched, git rebase
will now stop at the point of the "break".
You can now edit your files and create your commit normally.
You can then continue the rebase with git rebase --continue
. This may cause conflicts you'll have to fix. If you get lost, don't forget you can always abort using git rebase --abort
.
This strategy can be generalised to insert a commit anywhere, just put the "break" at the spot where you want to insert a commit.
After rewriting history, don't forget to git push -f
. The usual warnings about other people fetching your branch apply.
Assuming that the commit history is preA -- A -- B -- C
, if you want to insert a commit between A
and B
, the steps are as follows:
git rebase -i hash-of-preA
Git will open your editor. The content may like this:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Change the first pick
to edit
:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Save and Exit.
Modify your code and then git add . && git commit -m "I"
git rebase --continue
Now your Git commit history is preA -- A -- I -- B -- C
If you encounter a conflict, Git will stop at this commit. You can use git diff
to locate conflict markers and resolve them. After resolving all conflicts, you need to use git add <filename>
to tell Git that the conflict has been resolved and then rerun git rebase --continue
.
If you want to undo the rebase, use git rebase --abort
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With