just playing with tangled
at gvimdiff 217 lines 8.1 kB view raw view rendered
1# First-class conflicts 2 3 4## Introduction 5 6Conflicts happen when Jujutsu can't figure out how to merge different changes 7made to the same file. For instance, this can happen if two people are working 8on the same file and make different changes to the same part of the file, and 9then their commits are merged together with `jj new` (or one is rebased onto the 10other with `jj rebase`). 11 12Unlike most other VCSs, Jujutsu can record conflicted states in commits. For 13example, if you rebase a commit and it results in a conflict, the conflict will 14be recorded in the rebased commit and the rebase operation will succeed. You can 15then resolve the conflict whenever you want. Conflicted states can be further 16rebased, merged, or backed out. Note that what's stored in the commit is a 17logical representation of the conflict, not conflict *markers*; rebasing a 18conflict doesn't result in a nested conflict markers (see 19[technical doc](technical/conflicts.md) for how this works). 20 21 22## Advantages 23 24The deeper understanding of conflicts has many advantages: 25 26* Removes the need for things like 27 `git rebase/merge/cherry-pick/etc --continue`. Instead, you get a single 28 workflow for resolving conflicts: check out the conflicted commit, resolve 29 conflicts, and amend. 30* Enables the "auto-rebase" feature, where descendants of rewritten commits 31 automatically get rewritten. This feature mostly replaces Mercurial's 32 [Changeset Evolution](https://www.mercurial-scm.org/wiki/ChangesetEvolution). 33* Lets us define the change in a merge commit as being compared to the merged 34 parents. That way, we can rebase merge commits correctly (unlike both Git and 35 Mercurial). That includes conflict resolutions done in the merge commit, 36 addressing a common use case for 37 [git rerere](https://git-scm.com/docs/git-rerere). 38 Since the changes in a merge commit are displayed and rebased as expected, 39 [evil merges](https://git-scm.com/docs/gitglossary/2.22.0#Documentation/gitglossary.txt-aiddefevilmergeaevilmerge) 40 are arguably not as evil anymore. 41* Allows you to postpone conflict resolution until you're ready for it. You 42 can easily keep all your work-in-progress commits rebased onto upstream's head 43 if you like. 44* [Criss-cross merges](https://stackoverflow.com/questions/26370185/how-do-criss-cross-merges-arise-in-git) 45 and [octopus merges](https://git-scm.com/docs/git-merge#Documentation/git-merge.txt-octopus) 46 become trivial (implementation-wise); some cases that Git can't currently 47 handle, or that would result in nested conflict markers, can be automatically 48 resolved. 49* Enables collaborative conflict resolution. (This assumes that you can share 50 the conflicts with others, which you probably shouldn't do if some people 51 interact with your project using Git.) 52 53For information about how conflicts are handled in the working copy, see 54[here](working-copy.md#conflicts). 55 56 57## Conflict markers 58 59Conflicts are "materialized" using *conflict markers* in various contexts. For 60example, when you run `jj new` or `jj edit` on a commit with a conflict, it will 61be materialized in the working copy. Conflicts are also materialized when they 62are part of diff output (e.g. `jj show` on a commit that introduces or resolves 63a conflict). 64 65As an example, imagine that you have a file which contains the following text, 66all in lowercase: 67 68```text 69apple 70grape 71orange 72``` 73 74One person replaces the word "grape" with "grapefruit" in commit A, while 75another person changes every line to uppercase in commit B. If you merge the 76changes together with `jj new A B`, the resulting commit will have a conflict 77since Jujutsu can't figure out how to combine these changes. Therefore, Jujutsu 78will materialize the conflict in the working copy using conflict markers, which 79would look like this: 80 81```text 82<<<<<<< Conflict 1 of 1 83%%%%%%% Changes from base to side #1 84 apple 85-grape 86+grapefruit 87 orange 88+++++++ Contents of side #2 89APPLE 90GRAPE 91ORANGE 92>>>>>>> Conflict 1 of 1 ends 93``` 94 95The markers `<<<<<<<` and `>>>>>>>` indicate the start and end of a conflict 96respectively. The marker `+++++++` indicates the start of a snapshot, while the 97marker `%%%%%%%` indicates the start of a diff to apply to the snapshot. 98Therefore, to resolve this conflict, you would apply the diff (changing "grape" 99to "grapefruit") to the snapshot (the side with every line in uppercase), 100editing the file to look like this: 101 102```text 103APPLE 104GRAPEFRUIT 105ORANGE 106``` 107 108In practice, conflicts are usually 2-sided, meaning that there's only 2 109conflicting changes being merged together at a time, but Jujutsu supports 110conflicts with arbitrarily many sides, which can happen when merging 3 or more 111commits at once. In that case, you would see a single snapshot section and 112multiple diff sections. 113 114Compared to just showing the content of each side of the conflict, the main 115benefit of Jujutsu's style of conflict markers is that you don't need to spend 116time manually comparing the sides to spot the differences between them. This is 117especially beneficial for many-sided conflicts, since resolving them just 118requires applying each diff to the snapshot one-by-one. 119 120## Alternative conflict marker styles 121 122If you prefer to just see the contents of each side of the conflict without the 123diff, Jujutsu also supports a "snapshot" style, which can be enabled by setting 124the `ui.conflict-marker-style` config option to "snapshot": 125 126```text 127<<<<<<< Conflict 1 of 1 128+++++++ Contents of side #1 129apple 130grapefruit 131orange 132------- Contents of base 133apple 134grape 135orange 136+++++++ Contents of side #2 137APPLE 138GRAPE 139ORANGE 140>>>>>>> Conflict 1 of 1 ends 141``` 142 143Some tools expect Git-style conflict markers, so Jujutsu also supports [Git's 144"diff3" style](https://git-scm.com/docs/git-merge#_how_conflicts_are_presented) 145conflict markers by setting the `ui.conflict-marker-style` config option to 146"git": 147 148```text 149<<<<<<< Side #1 (Conflict 1 of 1) 150apple 151grapefruit 152orange 153||||||| Base 154apple 155grape 156orange 157======= 158APPLE 159GRAPE 160ORANGE 161>>>>>>> Side #2 (Conflict 1 of 1 ends) 162``` 163 164This conflict marker style only supports 2-sided conflicts though, so it falls 165back to the similar "snapshot" conflict markers if there are more than 2 sides 166to the conflict. 167 168## Long conflict markers 169 170Some files may contain lines which could be confused for conflict markers. For 171instance, a line could start with `=======`, which looks like a Git-style 172conflict marker. To ensure that it's always unambiguous which lines are conflict 173markers and which are just part of the file contents, `jj` sometimes uses 174conflict markers which are longer than normal: 175 176```text 177<<<<<<<<<<<<<<< Conflict 1 of 1 178%%%%%%%%%%%%%%% Changes from base to side #1 179-Heading 180+HEADING 181 ======= 182+++++++++++++++ Contents of side #2 183New Heading 184=========== 185>>>>>>>>>>>>>>> Conflict 1 of 1 ends 186``` 187 188## Conflicts with missing terminating newline 189 190When materializing conflicts, `jj` outputs them in a line-based format. This 191format is easiest to interpret for text files that consist of a series of lines, 192with each line terminated by a newline character (`\n`). This means that a text 193file should either be empty, or it should end with a newline character. 194 195While most text files follow this convention, some do not. When `jj` encounters 196a missing terminating newline character in a conflict, it will add a comment to 197the conflict markers to make the conflict easier to interpret. If you don't care 198about whether your file ends with a terminating newline character, you can 199generally ignore this comment and resolve the conflict normally. 200 201For instance, if a file originally contained `grape` with no terminating newline 202character, and one person changed `grape` to `grapefruit`, while another person 203added the missing newline character to make `grape\n`, the resulting conflict 204would look like this: 205 206```text 207<<<<<<< Conflict 1 of 1 208+++++++ Contents of side #1 (no terminating newline) 209grapefruit 210%%%%%%% Changes from base to side #2 (adds terminating newline) 211-grape 212+grape 213>>>>>>> Conflict 1 of 1 ends 214``` 215 216Therefore, a resolution of this conflict could be `grapefruit\n`, with the 217terminating newline character added.