largefiles: fix 'hg status' abort after merge
If a largefile is introduced on the branch that is merged into the
working copy, then 'hg status' would abort with an error like:
$ hg status
abort: .hglf/foo@
33fdd332ec64: not found in manifest!
The problem was that the largefiles status code only looked in the
first parent for the largefile. Largefiles are now always reported as
modified if they don't exist in the first parent -- this matches the
behavior of localrepo.status for normal files.
$ cat >> $HGRCPATH <<EOF
> [extensions]
> largefiles=
> purge=
> rebase=
> transplant=
> [largefiles]
> minsize=2
> patterns=glob:**.dat
> EOF
Create the repo with a couple of revisions of both large and normal
files, testing that status correctly shows largefiles.
$ hg init a
$ cd a
$ mkdir sub
$ echo normal1 > normal1
$ echo normal2 > sub/normal2
$ echo large1 > large1
$ echo large2 > sub/large2
$ hg add normal1 sub/normal2
$ hg add --large large1 sub/large2
$ hg commit -m "add files"
$ echo normal11 > normal1
$ echo normal22 > sub/normal2
$ echo large11 > large1
$ echo large22 > sub/large2
$ hg st
M large1
M normal1
M sub/large2
M sub/normal2
$ hg commit -m "edit files"
Commit preserved largefile contents.
$ cat normal1
normal11
$ cat large1
large11
$ cat sub/normal2
normal22
$ cat sub/large2
large22
Remove both largefiles and normal files.
$ hg remove normal1 large1
$ hg commit -m "remove files"
$ ls
sub
Copy both largefiles and normal files (testing that status output is correct).
$ hg cp sub/normal2 normal1
$ hg cp sub/large2 large1
$ hg st
A large1
A normal1
$ hg commit -m "copy files"
$ cat normal1
normal22
$ cat large1
large22
Test moving largefiles and verify that normal files are also unaffected.
$ hg mv normal1 normal3
$ hg mv large1 large3
$ hg mv sub/normal2 sub/normal4
$ hg mv sub/large2 sub/large4
$ hg commit -m "move files"
$ cat normal3
normal22
$ cat large3
large22
$ cat sub/normal4
normal22
$ cat sub/large4
large22
Test archiving the various revisions. These hit corner cases known with
archiving.
$ hg archive -r 0 ../archive0
$ hg archive -r 1 ../archive1
$ hg archive -r 2 ../archive2
$ hg archive -r 3 ../archive3
$ hg archive -r 4 ../archive4
$ cd ../archive0
$ cat normal1
normal1
$ cat large1
large1
$ cat sub/normal2
normal2
$ cat sub/large2
large2
$ cd ../archive1
$ cat normal1
normal11
$ cat large1
large11
$ cat sub/normal2
normal22
$ cat sub/large2
large22
$ cd ../archive2
$ ls
sub
$ cat sub/normal2
normal22
$ cat sub/large2
large22
$ cd ../archive3
$ cat normal1
normal22
$ cat large1
large22
$ cat sub/normal2
normal22
$ cat sub/large2
large22
$ cd ../archive4
$ cat normal3
normal22
$ cat large3
large22
$ cat sub/normal4
normal22
$ cat sub/large4
large22
Commit corner case: specify files to commit.
$ cd ../a
$ echo normal3 > normal3
$ echo large3 > large3
$ echo normal4 > sub/normal4
$ echo large4 > sub/large4
$ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
$ cat normal3
normal3
$ cat large3
large3
$ cat sub/normal4
normal4
$ cat sub/large4
large4
One more commit corner case: commit from a subdirectory.
$ cd ../a
$ echo normal33 > normal3
$ echo large33 > large3
$ echo normal44 > sub/normal4
$ echo large44 > sub/large4
$ cd sub
$ hg commit -m "edit files yet again"
$ cat ../normal3
normal33
$ cat ../large3
large33
$ cat normal4
normal44
$ cat large4
large44
Committing standins is not allowed.
$ cd ..
$ echo large3 > large3
$ hg commit .hglf/large3 -m "try to commit standin"
abort: file ".hglf/large3" is a largefile standin
(commit the largefile itself instead)
[255]
Corner cases for adding largefiles.
$ echo large5 > large5
$ hg add --large large5
$ hg add --large large5
large5 already a largefile
$ mkdir sub2
$ echo large6 > sub2/large6
$ echo large7 > sub2/large7
$ hg add --large sub2
adding sub2/large6 as a largefile
adding sub2/large7 as a largefile
$ hg st
M large3
A large5
A sub2/large6
A sub2/large7
Config settings (pattern **.dat, minsize 2 MB) are respected.
$ echo testdata > test.dat
$ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
$ hg add
adding reallylarge as a largefile
adding test.dat as a largefile
Test that minsize and --lfsize handle float values;
also tests that --lfsize overrides largefiles.minsize.
(0.250 MB = 256 kB = 262144 B)
$ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
$ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
$ hg --config largefiles.minsize=.25 add
adding ratherlarge as a largefile
adding medium
$ hg forget medium
$ hg --config largefiles.minsize=.25 add --lfsize=.125
adding medium as a largefile
$ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
$ hg --config largefiles.minsize=.25 add --lfsize=.125
adding notlarge
$ hg forget notlarge
Test forget on largefiles.
$ hg forget large3 large5 test.dat reallylarge ratherlarge medium
$ hg st
A sub2/large6
A sub2/large7
R large3
? large5
? medium
? notlarge
? ratherlarge
? reallylarge
? test.dat
$ hg commit -m "add/edit more largefiles"
$ hg st
? large3
? large5
? medium
? notlarge
? ratherlarge
? reallylarge
? test.dat
Purge with largefiles: verify that largefiles are still in the working
dir after a purge.
$ hg purge --all
$ cat sub/large4
large44
$ cat sub2/large6
large6
$ cat sub2/large7
large7
Clone a largefiles repo.
$ hg clone . ../b
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
3 largefiles updated, 0 removed
$ cd ../b
$ hg log --template '{rev}:{node|short} {desc|firstline}\n'
7:daea875e9014 add/edit more largefiles
6:4355d653f84f edit files yet again
5:9d5af5072dbd edit files again
4:74c02385b94c move files
3:9e8fbc4bce62 copy files
2:51a0ae4d5864 remove files
1:ce8896473775 edit files
0:30d30fe6a5be add files
$ cat normal3
normal33
$ cat sub/normal4
normal44
$ cat sub/large4
large44
$ cat sub2/large6
large6
$ cat sub2/large7
large7
$ cd ..
$ hg clone a -r 3 c
adding changesets
adding manifests
adding file changes
added 4 changesets with 10 changes to 4 files
updating to branch default
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
2 largefiles updated, 0 removed
$ cd c
$ hg log --template '{rev}:{node|short} {desc|firstline}\n'
3:9e8fbc4bce62 copy files
2:51a0ae4d5864 remove files
1:ce8896473775 edit files
0:30d30fe6a5be add files
$ cat normal1
normal22
$ cat large1
large22
$ cat sub/normal2
normal22
$ cat sub/large2
large22
Old revisions of a clone have correct largefiles content (this also
tests update).
$ hg update -r 1
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
1 largefiles updated, 0 removed
$ cat large1
large11
$ cat sub/large2
large22
Rebasing between two repositories does not revert largefiles to old
revisions (this was a very bad bug that took a lot of work to fix).
$ cd ..
$ hg clone a d
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
3 largefiles updated, 0 removed
$ cd b
$ echo large4-modified > sub/large4
$ echo normal3-modified > normal3
$ hg commit -m "modify normal file and largefile in repo b"
$ cd ../d
$ echo large6-modified > sub2/large6
$ echo normal4-modified > sub/normal4
$ hg commit -m "modify normal file largefile in repo d"
$ cd ..
$ hg clone d e
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
3 largefiles updated, 0 removed
$ cd d
$ hg pull --rebase ../b
pulling from ../b
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 2 changes to 2 files (+1 heads)
getting changed largefiles
1 largefiles updated, 0 removed
saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
nothing to rebase
$ hg log --template '{rev}:{node|short} {desc|firstline}\n'
9:598410d3eb9a modify normal file largefile in repo d
8:a381d2c8c80e modify normal file and largefile in repo b
7:daea875e9014 add/edit more largefiles
6:4355d653f84f edit files yet again
5:9d5af5072dbd edit files again
4:74c02385b94c move files
3:9e8fbc4bce62 copy files
2:51a0ae4d5864 remove files
1:ce8896473775 edit files
0:30d30fe6a5be add files
$ cat normal3
normal3-modified
$ cat sub/normal4
normal4-modified
$ cat sub/large4
large4-modified
$ cat sub2/large6
large6-modified
$ cat sub2/large7
large7
$ cd ../e
$ hg pull ../b
pulling from ../b
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 2 changes to 2 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg rebase
getting changed largefiles
1 largefiles updated, 0 removed
saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
$ hg log
changeset: 9:598410d3eb9a
tag: tip
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: modify normal file largefile in repo d
changeset: 8:a381d2c8c80e
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: modify normal file and largefile in repo b
changeset: 7:daea875e9014
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: add/edit more largefiles
changeset: 6:4355d653f84f
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: edit files yet again
changeset: 5:9d5af5072dbd
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: edit files again
changeset: 4:74c02385b94c
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: move files
changeset: 3:9e8fbc4bce62
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: copy files
changeset: 2:51a0ae4d5864
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: remove files
changeset: 1:ce8896473775
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: edit files
changeset: 0:30d30fe6a5be
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: add files
$ cat normal3
normal3-modified
$ cat sub/normal4
normal4-modified
$ cat sub/large4
large4-modified
$ cat sub2/large6
large6-modified
$ cat sub2/large7
large7
Rollback on largefiles.
$ echo large4-modified-again > sub/large4
$ hg commit -m "Modify large4 again"
$ hg rollback
repository tip rolled back to revision 9 (undo commit)
working directory now based on revision 9
$ hg st
M sub/large4
$ hg log
changeset: 9:598410d3eb9a
tag: tip
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: modify normal file largefile in repo d
changeset: 8:a381d2c8c80e
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: modify normal file and largefile in repo b
changeset: 7:daea875e9014
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: add/edit more largefiles
changeset: 6:4355d653f84f
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: edit files yet again
changeset: 5:9d5af5072dbd
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: edit files again
changeset: 4:74c02385b94c
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: move files
changeset: 3:9e8fbc4bce62
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: copy files
changeset: 2:51a0ae4d5864
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: remove files
changeset: 1:ce8896473775
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: edit files
changeset: 0:30d30fe6a5be
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: add files
$ cat sub/large4
large4-modified-again
"update --check" refuses to update with uncommitted changes.
$ hg update --check 8
abort: uncommitted local changes
[255]
"update --clean" leaves correct largefiles in working copy.
$ hg update --clean
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
1 largefiles updated, 0 removed
$ cat normal3
normal3-modified
$ cat sub/normal4
normal4-modified
$ cat sub/large4
large4-modified
$ cat sub2/large6
large6-modified
$ cat sub2/large7
large7
Now "update check" is happy.
$ hg update --check 8
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
1 largefiles updated, 0 removed
$ hg update --check
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
1 largefiles updated, 0 removed
"revert" works on largefiles (and normal files too).
$ echo hack3 >> normal3
$ echo hack4 >> sub/normal4
$ echo hack4 >> sub/large4
$ hg rm sub2/large6
$ echo new >> sub2/large8
$ hg add --large sub2/large8
# XXX we don't really want to report that we're reverting the standin;
# that's just an implementation detail. But I don't see an obvious fix. ;-(
$ hg revert sub
reverting .hglf/sub/large4
reverting sub/normal4
$ hg status
M normal3
A sub2/large8
R sub2/large6
? sub/large4.orig
? sub/normal4.orig
$ cat sub/normal4
normal4-modified
$ cat sub/large4
large4-modified
$ hg revert -a --no-backup
undeleting .hglf/sub2/large6
forgetting .hglf/sub2/large8
reverting normal3
$ hg status
? sub/large4.orig
? sub/normal4.orig
? sub2/large8
$ cat normal3
normal3-modified
$ cat sub2/large6
large6-modified
$ rm sub/*.orig sub2/large8
revert some files to an older revision
$ hg revert --no-backup -r 8 sub2
reverting .hglf/sub2/large6
$ cat sub2/large6
large6
$ hg revert --no-backup sub2
reverting .hglf/sub2/large6
$ hg status
"verify --large" actually verifies largefiles
$ hg verify --large
checking changesets
checking manifests
crosschecking files in changesets and manifests
checking files
10 files, 10 changesets, 28 total revisions
searching 1 changesets for largefiles
verified existence of 3 revisions of 3 largefiles
Merging does not revert to old versions of largefiles (this has also
been very problematic).
$ cd ..
$ hg clone -r 7 e f
adding changesets
adding manifests
adding file changes
added 8 changesets with 24 changes to 10 files
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
3 largefiles updated, 0 removed
$ cd f
$ echo "large4-merge-test" > sub/large4
$ hg commit -m "Modify large4 to test merge"
$ hg pull ../e
pulling from ../e
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 4 changes to 4 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg merge
merging sub/large4
largefile sub/large4 has a merge conflict
keep (l)ocal or take (o)ther? l
3 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
getting changed largefiles
1 largefiles updated, 0 removed
$ hg commit -m "Merge repos e and f"
$ cat normal3
normal3-modified
$ cat sub/normal4
normal4-modified
$ cat sub/large4
large4-merge-test
$ cat sub2/large6
large6-modified
$ cat sub2/large7
large7
Test status after merging with a branch that introduces a new largefile:
$ echo large > large
$ hg add --large large
$ hg commit -m 'add largefile'
$ hg update -q ".^"
$ echo change >> normal3
$ hg commit -m 'some change'
created new head
$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
getting changed largefiles
1 largefiles updated, 0 removed
$ hg status
M large
Test that a normal file and a largefile with the same name and path cannot
coexist.
$ rm sub2/large7
$ echo "largeasnormal" > sub2/large7
$ hg add sub2/large7
sub2/large7 already a largefile
Test that transplanting a largefile change works correctly.
$ cd ..
$ hg clone -r 8 d g
adding changesets
adding manifests
adding file changes
added 9 changesets with 26 changes to 10 files
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
3 largefiles updated, 0 removed
$ cd g
$ hg transplant -s ../d 598410d3eb9a
searching for changes
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 2 changes to 2 files
getting changed largefiles
1 largefiles updated, 0 removed
$ hg log --template '{rev}:{node|short} {desc|firstline}\n'
9:598410d3eb9a modify normal file largefile in repo d
8:a381d2c8c80e modify normal file and largefile in repo b
7:daea875e9014 add/edit more largefiles
6:4355d653f84f edit files yet again
5:9d5af5072dbd edit files again
4:74c02385b94c move files
3:9e8fbc4bce62 copy files
2:51a0ae4d5864 remove files
1:ce8896473775 edit files
0:30d30fe6a5be add files
$ cat normal3
normal3-modified
$ cat sub/normal4
normal4-modified
$ cat sub/large4
large4-modified
$ cat sub2/large6
large6-modified
$ cat sub2/large7
large7
Test that renaming a largefile results in correct output for status
$ hg rename sub/large4 large4-renamed
$ hg st
A large4-renamed
R sub/large4
$ hg commit -m "test rename output"
$ cat large4-renamed
large4-modified
$ cd sub2
$ hg rename large6 large6-renamed
$ hg st
A sub2/large6-renamed
R sub2/large6
$ cd ../..
vanilla clients not locked out from largefiles servers on vanilla repos
$ mkdir r1
$ cd r1
$ hg init
$ echo c1 > f1
$ hg add f1
$ hg com -m "m1"
$ cd ..
$ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
$ cat hg.pid >> $DAEMON_PIDS
$ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
largefiles clients still work with vanilla servers
$ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
$ cat hg.pid >> $DAEMON_PIDS
$ hg clone http://localhost:$HGPORT1 r3
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
vanilla clients locked out from largefiles http repos
$ mkdir r4
$ cd r4
$ hg init
$ echo c1 > f1
$ hg add --large f1
$ hg com -m "m1"
$ cd ..
$ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
$ cat hg.pid >> $DAEMON_PIDS
$ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
abort: remote error:
This repository uses the largefiles extension.
Please enable it in your Mercurial config file.
[255]
used all HGPORTs, kill all daemons
$ "$TESTDIR/killdaemons.py"
vanilla clients locked out from largefiles ssh repos
$ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
abort: remote error:
This repository uses the largefiles extension.
Please enable it in your Mercurial config file.
[255]
largefiles clients refuse to push largefiles repos to vanilla servers
$ mkdir r6
$ cd r6
$ hg init
$ echo c1 > f1
$ hg add f1
$ hg com -m "m1"
$ cat >> .hg/hgrc <<!
> [web]
> push_ssl = false
> allow_push = *
> !
$ cd ..
$ hg clone r6 r7
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd r7
$ echo c2 > f2
$ hg add --large f2
$ hg com -m "m2"
$ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
$ cat ../hg.pid >> $DAEMON_PIDS
$ hg push http://localhost:$HGPORT
pushing to http://localhost:$HGPORT/
searching for changes
abort: http://localhost:$HGPORT/ does not appear to be a largefile store
[255]
$ cd ..
Clone a local repository owned by another user
We have to simulate that here by setting $HOME and removing write permissions
$ ORIGHOME="$HOME"
$ mkdir alice
$ HOME="`pwd`/alice"
$ cd alice
$ hg init pubrepo
$ cd pubrepo
$ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
$ hg add --large a-large-file
$ hg commit -m "Add a large file"
$ cd ..
$ chmod -R a-w pubrepo
$ cd ..
$ mkdir bob
$ HOME="`pwd`/bob"
$ cd bob
$ hg clone --pull ../alice/pubrepo pubrepo
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
getting changed largefiles
1 largefiles updated, 0 removed
$ cd ..
$ HOME="$ORIGHOME"
Symlink to a large largefile should behave the same as a symlink to a normal file
$ hg init largesymlink
$ cd largesymlink
$ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
$ hg add --large largefile
$ hg commit -m "commit a large file"
$ ln -s largefile largelink
$ hg add largelink
$ hg commit -m "commit a large symlink"
$ rm -f largelink
$ hg up >/dev/null
$ test -f largelink
[1]
$ test -L largelink
[1]
$ rm -f largelink # make next part of the test independent of the previous
$ hg up -C >/dev/null
$ test -f largelink
$ test -L largelink
$ cd ..