2

Edit:

I was fundamentally using git rebase -i ... wrong and thinking of it the wrong way when I wrote this question. git rebase -i [some branch name or tag or commit hash] allows you to explicitly identify the start of the sequence of commits that you are interactively editing (e.g. git rebase -i HEAD~3). Relying on the default argument in the case of a branch tracking another branch is a weird way to use interactive rebase, not a normal one.


git rebase -i is incredibly useful for reordering commits and combining them. However, sometimes I want to reorder, drop, combine, or split commits without the rebasing behavior. The main use case I can think of for doing this is cleaning up a development branch first and then rebasing it and potentially dealing with merge conflicts rather than doing both steps at once.

In the following scenario I am working in a git repository where the main branch has a linear history and reviewed commits are incorporated into the main branch via cherry-pick. I am working on commits B, C and D on a branch called my-feature. Let's further suppose that my-feature tracks the main branch. Commit A in the main branch is a big refactor.

Future * | A D (my-feature) | / * C | / * B | / * Past 

Suppose I want to reorder C and B. I want to reorder them first before marching my-feature forward beyond A.

I first want to do this change:

Future * | A D (my-feature) | / * B | / * C | / * Past 

and then do this change:

Future D (my-feature) / B / C / * | A | * | * | * Past 
4
  • I don't see what the issue is here. You say you know about rebase interactive. And rebase interactive doesn't move things onto another base; it is for just the kind of reordering you describe. So rebase interactive to swap the order of the commits, then rebase my-feature onto the main branch. Commented Jun 27, 2020 at 21:43
  • Maybe it's related to how tracking works? If my-feature tracks the main branch, then using git rebase -i will rebase B, C, D onto the main branch. Commented Jun 27, 2020 at 21:47
  • I don't know what "tracks the main branch" means here. Commented Jun 27, 2020 at 22:13
  • my-feature has the main branch set as the upstream branch. git branch -u ... Commented Jun 27, 2020 at 22:15

2 Answers 2

2

To do what you describe you want to rebase on the same base and reorder.
git rebase -i HEAD~3 will allow you to reorder/change the most recent three changes. It will bring up an editor window that looks something like:

pick 5f22324 This is change B pick 843611f This is change C pick 76e4eab This is change D 

showing the most recent three changes in order from oldest to newest. To reorder B and C, just swap the first two lines. You can also squash changes (by changing the pick to squash or s) and remove changes (by just deleting them).

Sign up to request clarification or add additional context in comments.

1 Comment

The key misconception on my part was how to use git rebase -i. I've never used it with an explicit argument, and have always relied on the upstream branch feature to supply a default one.
1

I'm not seeing what the problem is. I started with a graph just like your starting graph, with a branch main containing A and a branch my-feature containing B C D, and did this:

$ git checkout my-feature $ git rebase -i <theCommitBeforeB> [swap the C and B commits, and save] $ git rebase main 

And I ended up with your ending graph, with A on main and then C B D growing out the end of it on my-feature.

And

7 Comments

Oh. I think I see what my problem is. I always do git rebase -i with no explicit argument. That drops me into a view where I see only the differences between the current branch and the upstream branch. I suspect not providing an explicit argument changes the behavior.
Ah yes!!!! That's right, so you are doing git rebase interactive completely wrong. Sorry about that, I didn't grasp that. Well spotted. Yes, you must always give the commit just before the series you want to play with. Then you are plunged into the text editor where you make whatever rearrangements you want.
I agree that I'm doing it wrong, but I don't think that what you said is correct. If you have an upstream branch set, you don't need to provide an argument to git rebase -i for it to do something, it will use the latest commit of the upstream branch as the default. I suspect that the rule is: if my branch is tracking main, then git rebase -i is exactly equivalent to git rebase -i main.
I'm sure you're right. It's just that it would never have occurred to me to use -i in that situation.
Also I feel that you're using the word "tracking" wrong. But that's another story!
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.