0

I have a feature branch that has too many features in it!

For example, say we have the branch foo that has spanned too many files and items to really be just one feature.

Master ---A---B---C
                   \
              foo   E---F---G---H

commit E and F have to do with each other, commits G and H are totally different. I should have checkout to master, then started another branch for G and H.

How would I move those commits to a new branch? This would leave commits E and F on branch foo, and commits G and H on a new branch bar with the same parent commit C that foo is based off.

Master ---A---B---C
                  |\
             Foo  | E---F
                  |
             Bar  G---H
Lacrosse343
  • 491
  • 1
  • 3
  • 18

3 Answers3

2

We can use the two parameter version of git rebase --onto here:

# from foo
git rebase --onto C F

This says to replay onto commit C the chain of commits starting whose parent is commit F (which would be commits G and H).

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
1

If none of the code changes are shared between the two features, you can checkout master (or C), make a new feature branch, then cherry-pick G and H (using the commit shas).

If they do depend on some changes from the other feature (E and F) it might be less work to treat F as a "feature trunk" and split again (so, have two feature branches that merge back to the trunk feature branch and then back to master eventually).

If they're really completely unrelated work that will ship separately, but the G-H feature does depend on a few changes from the E-F feature, it will probably be worth the work to use the former approach (cherry-pick) and just manually backport any changes you might need, and deal with potential conflicts from whichever branch gets merged last, when they come up.

There's a very handy guide to cherry-pick over here, including some nice graphs.

Zac Anger
  • 6,983
  • 2
  • 15
  • 42
  • I ended up cherry picking the relevant commits onto a new branch, then HARD RESET on branch `foo` – Lacrosse343 Jul 28 '23 at 03:09
  • 1
    @Lacrosse343 that's probably what I would've done, before I saw the other answers here. I've never seen the `--onto` option for rebase in my decade of using Git, that looks like the perfect solution here. – Zac Anger Jul 28 '23 at 03:18
1

First, do git checkout -b bar H, which will make bar a new branch head pointing at H, and check it out.

Then do git rebase --onto master F, which says to take the commits after F, replay them on top of master (creating new commits G' and H'), and update bar to point to the new H'.

Then, do git checkout foo; git reset --hard F, which drops the commits G and H from foo. (You could also use git revert H G, creating a new revert commit, if you need to avoid rewriting history, but in a lot of scenarios where this comes up, rewriting history is not a serious problem).

Lastly, push the branches somewhere if that's a thing you want to do, using --force if necessary in the case of foo.

hobbs
  • 223,387
  • 19
  • 210
  • 288