1

It seems that "git rebase" has additional fallback logic to deal with merge failures:

Falling back to patching base and 3-way merge...

What is it doing there, and how would I need to invoke my cherry-picks to get the same behavior?

Probably the right solution is to just not attempt to represent a rebase as a series of cherry-picks, but it would be nice if this were possible, since I can then deal with both rebases and arbitrary collections of changes using the same flow.

phd
  • 82,685
  • 13
  • 120
  • 165
Christian Goetze
  • 2,254
  • 3
  • 34
  • 51
  • Can you elaborate on what you're trying to do? A graph may help. – EncryptedWatermelon May 13 '19 at 19:19
  • I have a CI workflow that can either consume a rebase or a set of disparate patches. Instead of having to distinguish between the two cases, I'd rather transform the rebase into a set of cherry-picks and not have to think when doing a checkout. – Christian Goetze May 13 '19 at 21:35

1 Answers1

5

Most git rebase commands actually do run git cherry-pick.

The fallback you're seeing occurs from the one form of git rebase that, for historical reasons, doesn't use git cherry-pick. That one form is used when you invoke a non-interactive git-rebase and don't use any of the options that make it use new-and-improved rebase-invoking method.

The old form usually produces the same effect. It consists of using git format-patch to turn each commit into a patch, and then using git am --3way to apply all the formatted patches. The --3way option tells git am that, if the patch cannot be applied blindly, it should use the index lines in each formatted patch to achieve part of what git cherry-pick would have done automatically.

If you want rebase to use git cherry-pick directly, you may:

  • supply the -k option, or
  • supply the -m option, or
  • supply a -s strategy option, or
  • supply a -X extended-option option, or
  • use interactive rebase (-i or --interactive), or
  • use the --autosquash option, or
  • use the -p or (Git 2.18+) -r option.
torek
  • 448,244
  • 59
  • 642
  • 775
  • I'd rather understand how I can make my series of patches behave like a rebase. I think you gave the answer, but I'd need to code it and test it. If I understand correctly, every "cherry-pick" needs to use format-patch and git am --3way. – Christian Goetze May 13 '19 at 21:36
  • I guess what I'm trying to say is that I've tried applying cherry-picks one after the other, and that fails, but the rebase succeeds... but you seem to be saying that it should have succeeded... – Christian Goetze May 13 '19 at 21:43
  • 1
    I'm not sure what your question is, then. If you have a series of patches, use `git am --3way` (or `-3` for short) to get the same effect that `git rebase` gets when it uses `git format-patch` and `git am`. Note that if you don't control the `git format-patch` operation, you'll get *abbreviated* `index` lines, which may not be useful. You want whoever generates patches to use `--full-index`. Or, if you have a series of commit hash IDs in your own repository, use `git cherry-pick` on them, one at a time, to apply them at the current `HEAD`. – torek May 13 '19 at 21:55
  • 1
    Using `cherry-pick` is superior in a few ways, but also slower (because it does full-tree diffs to find renames). Note also that rebasing ends by forcing the branch label to move to the newly constructed commits; if you invoke either `git cherry-pick` or `git am` / `git apply` yourself, you have to do that yourself too. – torek May 13 '19 at 21:55
  • 1
    The one remaining thing to consider is that when `git rebase` enumerates commits for `git cherry-pick` (using the cherry-pick code path), it *omits* some commits intentionally. Specifically, commits that exist in the upstream as well as the current branch, and have the same patch-ID in both "sides", get omitted; all merges get omitted unless using `-p` or `-r`, in which case they're enumerated specially so as to be repeated. The enumeration uses `git rev-list --left-right --cherry-mark ...HEAD` to figure out which commits are which. – torek May 13 '19 at 22:00
  • 1
    (The above details aren't 100% accurate, sometimes there's `--no-merges` and sometimes you can get away with `--right-only`. Before recent changes to make `git rebase` all C code, it was easier to identify which rebases did which thing and what `git rev-list` command they used, as this as all several very large shell scripts.) – torek May 13 '19 at 22:02