13

Suppose I have a branch that consists of three commits, one of them empty:

# On branch test
3208910 empty
85c949c bar
0c1a615 foo

I want to rebase it on the root and from the man page it seems that --root --keep-empty is exactly what I need.

However, both git rebase -i --root and git rebase -i --root --keep-empty omit the empty commit and show me this plan instead:

pick 0c1a615 foo
pick 85c949c bar

How can I rebase the entire branch and keep empty commits at the same time?

P.S. I needed this to remove a few first commits on the branch and I managed to achieve that with filter-branch as described in this SO answer, but I'm still interested in knowing if rebase is capable of that. Is it a bug in Git that I found? It's hard to believe this behavior is intentional but I'm not sure.

P.P.S. I found that I can edit the plan by hand and add pick 3208910.

Community
  • 1
  • 1
eush77
  • 3,870
  • 1
  • 23
  • 30
  • 8
    I don't really know why. But it has to do with the `--root` flag you are using. Doing the same on a branch - `git rebase -i --keep-empty master` seems to work as expected. – Igal S. Dec 30 '15 at 13:01
  • 4
    `git rebase -i --root --keep-empty --preserve-merges` also works for some reason. The `--root` option is really weird, I don’t get what’s happening there… – poke Dec 30 '15 at 13:21
  • 4
    @poke: probably just a bug ... `--root` internally works by setting the "onto" target to the empty tree, which is not a commit but works for cherry-pick. It's not immediately obvious what, but without the preserve merge setting, something's removing the pick command for the empty-diff commit, perhaps because the difference itself is an empty tree and hence matches $onto. – torek Dec 30 '15 at 15:42
  • you could `git cherry-pick` the empty commit to the root branch – GitProphet Aug 17 '17 at 16:51
  • Git 2.18 (Q2 2018) should improve and resolve this issue: https://stackoverflow.com/a/50122618/6309 – VonC May 01 '18 at 19:30

2 Answers2

1

It is connected with the two modes of git rebase.

Patch-id approach should keep the empty commit and is the default behaviour.

However, as correctly pinpointed, --root flag is a shortcut for "onto NULL" and this triggers the fork-point mode.

More information can be deducted from:

petrpulc
  • 940
  • 6
  • 22
0

--root flag is a shortcut for "onto NULL" and this triggers the fork-point mode.

This is no longer the case with Git 2.27 (Q2 2020), since the incompatible options "--root" and "--fork-point" of "git rebase" have been marked and documented as being incompatible.

See commit a35413c (27 Apr 2020) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit 6d6b412, 01 May 2020)

rebase: display an error if --root and --fork-point are both provided

Reported-by: Alexander Berg
Documentation-by: Alban Gruin
Signed-off-by: Elijah Newren

  • --root implies we want to rebase all commits since the beginning of history.

  • --fork-point means we want to use the reflog of the specified upstream to find the best common ancestor between <upstream> and <branch> and only rebase commits since that common ancestor.

These options are clearly contradictory, so throw an error (instead of segfaulting on a NULL pointer) if both are specified.

The error will be:

cannot combine '--root' with '--fork-point'
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I think OP's problem is that rebase strips previous cherrypicks, and its implementation of the `--root` commit puts an empty commit at the base, so when it checks patch id's the new empty commit looks like it's already been applied. – jthill May 02 '20 at 20:48
  • @jthill Agreed. This was more to mention this corner case when using `git rebase --root`. – VonC May 03 '20 at 17:36