Home > Net >  Can you rebase while rebasing?
Can you rebase while rebasing?

Time:07-23

Let's say I am doing a large rebase (yes, it's better to do one history change at a time, but, I'm an expert here).

I breakup a large commit, and have a few snippets to squash into older commits (I can't reach into git rebase --edit-todo to squash them, because the commits I want to squash into are already in the past). I love squashing with the GitHub desktop app. I do fear if I drag n' drop (squash) some commits, while I am already rebasing, that it's going to get too messy.

CodePudding user response:

The short answer is both no and yes. The long answer tells you when it's no and when it's yes, though in your case, I think it's just going to be "no" anyway, but see if the trick I mention below works for you.

We start, as always, with the basics:

  • Rebase is about copying some commits to new-and-improved commits.
  • Interactive rebase, which you're more specifically interested in here, involves a "todo" edit sheet as well (as you noted).
  • In all cases, the copying needs to make use of Git's index and your working tree—and there's only one index and working tree.
  • In all cases, the copying action uses a detached HEAD, and in the end, yanks what was the current branch name around to point to the final copied commit. (If you start with a detached HEAD, it just leaves HEAD detached at the final copied commit.) There's only one HEAD as well.

So the answer starts out as "no" because of the "only one" aspect.

But since Git 2.5, we have git worktree add. An added working tree comes with a new index and its own HEAD, and of course a separate "todo" edit sheet and so on. So the yes case applies when you have an added working tree.

The constraint on each added working tree is that each one must be on its own branch (or in detached HEAD mode). So you can have multiple ongoing rebases, but only if they're starting with different branch names.

Since your goal is to do some work in the middle of your existing detached HEAD work, you could add a new detached-HEAD working tree. You could set that detached HEAD to point to the latest commit in the rebase you've been doing so far. You can now start a new interactive rebase in the added working tree. When it's done, note the hash ID of the final copied commit.

You can now return to your original ongoing rebase, and git reset (presumably --hard because presumably you had committed everything before you started all of this) to the final commit in the added working tree. Then use git rebase --edit-todo to tweak the todo sheet in this working tree if/as needed, and resume the suspended rebase. Since you'll be working by raw hash ID, it will be ugly, but it is possible (and you can make temporary tags or branch names to remember specific commits if that's helpful, although for one-off use, cut-and-paste hash IDs is probably fine).

CodePudding user response:

I suppose, if git could track multiple git-rebase-todo files, this could work. But, obviously git only has one static git-rebase-todo file. So in reality, I shouldn't be able to start a second rebase.

CodePudding user response:

Going to create a summarized set of commands (for myself/others to use later), fully inspired by @torek's answer.

  1. You are stopped at commit5 (lets imagine for a moment, that our sha's are actually not random letters/numbers)
  2. You want to squash into some older commits. 2.5 Make a backup of your current git-rebase-todo file: git rebase --edit-todo. Simply copy/paste this into a safe place.
  3. git worktree add ../squash-below-commit5 commit5 && cd ../squash-below-commit5
  4. git rebase -i commit0
  5. If you have rebase.autoSquash enabled and are using squash! Foo commit message syntax, you are half way done editing git-rebase-todo.
  6. Paste previous git-rebase-todo file contents (we backed up in step 2.5) into the new file for the new interactive rebase you've just entered.
  7. Finish rebasing.
  8. git branch -D original-branch-name && git checkout -b original-branch-name. Likewise, you can: git log -1; echo "^note sha^"; git checkout original-branch-name; git reset --hard <sha from git log -1>
  • Related