mirror of
https://github.com/facebook/sapling.git
synced 2024-10-09 16:31:02 +03:00
2a4db136e5
Summary: Written by Martin von Zweigbergk at https://phab.mercurial-scm.org/D9551, or https://www.mercurial-scm.org/repo/hg/rev/bdc2bf68f19e. He suggested it and it's a useful feature. I did minor compatibility changes (encoding, avoid rev numbers, foo_bar -> foobar). Original commit message: I use 3-way conflict markers. Often when I resolve them, I manually compare one the base with one side and apply the differences to the other side. That can be hard when the conflict marker is large. This patch introduces a new type of conflict marker, which I'm hoping will make it easier to resolve conflicts. The new format uses `<<<<<<<` and `>>>>>>>` to open and close the markers, just like our existing 2-way and 3-way conflict markers. Instead of having 2 or 3 snapshots (left+right or left+base+right), it has a sequence of diffs. A diff looks like this: ``` ------- base +++++++ left a -b +c d ``` A diff that adds one side ("diff from nothing") has a `=======` header instead and does not have have `+` prefixed on its lines. A regular 3-way merge can be viewed as adding one side plus a diff between the base and the other side. It thus has two ways of being represented, depending on which side is being diffed: ``` <<<<<<< ======= left contents on left ------- base +++++++ right contents on -left +right >>>>>>> ``` or ``` <<<<<<< ------- base +++++++ left contents on -right +left ======= right contents on right >>>>>>> ``` I've made it so the new merge tool tries to pick a version that has the most common lines (no difference in the example above). I've called the new tool "mergediff" to stick to the convention of starting with "merge" if the tool tries a regular 3-way merge. The idea came from my pet VCS (placeholder name `jj`), which has support for octopus merges and other ways of ending up with merges of more than 3 versions. I wanted to be able to represent such conflicts in the working copy and therefore thought of this format (although I have not yet implemented it in my VCS). I then attended a meeting with Larry McVoy, who said BitKeeper has an option (`bk smerge -g`) for showing a similar format, which reminded me to actually attempt this in Mercurial. Reviewed By: DurhamG Differential Revision: D26947920 fbshipit-source-id: 8b4446862897ff9a6dfdf5a2e35617d4db09e883
375 lines
7.7 KiB
Perl
375 lines
7.7 KiB
Perl
#chg-compatible
|
|
|
|
$ hg init repo
|
|
$ cd repo
|
|
$ cat << EOF > a
|
|
> Small Mathematical Series.
|
|
> One
|
|
> Two
|
|
> Three
|
|
> Four
|
|
> Five
|
|
> Hop we are done.
|
|
> EOF
|
|
$ hg add a
|
|
$ hg commit -m ancestor
|
|
$ cat << EOF > a
|
|
> Small Mathematical Series.
|
|
> 1
|
|
> 2
|
|
> 3
|
|
> 4
|
|
> 5
|
|
> Hop we are done.
|
|
> EOF
|
|
$ hg commit -m branch1
|
|
$ hg co 'desc(ancestor)'
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
$ cat << EOF > a
|
|
> Small Mathematical Series.
|
|
> 1
|
|
> 2
|
|
> 3
|
|
> 6
|
|
> 8
|
|
> Hop we are done.
|
|
> EOF
|
|
$ hg commit -m branch2
|
|
|
|
$ hg merge 'desc(branch1)'
|
|
merging a
|
|
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
|
|
[1]
|
|
|
|
$ hg id
|
|
618808747361+c0c68e4fe667+
|
|
|
|
$ echo "[commands]" >> $HGRCPATH
|
|
$ echo "status.verbose=true" >> $HGRCPATH
|
|
$ hg status
|
|
M a
|
|
? a.orig
|
|
# The repository is in an unfinished *merge* state.
|
|
|
|
# Unresolved merge conflicts:
|
|
#
|
|
# a
|
|
#
|
|
# To mark files as resolved: hg resolve --mark FILE
|
|
|
|
# To continue: hg commit
|
|
# To abort: hg update --clean . (warning: this will discard uncommitted changes)
|
|
|
|
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
<<<<<<< working copy: 618808747361 - test: branch2
|
|
6
|
|
8
|
|
=======
|
|
4
|
|
5
|
|
>>>>>>> merge rev: c0c68e4fe667 - test: branch1
|
|
Hop we are done.
|
|
|
|
$ hg status --config commands.status.verbose=0
|
|
M a
|
|
? a.orig
|
|
|
|
Verify custom conflict markers
|
|
|
|
$ hg up -q --clean .
|
|
$ cat <<EOF >> .hg/hgrc
|
|
> [ui]
|
|
> mergemarkertemplate = '{author} {node}'
|
|
> EOF
|
|
|
|
$ hg merge 'desc(branch1)'
|
|
merging a
|
|
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
|
|
[1]
|
|
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
<<<<<<< working copy: test 6188087473610f9c9c11296d35620d7e0d35f796
|
|
6
|
|
8
|
|
=======
|
|
4
|
|
5
|
|
>>>>>>> merge rev: test c0c68e4fe667f80c031c0e5871bcb12fae657a57
|
|
Hop we are done.
|
|
|
|
Verify line splitting of custom conflict marker which causes multiple lines
|
|
|
|
$ hg up -q --clean .
|
|
$ cat >> .hg/hgrc <<EOF
|
|
> [ui]
|
|
> mergemarkertemplate={author} {node}\nfoo\nbar\nbaz
|
|
> EOF
|
|
|
|
$ hg -q merge 'desc(branch1)'
|
|
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
[1]
|
|
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
<<<<<<< working copy: test 6188087473610f9c9c11296d35620d7e0d35f796
|
|
6
|
|
8
|
|
=======
|
|
4
|
|
5
|
|
>>>>>>> merge rev: test c0c68e4fe667f80c031c0e5871bcb12fae657a57
|
|
Hop we are done.
|
|
|
|
Verify line trimming of custom conflict marker using multi-byte characters
|
|
|
|
$ hg up -q --clean .
|
|
$ $PYTHON <<EOF
|
|
> fp = open('logfile', 'wb')
|
|
> fp.write(b'12345678901234567890123456789012345678901234567890' +
|
|
> b'1234567890') # there are 5 more columns for 80 columns
|
|
>
|
|
> # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
|
|
> fp.write(b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88')
|
|
>
|
|
> fp.close()
|
|
> EOF
|
|
$ hg add logfile
|
|
$ hg --encoding utf-8 commit --logfile logfile
|
|
|
|
$ cat >> .hg/hgrc <<EOF
|
|
> [ui]
|
|
> mergemarkertemplate={desc|firstline}
|
|
> EOF
|
|
|
|
$ hg -q --encoding utf-8 merge 'desc(branch1)'
|
|
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
[1]
|
|
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
<<<<<<< working copy: 1234567890123456789012345678901234567890123456789012345...
|
|
6
|
|
8
|
|
=======
|
|
4
|
|
5
|
|
>>>>>>> merge rev: branch1
|
|
Hop we are done.
|
|
|
|
Verify basic conflict markers
|
|
|
|
$ hg up -q --clean 'desc(branch2)'
|
|
$ printf "\n[ui]\nmergemarkers=basic\n" >> .hg/hgrc
|
|
|
|
$ hg merge 'desc(branch1)'
|
|
merging a
|
|
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
|
|
[1]
|
|
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
<<<<<<< working copy
|
|
6
|
|
8
|
|
=======
|
|
4
|
|
5
|
|
>>>>>>> merge rev
|
|
Hop we are done.
|
|
|
|
internal:merge3
|
|
|
|
$ hg up -q --clean .
|
|
|
|
$ hg merge 'desc(branch1)' --tool internal:merge3
|
|
merging a
|
|
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
|
|
[1]
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
<<<<<<< working copy
|
|
1
|
|
2
|
|
3
|
|
6
|
|
8
|
|
||||||| base
|
|
One
|
|
Two
|
|
Three
|
|
Four
|
|
Five
|
|
=======
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
>>>>>>> merge rev
|
|
Hop we are done.
|
|
|
|
Add some unconflicting changes on each head, to make sure we really
|
|
are merging, unlike :local and :other
|
|
|
|
$ hg up -C
|
|
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
updated to "e0693e20f496: 123456789012345678901234567890123456789012345678901234567890\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88" (esc)
|
|
1 other heads for branch "default"
|
|
$ printf "\n\nEnd of file\n" >> a
|
|
$ hg ci -m "Add some stuff at the end"
|
|
$ hg up -r 'desc(branch1)'
|
|
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
|
|
$ printf "Start of file\n\n\n" > tmp
|
|
$ cat a >> tmp
|
|
$ mv tmp a
|
|
$ hg ci -m "Add some stuff at the beginning"
|
|
|
|
Now test :merge-other and :merge-local
|
|
|
|
$ hg merge
|
|
merging a
|
|
warning: 1 conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
1 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
|
|
[1]
|
|
$ hg resolve --tool :merge-other a
|
|
merging a
|
|
(no more unresolved files)
|
|
$ cat a
|
|
Start of file
|
|
|
|
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
6
|
|
8
|
|
Hop we are done.
|
|
|
|
|
|
End of file
|
|
|
|
$ hg up -C
|
|
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
|
|
updated to "18b51d585961: Add some stuff at the beginning"
|
|
1 other heads for branch "default"
|
|
$ hg merge --tool :merge-local
|
|
merging a
|
|
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
(branch merge, don't forget to commit)
|
|
$ cat a
|
|
Start of file
|
|
|
|
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
Hop we are done.
|
|
|
|
|
|
End of file
|
|
|
|
internal:mergediff
|
|
|
|
$ hg co -C 'desc(branch1)'
|
|
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
|
|
$ cat << EOF > a
|
|
> Small Mathematical Series.
|
|
> 1
|
|
> 2
|
|
> 3
|
|
> 4
|
|
> 4.5
|
|
> 5
|
|
> Hop we are done.
|
|
> EOF
|
|
$ hg co -m 'desc(branch2)' -t internal:mergediff
|
|
merging a
|
|
warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges
|
|
[1]
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
3
|
|
<<<<<<<
|
|
------- base
|
|
+++++++ working copy
|
|
4
|
|
+4.5
|
|
5
|
|
======= destination
|
|
6
|
|
8
|
|
>>>>>>>
|
|
Hop we are done.
|
|
Test the same thing as above but modify a bit more so we instead get the working
|
|
copy in full and the diff from base to destination.
|
|
$ hg co -C 'desc(branch1)'
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
$ cat << EOF > a
|
|
> Small Mathematical Series.
|
|
> 1
|
|
> 2
|
|
> 3.5
|
|
> 4.5
|
|
> 5.5
|
|
> Hop we are done.
|
|
> EOF
|
|
$ hg co -m 'desc(branch2)' -t internal:mergediff
|
|
merging a
|
|
warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges
|
|
[1]
|
|
$ cat a
|
|
Small Mathematical Series.
|
|
1
|
|
2
|
|
<<<<<<<
|
|
======= working copy
|
|
3.5
|
|
4.5
|
|
5.5
|
|
------- base
|
|
+++++++ destination
|
|
3
|
|
-4
|
|
-5
|
|
+6
|
|
+8
|
|
>>>>>>>
|
|
Hop we are done.
|