Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a right way to combine two commits that are not in order?

Tags:

git

I want to combine two commits that are not in order into one.

For example, if I execute the command git rebase -i HEAD~3:

pick 8h47n1f Update documentation and release-notes  #a
pick 8n32b7a Implemented some random function        #b
pick a73ncj1 Update documentation and release-notes  #c

I want to combine line a and c into one commit before pushing.

My current way of accomplishing this is to reorder my commits in the following way:

pick 8h47n1f Update documentation and release-notes   #a
squash a73ncj1 Update documentation and release-notes #c
pick 8n32b7a Implemented some random function         #b

So far I have not witnessed any dangerous side effects. Does anyone know if I could really break something by doing this? Is there a better, safer way to do what I'm trying to accomplish?

like image 654
Hen Avatar asked Sep 22 '16 20:09

Hen


2 Answers

This is the best way (and afaik the only way) to achieve it. You can't do anything that couldn't be reverted (for example you can always abort rebase process on conflicts).

like image 79
Maciej Małecki Avatar answered Nov 02 '22 04:11

Maciej Małecki


The list presented by the interactive rebase (git rebase -i) is, in a simplistic view, just a script for automated execution of cherry-picks. The list is fully editable, you can even delete everything and write a whole new and completely different list. Git will just checkout the base commit and then execute the list commands in order.

There is a way to reorder the commits in the list automatically: using autosquash. From git-rebase documentation:

--autosquash
--no-autosquash

When the commit log message begins with "squash! …​" (or "fixup! …​"), and there is a commit whose title begins with the same …​, automatically modify the todo list of rebase -i so that the commit marked for squashing comes right after the commit to be modified, and change the action of the moved commit from pick to squash (or fixup). Ignores subsequent "fixup! " or "squash! " after the first, in case you referred to an earlier fixup/squash with git commit --fixup/--squash.

This option is only valid when the --interactive option is used.

If the --autosquash option is enabled by default using the configuration variable rebase.autoSquash, this option can be used to override and disable this setting.

In your example, when creating the commit c, use git commit --squash <commit-a> (also works with --amend, if the commit already exists). When git rebase -i is issued (assuming you set rebase.autoSquash), the list will be presented as you want it.

The only issue regarding interactive rebase is when combining the -p and -i options. Again, from git-rebase docs, in the Bugs section:

The todo list presented by --preserve-merges --interactive does not represent the topology of the revision graph. Editing commits and rewording their commit messages should work fine, but attempts to reorder commits tend to produce counterintuitive results.

like image 36
André Sassi Avatar answered Nov 02 '22 04:11

André Sassi