Skip to contentSkip to conversation

git rebase skips reapplied commits

DISCUSSION 45mg 2 participants 2 messages Mar 11, 2025

lore
Share & tools
lore

45mg

author
#0 lore raw

If the same commit is made and then reverted on both <upstream> and <branch>, and then reapplied only on <branch>, then
git rebase <upstream> <branch> will skip the reapplied commit.

The following script demonstrates the issue:

```
#!/bin/sh -eu

# Set up a repo for the following commands.
repo_directory="./rebase-test-repo"
rm -rf "${repo_directory}"
mkdir -p "${repo_directory}"
cd "${repo_directory}"
git init -b main
git config user.name test
git config user.email [email protected]

# Create a branch 'br' starting from a commit other than the tip of the
# 'main' branch. Switch to it.
git commit --allow-empty -m 'initial commit'
git commit --allow-empty -m 'another empty commit'
git switch --create br HEAD^

# Create a non-empty commit on 'br', then revert it.
touch a
git add a
git commit -m 'Add a'
git revert --no-edit HEAD

# Make identical commits on 'main'.
git switch main
touch a
git add a
git commit -m "Add a (on 'main')"
git revert --no-edit HEAD

# Reapply the reverted commit to 'br'.
git switch br
git revert --no-edit HEAD

# Rebase 'br' onto 'main'.
git rebase main br

git -P log --graph --all --oneline
# Sample output:
#
# * 5b4d655 (HEAD -> br, main) Revert "Add a (on 'main')"
# * 7881a38 Add a (on 'main')
# * 907f1a8 another empty commit
# * 6c094a9 initial commit
#
# What we expect to see:
# The commit 'Reapply "Add a"' should have been rebased onto 'main'.
#
# What we see:
# This commit was skipped during the rebase and has been lost.
```

Using the '--reapply-cherry-picks' option prevents this from happening, but it also creates empty commits, so it's not a proper workaround.

[System Info]
git version:
git version 2.48.1
cpu: x86_64
no commit associated with this build
sizeof-long: 8
sizeof-size_t: 8
shell-path: /gnu/store/jlqbjxk51bdq5w7wlnbmwxm1j0pnllpx-bash-minimal-5.1.16/bin/sh
zlib: 1.3
compiler info: gnuc: 11.4
libc info: glibc: 2.39
$SHELL (typically, interactive shell): /gnu/store/cdwviyfnsfv7k57qrwmym0mrynjixc1i-bash-5.1.16/bin/bash

[Enabled Hooks]
not run from a git repository - no hooks to show

#1 lore raw
Quoted 4 lines · On Tue, Mar 11, 2025 at 11:11 AM 45mg <[email protected]> wrote:

If the same commit is made and then reverted on both <upstream> and <branch>, and then reapplied only on <branch>, then
git rebase <upstream> <branch> will skip the reapplied commit.

Yes, as expected and as documented. Another commit exists upstream which introduces the same change, so it is omitted.

Quoted 26 lines

The following script demonstrates the issue:

```
#!/bin/sh -eu

# Set up a repo for the following commands.
repo_directory="./rebase-test-repo"
rm -rf "${repo_directory}"
mkdir -p "${repo_directory}"
cd "${repo_directory}"
git init -b main
git config user.name test
git config user.email [email protected]

# Create a branch 'br' starting from a commit other than the tip of the # 'main' branch. Switch to it.
git commit --allow-empty -m 'initial commit'
git commit --allow-empty -m 'another empty commit'
git switch --create br HEAD^

# Create a non-empty commit on 'br', then revert it. touch a
git add a
git commit -m 'Add a'
git revert --no-edit HEAD

Quoted 6 lines

# Make identical commits on 'main'.
git switch main
touch a
git add a
git commit -m "Add a (on 'main')"
git revert --no-edit HEAD

Note that this does not match your original description, and your comment here, "Make identical commits on 'main'" is not (always) correct. If there's even a little lag between when the last two commands run and the ones before them, then the commits on 'br' and the commits on 'main' are not the same.

Quoted 6 lines

# Reapply the reverted commit to 'br'.
git switch br
git revert --no-edit HEAD

# Rebase 'br' onto 'main'.
git rebase main br

I would have expected
git rebase --onto main br~1 br
due to the non-identical commits issue I mentioned above, though without --reapply-cherry-picks it doesn't really matter. With --reapply-cherry-picks, though, it matters because I would have expected you wanted 5 commits rather than 7 (empty initial commit, another empty commit, Add a on main, revert add a on main, Add a, revert that, Reapply add a).

Quoted 6 lines

git -P log --graph --all --oneline
# Sample output:
#
# * 5b4d655 (HEAD -> br, main) Revert "Add a (on 'main')" # * 7881a38 Add a (on 'main')
# * 907f1a8 another empty commit

Quoted 8 lines

# * 6c094a9 initial commit
#
# What we expect to see:
# The commit 'Reapply "Add a"' should have been rebased onto 'main'. #
# What we see:
# This commit was skipped during the rebase and has been lost. ```

Yes, it's behaving as documented.

Quoted 2 lines

Using the '--reapply-cherry-picks' option prevents this from happening, but it also creates empty commits, so it's not a proper workaround.

It'll only create an empty commit if (a) the commit being cherry-picked is empty, or (b) the application of the changes from the commit result in no-change.
In this example you provided, no empty commit would be created (whether or not you used your original rebase command or the modification I expected).

So, it looks like precisely the appropriate workaround if you really want to reapply these commits. Why do you think it's not the right workaround?