mirror of
https://github.com/facebook/sapling.git
synced 2024-10-09 16:31:02 +03:00
2e0675043e
A concern around the user experience of Mercurial is user getting stuck on there own topological branch forever. For example, someone pulling another topological branch, missing that message in pull asking them to merge and getting stuck on there own local branch. The current way to "address" this concern was for bare 'hg update' to target the tipmost (also latest pulled) changesets and complain when the update was not linear. That way, failure to merge newly pulled changesets would result in some kind of failure. Yet the failure was quite obscure, not working in all cases (eg: commit right after pull) and the behavior was very impractical in the common case (eg: issue4673). To be able to change that behavior, we need to provide other ways to alert a user stucks on one of many topological head. We do so with an extra message after bare update: 1 other heads for branch "default" Bookmark get its own special version: 1 other divergent bookmarks for "foobar" There is significant room to improve the message itself, and we should augment it with hint about how to see theses other heads or handle the situation (see in-line comment). But having "a" message is already a significant improvement compared to the existing situation. Once we have it we can iterate on a better version of it. As having such message is an important step toward changing the default destination for update and other nicety, I would like to move forward quickly on getting such message. This was discussed during London - October 2015 Sprint.
444 lines
12 KiB
Perl
444 lines
12 KiB
Perl
#require symlink execbit
|
|
|
|
$ tellmeabout() {
|
|
> if [ -h $1 ]; then
|
|
> echo $1 is a symlink:
|
|
> $TESTDIR/readlink.py $1
|
|
> elif [ -x $1 ]; then
|
|
> echo $1 is an executable file with content:
|
|
> cat $1
|
|
> else
|
|
> echo $1 is a plain file with content:
|
|
> cat $1
|
|
> fi
|
|
> }
|
|
|
|
$ hg init test1
|
|
$ cd test1
|
|
|
|
$ echo a > a
|
|
$ hg ci -Aqmadd
|
|
$ chmod +x a
|
|
$ hg ci -mexecutable
|
|
|
|
$ hg up -q 0
|
|
$ rm a
|
|
$ ln -s symlink a
|
|
$ hg ci -msymlink
|
|
created new head
|
|
|
|
Symlink is local parent, executable is other:
|
|
|
|
$ hg merge --debug
|
|
searching for copies back to rev 1
|
|
resolving manifests
|
|
branchmerge: True, force: False, partial: False
|
|
ancestor: c334dc3be0da, local: 521a1e40188f+, remote: 3574f3e69b1c
|
|
preserving a for resolve of a
|
|
a: versions differ -> m (premerge)
|
|
picked tool ':merge' for a (binary False symlink True changedelete False)
|
|
merging a
|
|
my a@521a1e40188f+ other a@3574f3e69b1c ancestor a@c334dc3be0da
|
|
warning: internal :merge cannot merge symlinks for 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 or 'hg update -C .' to abandon
|
|
[1]
|
|
|
|
$ tellmeabout a
|
|
a is a symlink:
|
|
a -> symlink
|
|
$ hg resolve a --tool internal:other
|
|
(no more unresolved files)
|
|
$ tellmeabout a
|
|
a is an executable file with content:
|
|
a
|
|
$ hg st
|
|
M a
|
|
? a.orig
|
|
|
|
Symlink is other parent, executable is local:
|
|
|
|
$ hg update -C 1
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
|
|
$ hg merge --debug --tool :union
|
|
searching for copies back to rev 1
|
|
resolving manifests
|
|
branchmerge: True, force: False, partial: False
|
|
ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
|
|
preserving a for resolve of a
|
|
a: versions differ -> m (premerge)
|
|
picked tool ':union' for a (binary False symlink True changedelete False)
|
|
merging a
|
|
my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
|
|
warning: internal :union cannot merge symlinks for 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 or 'hg update -C .' to abandon
|
|
[1]
|
|
|
|
$ tellmeabout a
|
|
a is an executable file with content:
|
|
a
|
|
|
|
$ hg update -C 1
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
|
|
$ hg merge --debug --tool :merge3
|
|
searching for copies back to rev 1
|
|
resolving manifests
|
|
branchmerge: True, force: False, partial: False
|
|
ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
|
|
preserving a for resolve of a
|
|
a: versions differ -> m (premerge)
|
|
picked tool ':merge3' for a (binary False symlink True changedelete False)
|
|
merging a
|
|
my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
|
|
warning: internal :merge3 cannot merge symlinks for 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 or 'hg update -C .' to abandon
|
|
[1]
|
|
|
|
$ tellmeabout a
|
|
a is an executable file with content:
|
|
a
|
|
|
|
$ hg update -C 1
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
|
|
$ hg merge --debug --tool :merge-local
|
|
searching for copies back to rev 1
|
|
resolving manifests
|
|
branchmerge: True, force: False, partial: False
|
|
ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
|
|
preserving a for resolve of a
|
|
a: versions differ -> m (premerge)
|
|
picked tool ':merge-local' for a (binary False symlink True changedelete False)
|
|
merging a
|
|
my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
|
|
warning: internal :merge-local cannot merge symlinks for a
|
|
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]
|
|
|
|
$ tellmeabout a
|
|
a is an executable file with content:
|
|
a
|
|
|
|
$ hg update -C 1
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
|
|
$ hg merge --debug --tool :merge-other
|
|
searching for copies back to rev 1
|
|
resolving manifests
|
|
branchmerge: True, force: False, partial: False
|
|
ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
|
|
preserving a for resolve of a
|
|
a: versions differ -> m (premerge)
|
|
picked tool ':merge-other' for a (binary False symlink True changedelete False)
|
|
merging a
|
|
my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
|
|
warning: internal :merge-other cannot merge symlinks for a
|
|
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]
|
|
|
|
$ tellmeabout a
|
|
a is an executable file with content:
|
|
a
|
|
|
|
Update to link without local change should get us a symlink (issue3316):
|
|
|
|
$ hg up -C 0
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
$ hg up
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
1 other heads for branch "default"
|
|
$ hg st
|
|
? a.orig
|
|
|
|
Update to link with local change should cause a merge prompt (issue3200):
|
|
|
|
$ hg up -Cq 0
|
|
$ echo data > a
|
|
$ HGMERGE= hg up -y --debug
|
|
searching for copies back to rev 2
|
|
resolving manifests
|
|
branchmerge: False, force: False, partial: False
|
|
ancestor: c334dc3be0da, local: c334dc3be0da+, remote: 521a1e40188f
|
|
preserving a for resolve of a
|
|
a: versions differ -> m (premerge)
|
|
(couldn't find merge tool hgmerge|tool hgmerge can't handle symlinks) (re)
|
|
picked tool ':prompt' for a (binary False symlink True changedelete False)
|
|
no tool found to merge a
|
|
keep (l)ocal, take (o)ther, or leave (u)nresolved? u
|
|
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges
|
|
1 other heads for branch "default"
|
|
[1]
|
|
$ hg diff --git
|
|
diff --git a/a b/a
|
|
old mode 120000
|
|
new mode 100644
|
|
--- a/a
|
|
+++ b/a
|
|
@@ -1,1 +1,1 @@
|
|
-symlink
|
|
\ No newline at end of file
|
|
+data
|
|
|
|
|
|
Test only 'l' change - happens rarely, except when recovering from situations
|
|
where that was what happened.
|
|
|
|
$ hg init test2
|
|
$ cd test2
|
|
$ printf base > f
|
|
$ hg ci -Aqm0
|
|
$ echo file > f
|
|
$ echo content >> f
|
|
$ hg ci -qm1
|
|
$ hg up -qr0
|
|
$ rm f
|
|
$ ln -s base f
|
|
$ hg ci -qm2
|
|
$ hg merge
|
|
merging f
|
|
warning: internal :merge cannot merge symlinks for f
|
|
warning: conflicts while merging f! (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]
|
|
$ tellmeabout f
|
|
f is a symlink:
|
|
f -> base
|
|
|
|
$ hg up -Cqr1
|
|
$ hg merge
|
|
merging f
|
|
warning: internal :merge cannot merge symlinks for f
|
|
warning: conflicts while merging f! (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]
|
|
$ tellmeabout f
|
|
f is a plain file with content:
|
|
file
|
|
content
|
|
|
|
$ cd ..
|
|
|
|
Test removed 'x' flag merged with change to symlink
|
|
|
|
$ hg init test3
|
|
$ cd test3
|
|
$ echo f > f
|
|
$ chmod +x f
|
|
$ hg ci -Aqm0
|
|
$ chmod -x f
|
|
$ hg ci -qm1
|
|
$ hg up -qr0
|
|
$ rm f
|
|
$ ln -s dangling f
|
|
$ hg ci -qm2
|
|
$ hg merge
|
|
merging f
|
|
warning: internal :merge cannot merge symlinks for f
|
|
warning: conflicts while merging f! (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]
|
|
$ tellmeabout f
|
|
f is a symlink:
|
|
f -> dangling
|
|
|
|
$ hg up -Cqr1
|
|
$ hg merge
|
|
merging f
|
|
warning: internal :merge cannot merge symlinks for f
|
|
warning: conflicts while merging f! (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]
|
|
$ tellmeabout f
|
|
f is a plain file with content:
|
|
f
|
|
|
|
Test removed 'x' flag merged with content change - both ways
|
|
|
|
$ hg up -Cqr0
|
|
$ echo change > f
|
|
$ hg ci -qm3
|
|
$ hg merge -r1
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
(branch merge, don't forget to commit)
|
|
$ tellmeabout f
|
|
f is a plain file with content:
|
|
change
|
|
|
|
$ hg up -qCr1
|
|
$ hg merge -r3
|
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
|
(branch merge, don't forget to commit)
|
|
$ tellmeabout f
|
|
f is a plain file with content:
|
|
change
|
|
|
|
$ cd ..
|
|
|
|
Test merge with no common ancestor:
|
|
a: just different
|
|
b: x vs -, different (cannot calculate x, cannot ask merge tool)
|
|
c: x vs -, same (cannot calculate x, merge tool is no good)
|
|
d: x vs l, different
|
|
e: x vs l, same
|
|
f: - vs l, different
|
|
g: - vs l, same
|
|
h: l vs l, different
|
|
(where same means the filelog entry is shared and there thus is an ancestor!)
|
|
|
|
$ hg init test4
|
|
$ cd test4
|
|
$ echo 0 > 0
|
|
$ hg ci -Aqm0
|
|
|
|
$ echo 1 > a
|
|
$ echo 1 > b
|
|
$ chmod +x b
|
|
$ echo x > c
|
|
$ chmod +x c
|
|
$ echo 1 > d
|
|
$ chmod +x d
|
|
$ printf x > e
|
|
$ chmod +x e
|
|
$ echo 1 > f
|
|
$ printf x > g
|
|
$ ln -s 1 h
|
|
$ hg ci -qAm1
|
|
|
|
$ hg up -qr0
|
|
$ echo 2 > a
|
|
$ echo 2 > b
|
|
$ echo x > c
|
|
$ ln -s 2 d
|
|
$ ln -s x e
|
|
$ ln -s 2 f
|
|
$ ln -s x g
|
|
$ ln -s 2 h
|
|
$ hg ci -Aqm2
|
|
|
|
$ hg merge
|
|
merging a
|
|
warning: cannot merge flags for b
|
|
merging b
|
|
warning: cannot merge flags for c
|
|
merging d
|
|
warning: internal :merge cannot merge symlinks for d
|
|
warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
|
|
merging f
|
|
warning: internal :merge cannot merge symlinks for f
|
|
warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
|
|
merging h
|
|
warning: internal :merge cannot merge symlinks for h
|
|
warning: conflicts while merging h! (edit, then use 'hg resolve --mark')
|
|
warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
|
|
3 files updated, 0 files merged, 0 files removed, 5 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
|
|
[1]
|
|
$ hg resolve -l
|
|
U a
|
|
U b
|
|
U d
|
|
U f
|
|
U h
|
|
$ tellmeabout a
|
|
a is a plain file with content:
|
|
<<<<<<< local: 0139c5610547 - test: 2
|
|
2
|
|
=======
|
|
1
|
|
>>>>>>> other: 97e29675e796 - test: 1
|
|
$ tellmeabout b
|
|
b is a plain file with content:
|
|
<<<<<<< local: 0139c5610547 - test: 2
|
|
2
|
|
=======
|
|
1
|
|
>>>>>>> other: 97e29675e796 - test: 1
|
|
$ tellmeabout c
|
|
c is a plain file with content:
|
|
x
|
|
$ tellmeabout d
|
|
d is a symlink:
|
|
d -> 2
|
|
$ tellmeabout e
|
|
e is a symlink:
|
|
e -> x
|
|
$ tellmeabout f
|
|
f is a symlink:
|
|
f -> 2
|
|
$ tellmeabout g
|
|
g is a symlink:
|
|
g -> x
|
|
$ tellmeabout h
|
|
h is a symlink:
|
|
h -> 2
|
|
|
|
$ hg up -Cqr1
|
|
$ hg merge
|
|
merging a
|
|
warning: cannot merge flags for b
|
|
merging b
|
|
warning: cannot merge flags for c
|
|
merging d
|
|
warning: internal :merge cannot merge symlinks for d
|
|
warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
|
|
merging f
|
|
warning: internal :merge cannot merge symlinks for f
|
|
warning: conflicts while merging f! (edit, then use 'hg resolve --mark')
|
|
merging h
|
|
warning: internal :merge cannot merge symlinks for h
|
|
warning: conflicts while merging h! (edit, then use 'hg resolve --mark')
|
|
warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
|
|
warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
|
|
3 files updated, 0 files merged, 0 files removed, 5 files unresolved
|
|
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
|
|
[1]
|
|
$ tellmeabout a
|
|
a is a plain file with content:
|
|
<<<<<<< local: 97e29675e796 - test: 1
|
|
1
|
|
=======
|
|
2
|
|
>>>>>>> other: 0139c5610547 - test: 2
|
|
$ tellmeabout b
|
|
b is an executable file with content:
|
|
<<<<<<< local: 97e29675e796 - test: 1
|
|
1
|
|
=======
|
|
2
|
|
>>>>>>> other: 0139c5610547 - test: 2
|
|
$ tellmeabout c
|
|
c is an executable file with content:
|
|
x
|
|
$ tellmeabout d
|
|
d is an executable file with content:
|
|
1
|
|
$ tellmeabout e
|
|
e is an executable file with content:
|
|
x (no-eol)
|
|
$ tellmeabout f
|
|
f is a plain file with content:
|
|
1
|
|
$ tellmeabout g
|
|
g is a plain file with content:
|
|
x (no-eol)
|
|
$ tellmeabout h
|
|
h is a symlink:
|
|
h -> 1
|
|
|
|
$ cd ..
|