merge: fix a copy detection bug (issue672)
When merging rev1 and rev2, we want to search for copies that happened
in rev1 but not in rev2 and vice-versa. We were starting the search at
rev1/rev2 and then going back, stopping as soon as we reached the revno
of the ancestor, but that can miss some cases (see the new
test-issue672).
Now we calculate the revisions that are ancestors of rev1 or rev2 (but
not both) and make sure the search doesn't stop too early.
Simplified test provided by mpm, based on a test case provided by
Edward Lee.
#!/bin/sh
echo "[extensions]" >> $HGRCPATH
echo "mq=" >> $HGRCPATH
echo % help
hg help mq
hg init a
cd a
echo a > a
hg ci -Ama
hg clone . ../k
mkdir b
echo z > b/z
hg ci -Ama
echo % qinit
hg qinit
cd ..
hg init b
echo % -R qinit
hg -R b qinit
hg init c
echo % qinit -c
hg --cwd c qinit -c
hg -R c/.hg/patches st
echo % qnew implies add
hg -R c qnew test.patch
hg -R c/.hg/patches st
echo '% qinit; qinit -c'
hg init d
cd d
hg qinit
hg qinit -c
# qinit -c should create both files if they don't exist
echo ' .hgignore:'
cat .hg/patches/.hgignore
echo ' series:'
cat .hg/patches/series
hg qinit -c 2>&1 | sed -e 's/repository.*already/repository already/'
cd ..
echo '% qinit; <stuff>; qinit -c'
hg init e
cd e
hg qnew A
echo foo > foo
hg add foo
hg qrefresh
hg qnew B
echo >> foo
hg qrefresh
echo status >> .hg/patches/.hgignore
echo bleh >> .hg/patches/.hgignore
hg qinit -c
hg -R .hg/patches status
# qinit -c shouldn't touch these files if they already exist
echo ' .hgignore:'
cat .hg/patches/.hgignore
echo ' series:'
cat .hg/patches/series
cd ..
cd a
echo % qnew -m
hg qnew -m 'foo bar' test.patch
cat .hg/patches/test.patch
echo % qrefresh
echo a >> a
hg qrefresh
sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \
-e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
echo % empty qrefresh
hg qrefresh -X a
echo 'revision:'
hg diff -r -2 -r -1
echo 'patch:'
cat .hg/patches/test.patch
echo 'working dir diff:'
hg diff --nodates -q
# restore things
hg qrefresh
echo % qpop
hg qpop
echo % qpush
hg qpush
cd ..
echo % pop/push outside repo
hg -R a qpop
hg -R a qpush
cd a
hg qnew test2.patch
echo % qrefresh in subdir
cd b
echo a > a
hg add a
hg qrefresh
echo % pop/push -a in subdir
hg qpop -a
hg --traceback qpush -a
echo % qseries
hg qseries
hg qpop
hg qseries -vs
hg qpush
echo % qapplied
hg qapplied
echo % qtop
hg qtop
echo % qprev
hg qprev
echo % qnext
hg qnext
echo % pop, qnext, qprev, qapplied
hg qpop
hg qnext
hg qprev
hg qapplied
echo % commit should fail
hg commit
echo % push should fail
hg push ../../k
echo % qunapplied
hg qunapplied
echo % qpush/qpop with index
hg qnew test1b.patch
echo 1b > 1b
hg add 1b
hg qrefresh
hg qpush 2
hg qpop 0
hg qpush test.patch+1
hg qpush test.patch+2
hg qpop test2.patch-1
hg qpop test2.patch-2
hg qpush test1b.patch+1
echo % push should succeed
hg qpop -a
hg push ../../k
echo % qpush/qpop error codes
errorcode()
{
hg "$@" && echo " $@ succeeds" || echo " $@ fails"
}
# we want to start with some patches applied
hg qpush -a
echo " % pops all patches and succeeds"
errorcode qpop -a
echo " % does nothing and succeeds"
errorcode qpop -a
echo " % fails - nothing else to pop"
errorcode qpop
echo " % pushes a patch and succeeds"
errorcode qpush
echo " % pops a patch and succeeds"
errorcode qpop
echo " % pushes up to test1b.patch and succeeds"
errorcode qpush test1b.patch
echo " % does nothing and succeeds"
errorcode qpush test1b.patch
echo " % does nothing and succeeds"
errorcode qpop test1b.patch
echo " % fails - can't push to this patch"
errorcode qpush test.patch
echo " % fails - can't pop to this patch"
errorcode qpop test2.patch
echo " % pops up to test.patch and succeeds"
errorcode qpop test.patch
echo " % pushes all patches and succeeds"
errorcode qpush -a
echo " % does nothing and succeeds"
errorcode qpush -a
echo " % fails - nothing else to push"
errorcode qpush
echo " % does nothing and succeeds"
errorcode qpush test2.patch
echo % strip
cd ../../b
echo x>x
hg ci -Ama
hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
hg unbundle .hg/strip-backup/*
echo '% cd b; hg qrefresh'
hg init refresh
cd refresh
echo a > a
hg ci -Ama -d'0 0'
hg qnew -mfoo foo
echo a >> a
hg qrefresh
mkdir b
cd b
echo f > f
hg add f
hg qrefresh
sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
echo % hg qrefresh .
hg qrefresh .
sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
hg status
echo % qpush failure
cd ..
hg qrefresh
hg qnew -mbar bar
echo foo > foo
echo bar > bar
hg add foo bar
hg qrefresh
hg qpop -a
echo bar > foo
hg qpush -a
hg st
echo % mq tags
hg log --template '{rev} {tags}\n' -r qparent:qtip
cat >>$HGRCPATH <<EOF
[diff]
git = True
EOF
cd ..
hg init git
cd git
hg qinit
hg qnew -m'new file' new
echo foo > new
chmod +x new
hg add new
hg qrefresh
sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
hg qnew -m'copy file' copy
hg cp new copy
hg qrefresh
sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
hg qpop
hg qpush
hg qdiff
cat >>$HGRCPATH <<EOF
[diff]
git = False
EOF
hg qdiff --git
cd ..
hg init slow
cd slow
hg qinit
echo foo > foo
hg add foo
hg ci -m 'add foo'
hg qnew bar
echo bar > bar
hg add bar
hg mv foo baz
hg qrefresh --git
hg up -C 0
echo >> foo
hg ci -m 'change foo'
hg up -C 1
hg qrefresh --git 2>&1 | grep -v 'saving bundle'
cat .hg/patches/bar
hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
hg qrefresh --git
cat .hg/patches/bar
hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
hg qrefresh
grep 'diff --git' .hg/patches/bar
echo
hg up -C 1
echo >> foo
hg ci -m 'change foo again'
hg up -C 2
hg mv bar quux
hg mv baz bleh
hg qrefresh --git 2>&1 | grep -v 'saving bundle'
cat .hg/patches/bar
hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
hg mv quux fred
hg mv bleh barney
hg qrefresh --git
cat .hg/patches/bar
hg log -vC --template '{rev} {file_copies%filecopy}\n' -r .
echo '% strip again'
cd ..
hg init strip
cd strip
touch foo
hg add foo
hg ci -m 'add foo' -d '0 0'
echo >> foo
hg ci -m 'change foo 1' -d '0 0'
hg up -C 0
echo 1 >> foo
hg ci -m 'change foo 2' -d '0 0'
HGMERGE=true hg merge
hg ci -m merge -d '0 0'
hg log
hg strip 1 2>&1 | sed 's/\(saving bundle to \).*/\1/'
hg log
cd ..
echo '% qclone'
qlog()
{
echo 'main repo:'
hg log --template ' rev {rev}: {desc}\n'
echo 'patch repo:'
hg -R .hg/patches log --template ' rev {rev}: {desc}\n'
}
hg init qclonesource
cd qclonesource
echo foo > foo
hg add foo
hg ci -m 'add foo'
hg qinit -c
hg qnew patch1
echo bar >> foo
hg qrefresh -m 'change foo'
hg qci -m checkpoint
qlog
cd ..
# repo with patches applied
hg qclone qclonesource qclonedest
cd qclonedest
qlog
cd ..
# repo with patches unapplied
cd qclonesource
hg qpop -a
qlog
cd ..
hg qclone qclonesource qclonedest2
cd qclonedest2
qlog
cd ..