From: Elijah Newren <newren@xxxxxxxxx> Signed-off-by: Elijah Newren <newren@xxxxxxxxx> --- Documentation/git-rebase.txt | 102 +++++++++++++++++++++--- t/t3433-rebase-options-compatibility.sh | 5 +- 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index ff32ca1080..f1ace07c38 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -409,13 +409,10 @@ your branch contains commits which were dropped, this option can be used with `--keep-base` in order to drop those commits from your branch. --ignore-whitespace:: - Behaves differently depending on which backend is selected. -+ -'am' backend: When applying a patch, ignore changes in whitespace in -context lines if necessary. -+ -'interactive' backend: Treat lines with only whitespace changes as -unchanged for the sake of a three-way merge. + Ignore whitespace-only changes in the commits being rebased, + which may avoid "unnecessary" conflicts. (Both backends + currently have differing edgecase bugs with this option; see + BEHAVIORAL DIFFERENCES.) --whitespace=<option>:: This flag is passed to the 'git apply' program @@ -609,9 +606,94 @@ There are some subtle differences how the backends behave. Directory rename detection ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Directory rename heuristics are enabled in the merge and interactive -backends. Due to the lack of accurate tree information, directory -rename detection is disabled in the am backend. +Due to the lack of accurate tree information (arising from +constructing fake ancestors with the limited information available in +patches), directory rename detection is disabled in the am backend. +Disabled directory rename detection means that if one side of history +renames a directory and the other adds new files to the old directory, +then the new files will be left behind in the old directory without +any warning at the time of rebasing that you may want to move these +files into the new directory. + +Directory rename detection works with the merge and interactive +backends to provide you warnings in such cases. + +Context +~~~~~~~ + +The am backend works by creating a sequence of patches (by calling +`format-patch` internally), and then applying the patches in sequence +(calling `am` internally). Patches are composed of multiple hunks, +each with line numbers, a context region, and the actual changes. The +line numbers have to be taken with some fuzz, since the other side +will likely have inserted or deleted lines earlier in the file. The +context region is meant to help find how to adjust the line numbers in +order to apply the changes to the right lines. However, if multiple +areas of the code have the same surrounding lines of context, the +wrong one can be picked. There are real-world cases where this has +caused commits to be reapplied incorrectly with no conflicts reported. +Setting diff.context to a larger value may prevent such types of +problems, but increases the chance of spurious conflicts (since it +will require more lines of matching context to apply). + +The interactive backend works with a full copy of each relevant file, +insulating it from these types of problems. + +Labelling of conflicts markers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When there are content conflicts, the merge machinery tries to +annotate each side's conflict markers with the commits where the +content came from. Since the am backend drops the original +information about the rebased commits and their parents (and instead +generates new fake commits based off limited information in the +generated patches), those commits cannot be identified; instead it has +to fall back to a commit summary. Also, when merge.conflictStyle is +set to diff3, the am backend will use "constructed merge base" to +label the content from the merge base, and thus provide no information +about the merge base commit whatsoever. + +The interactive backend works with the full commits on both sides of +history and thus has no such limitations. + +--ignore-whitespace +~~~~~~~~~~~~~~~~~~~ + +The --ignore-whitespace option is supposed to ignore whitespace-only +changes if it allows the code to merge cleanly. Unfortunately, the +different backends implement this differently, and both have different +edge case bugs. ++ +'am' backend: When applying a patch, ignore changes in whitespace in +context lines if necessary. (Which implies that if the whitespace +change was not in the context lines but on a line with a real change, +then the rebase will still fail with "unnecessary" content conflicts.) ++ +'interactive' backend: Treat lines with only whitespace changes as +unchanged for the sake of a three-way merge. This means that if one +side made no changes and the commits being rebased had whitespace-only +changes, those whitespaces fixups will be discarded despite the fact +that they present no content conflict. + +Miscellaneous differences +~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are a few more behavioral differences that most folks would +probably consider inconsequential but which are mentioned for +completeness: + +* Reflog: The two backends will use different wording when describing + the changes made in the reflog, though both will make use of the + word "rebase". + +* Progress, informational, and error messages: The two backends + provide slightly different progress and informational messages. + Also, the am backend writes error messages (such as "Your files + would be overwritten...") to stdout, while the interactive backend + writes them to stderr. + +* State directories: The two backends keep their state in different + directories under .git/ include::merge-strategies.txt[] diff --git a/t/t3433-rebase-options-compatibility.sh b/t/t3433-rebase-options-compatibility.sh index 5166f158dd..bd4d2d2f63 100755 --- a/t/t3433-rebase-options-compatibility.sh +++ b/t/t3433-rebase-options-compatibility.sh @@ -10,9 +10,8 @@ test_description='tests to ensure compatibility between am and interactive backe GIT_AUTHOR_DATE="1999-04-02T08:03:20+05:30" export GIT_AUTHOR_DATE -# This is a special case in which both am and interactive backends -# provide the same output. It was done intentionally because -# both the backends fall short of optimal behaviour. +# This is a common case in which both am and interactive backends +# provide the same output with --ignore-whitespace. test_expect_success 'setup' ' git checkout -b topic && q_to_tab >file <<-\EOF && -- gitgitgadget