{"thread":{"id":"63096","subject":"git rebase skips reapplied commits","startedAt":"2025-03-11T18:10:43Z","lastAt":"2025-03-11T18:55:15Z","messageCount":2,"participants":["45mg","Elijah Newren"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"513995","messageId":"87jz8v8mlj.fsf@gmail.com","threadId":"63096","inReplyTo":null,"subject":"git rebase skips reapplied commits","fromName":"45mg","fromEmail":"45mg.writes@gmail.com","sentAt":"2025-03-11T18:10:32Z","receivedAt":"2025-03-11T18:10:43Z","isPatch":false,"sender":{"key":"45mg.writes@gmail.com","avatar":null},"body":"\nIf the same commit is made and then reverted on both <upstream> and\n<branch>, and then reapplied only on <branch>, then\n`git rebase <upstream> <branch>` will skip the reapplied commit.\n\nThe following script demonstrates the issue:\n\n```\n#!/bin/sh -eu\n\n# Set up a repo for the following commands.\nrepo_directory=\"./rebase-test-repo\"\nrm -rf \"${repo_directory}\"\nmkdir -p \"${repo_directory}\"\ncd \"${repo_directory}\"\ngit init -b main\ngit config user.name test\ngit config user.email test@no.mail\n\n# Create a branch 'br' starting from a commit other than the tip of the\n# 'main' branch. Switch to it.\ngit commit --allow-empty -m 'initial commit'\ngit commit --allow-empty -m 'another empty commit'\ngit switch --create br HEAD^\n\n# Create a non-empty commit on 'br', then revert it.\ntouch a\ngit add a\ngit commit -m 'Add a'\ngit revert --no-edit HEAD\n\n# Make identical commits on 'main'.\ngit switch main\ntouch a\ngit add a\ngit commit -m \"Add a (on 'main')\"\ngit revert --no-edit HEAD\n\n# Reapply the reverted commit to 'br'.\ngit switch br\ngit revert --no-edit HEAD\n\n# Rebase 'br' onto 'main'.\ngit rebase main br\n\ngit -P log --graph --all --oneline\n# Sample output:\n#\n# * 5b4d655 (HEAD -> br, main) Revert \"Add a (on 'main')\"\n# * 7881a38 Add a (on 'main')\n# * 907f1a8 another empty commit\n# * 6c094a9 initial commit\n#\n# What we expect to see:\n# The commit 'Reapply \"Add a\"' should have been rebased onto 'main'.\n#\n# What we see:\n# This commit was skipped during the rebase and has been lost.\n```\n\nUsing the '--reapply-cherry-picks' option prevents this from happening,\nbut it also creates empty commits, so it's not a proper workaround.\n\n\n[System Info]\ngit version:\ngit version 2.48.1\ncpu: x86_64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /gnu/store/jlqbjxk51bdq5w7wlnbmwxm1j0pnllpx-bash-minimal-5.1.16/bin/sh\nzlib: 1.3\ncompiler info: gnuc: 11.4\nlibc info: glibc: 2.39\n$SHELL (typically, interactive shell): /gnu/store/cdwviyfnsfv7k57qrwmym0mrynjixc1i-bash-5.1.16/bin/bash\n\n\n[Enabled Hooks]\nnot run from a git repository - no hooks to show\n"},{"id":"513998","messageId":"CABPp-BH0xziowZx4S2aKJL5wjPHbJQ8wNstPUSLaw0FNdDu-fg@mail.gmail.com","threadId":"63096","inReplyTo":"87jz8v8mlj.fsf@gmail.com","subject":"Re: git rebase skips reapplied commits","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-03-11T18:55:02Z","receivedAt":"2025-03-11T18:55:15Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Mar 11, 2025 at 11:11 AM 45mg <45mg.writes@gmail.com> wrote:\n>\n> If the same commit is made and then reverted on both <upstream> and\n> <branch>, and then reapplied only on <branch>, then\n> `git rebase <upstream> <branch>` will skip the reapplied commit.\n\nYes, as expected and as documented.  Another commit exists upstream\nwhich introduces the same change, so it is omitted.\n\n> The following script demonstrates the issue:\n>\n> ```\n> #!/bin/sh -eu\n>\n> # Set up a repo for the following commands.\n> repo_directory=\"./rebase-test-repo\"\n> rm -rf \"${repo_directory}\"\n> mkdir -p \"${repo_directory}\"\n> cd \"${repo_directory}\"\n> git init -b main\n> git config user.name test\n> git config user.email test@no.mail\n>\n> # Create a branch 'br' starting from a commit other than the tip of the\n> # 'main' branch. Switch to it.\n> git commit --allow-empty -m 'initial commit'\n> git commit --allow-empty -m 'another empty commit'\n> git switch --create br HEAD^\n>\n> # Create a non-empty commit on 'br', then revert it.\n> touch a\n> git add a\n> git commit -m 'Add a'\n> git revert --no-edit HEAD\n>\n> # Make identical commits on 'main'.\n> git switch main\n> touch a\n> git add a\n> git commit -m \"Add a (on 'main')\"\n> git revert --no-edit HEAD\n\nNote that this does not match your original description, and your\ncomment here, \"Make identical commits on 'main'\" is not (always)\ncorrect.  If there's even a little lag between when the last two\ncommands run and the ones before them, then the commits on 'br' and\nthe commits on 'main' are not the same.\n\n> # Reapply the reverted commit to 'br'.\n> git switch br\n> git revert --no-edit HEAD\n>\n> # Rebase 'br' onto 'main'.\n> git rebase main br\n\nI would have expected\n   git rebase --onto main br~1 br\ndue to the non-identical commits issue I mentioned above, though\nwithout --reapply-cherry-picks it doesn't really matter.  With\n--reapply-cherry-picks, though, it matters because I would have\nexpected you wanted 5 commits rather than 7 (empty initial commit,\nanother empty commit, Add a on main, revert add a on main, Add a,\nrevert that, Reapply add a).\n\n> git -P log --graph --all --oneline\n> # Sample output:\n> #\n> # * 5b4d655 (HEAD -> br, main) Revert \"Add a (on 'main')\"\n> # * 7881a38 Add a (on 'main')\n> # * 907f1a8 another empty commit\n> # * 6c094a9 initial commit\n> #\n> # What we expect to see:\n> # The commit 'Reapply \"Add a\"' should have been rebased onto 'main'.\n> #\n> # What we see:\n> # This commit was skipped during the rebase and has been lost.\n> ```\n\nYes, it's behaving as documented.\n\n> Using the '--reapply-cherry-picks' option prevents this from happening,\n> but it also creates empty commits, so it's not a proper workaround.\n\nIt'll only create an empty commit if (a) the commit being\ncherry-picked is empty, or (b) the application of the changes from the\ncommit result in no-change.\nIn this example you provided, no empty commit would be created\n(whether or not you used your original rebase command or the\nmodification I expected).\n\nSo, it looks like precisely the appropriate workaround if you really\nwant to reapply these commits.  Why do you think it's not the right\nworkaround?\n"}]}