Question

Consider the following git history:

* 21f05f9 - Fifth commit
* 0534049 - Fourth commit
* 738ae0a - Third commit
* 288ffd2 - Second commit
* 2535dca - First commit

How would I combine 21f05f9 738ae0a and 2535dca into one commit?

I have tried git rebase -i 2535dca, picking 2535dca and squashing 21f05f9 and 738ae0a, but I was given the following error:

error: could not apply 21f05f9 ... Fifth commit

I'm not sure if there's a way to skip commits 0534049 and 288ffd2 within rebase's interactive mode.

Is there a better way to do what I am doing? Are there any pitfalls?

Edit:

What I'm beginning to understand is I shouldn't really put myself in a place where non-linear commits are needed, especially if those commits all relate to one file. I could see an instance where a commit could break code or give a conflict.

Was it helpful?

Solution

This might not be as simple if the commits affect the same files. You can try:

Checkout a new branch from the 1st commit id mentioned:

git checkout -b new_branch 2535dca

Then just cherrypick the commits you want to add:

git cherry-pick 738ae0a

git cherry-pick 21f05f9

OTHER TIPS

There's no guarantee that you can arbitrarily reorder commits. Since 21f05f9 cannot be applied, it apparently assumes code introduced in an earlier commit which is missing from, perhaps, 2535dca. In this case, you simply need to treat it as a conflict and manually edit the file so that it agrees.

Start slowly. First, try to simply reorder the commits, even something as slow as swapping the fourth and fifth commits. This allows you to modify your history while making as few changes as possible at each step. Once the five commits are in the proper order, it will be a simple matter to merge the three desired commits into one, as they will be consecutive in the new history.

You are correct in the narrative of employing git rebase -i. (And you were also likely to have run git rebase -i 2535dca^, otherwise that commit would not have been in the rebase listing.)

One thing that you can do is to reorder and squash separately to simplify the flow – run two rebases, but fundamentally there isn’t much you can do except following the instructions and resolving all the merge failures every time rebase fails, whether running one or two rebases.

Apart from rebasing everything you may find the following flow slightly more explicit, and thus more intuitive for your specific case. (It is almost identical to what rebase is doing behind the scene.) You can work on a temporary branch where you will explicitly cherry pick the changes in the wanted order and squash as necessary:

$ git checkout -b tmp-topic 2535dca
$ git cherry-pick 738ae0a 21f05f9 
    ... will most likely have to resolve conflicts for each cherry-picked change
$ git rebase -i 2535dca
     … squash the two commits you just cherry-picked
$ git cherry-pick 288ffd2 0534049
    ... will most likely have to resolve conflicts for each cherry-picked change

Now you have your original branch topic and the new tmp-topic branch, where the order is just right, but topic is the one that should be pointing to the new graph of commits you’ve just finished working on:

$ git update-ref refs/heads/topic tmp-topic
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top