Show More
@@ -1,165 +1,170 b'' | |||||
1 | # Copyright (C) 2015 - Mike Edgar <adgar@google.com> |
|
1 | # Copyright (C) 2015 - Mike Edgar <adgar@google.com> | |
2 | # |
|
2 | # | |
3 | # This extension enables removal of file content at a given revision, |
|
3 | # This extension enables removal of file content at a given revision, | |
4 | # rewriting the data/metadata of successive revisions to preserve revision log |
|
4 | # rewriting the data/metadata of successive revisions to preserve revision log | |
5 | # integrity. |
|
5 | # integrity. | |
6 |
|
6 | |||
7 | """erase file content at a given revision |
|
7 | """erase file content at a given revision | |
8 |
|
8 | |||
9 | The censor command instructs Mercurial to erase all content of a file at a given |
|
9 | The censor command instructs Mercurial to erase all content of a file at a given | |
10 | revision *without updating the changeset hash.* This allows existing history to |
|
10 | revision *without updating the changeset hash.* This allows existing history to | |
11 | remain valid while preventing future clones/pulls from receiving the erased |
|
11 | remain valid while preventing future clones/pulls from receiving the erased | |
12 | data. |
|
12 | data. | |
13 |
|
13 | |||
14 | Typical uses for censor are due to security or legal requirements, including:: |
|
14 | Typical uses for censor are due to security or legal requirements, including:: | |
15 |
|
15 | |||
16 | * Passwords, private keys, crytographic material |
|
16 | * Passwords, private keys, crytographic material | |
17 | * Licensed data/code/libraries for which the license has expired |
|
17 | * Licensed data/code/libraries for which the license has expired | |
18 | * Personally Identifiable Information or other private data |
|
18 | * Personally Identifiable Information or other private data | |
19 |
|
19 | |||
20 | Censored nodes can interrupt mercurial's typical operation whenever the excised |
|
20 | Censored nodes can interrupt mercurial's typical operation whenever the excised | |
21 | data needs to be materialized. Some commands, like ``hg cat``/``hg revert``, |
|
21 | data needs to be materialized. Some commands, like ``hg cat``/``hg revert``, | |
22 | simply fail when asked to produce censored data. Others, like ``hg verify`` and |
|
22 | simply fail when asked to produce censored data. Others, like ``hg verify`` and | |
23 | ``hg update``, must be capable of tolerating censored data to continue to |
|
23 | ``hg update``, must be capable of tolerating censored data to continue to | |
24 | function in a meaningful way. Such commands only tolerate censored file |
|
24 | function in a meaningful way. Such commands only tolerate censored file | |
25 | revisions if they are allowed by the "censor.policy=ignore" config option. |
|
25 | revisions if they are allowed by the "censor.policy=ignore" config option. | |
26 | """ |
|
26 | """ | |
27 |
|
27 | |||
28 | from mercurial.node import short |
|
28 | from mercurial.node import short | |
29 | from mercurial import cmdutil, error, filelog, revlog, scmutil, util |
|
29 | from mercurial import cmdutil, error, filelog, revlog, scmutil, util | |
30 | from mercurial.i18n import _ |
|
30 | from mercurial.i18n import _ | |
31 |
|
31 | |||
32 | cmdtable = {} |
|
32 | cmdtable = {} | |
33 | command = cmdutil.command(cmdtable) |
|
33 | command = cmdutil.command(cmdtable) | |
34 | # Note for extension authors: ONLY specify testedwith = 'internal' for |
|
34 | # Note for extension authors: ONLY specify testedwith = 'internal' for | |
35 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
35 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
36 | # be specifying the version(s) of Mercurial they are tested with, or |
|
36 | # be specifying the version(s) of Mercurial they are tested with, or | |
37 | # leave the attribute unspecified. |
|
37 | # leave the attribute unspecified. | |
38 | testedwith = 'internal' |
|
38 | testedwith = 'internal' | |
39 |
|
39 | |||
40 | @command('censor', |
|
40 | @command('censor', | |
41 | [('r', 'rev', '', _('censor file from specified revision'), _('REV')), |
|
41 | [('r', 'rev', '', _('censor file from specified revision'), _('REV')), | |
42 | ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))], |
|
42 | ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))], | |
43 | _('-r REV [-t TEXT] [FILE]')) |
|
43 | _('-r REV [-t TEXT] [FILE]')) | |
44 | def censor(ui, repo, path, rev='', tombstone='', **opts): |
|
44 | def censor(ui, repo, path, rev='', tombstone='', **opts): | |
45 | if not path: |
|
45 | if not path: | |
46 | raise util.Abort(_('must specify file path to censor')) |
|
46 | raise util.Abort(_('must specify file path to censor')) | |
47 | if not rev: |
|
47 | if not rev: | |
48 | raise util.Abort(_('must specify revision to censor')) |
|
48 | raise util.Abort(_('must specify revision to censor')) | |
49 |
|
49 | |||
|
50 | wctx = repo[None] | |||
|
51 | ||||
|
52 | m = scmutil.match(wctx, (path,)) | |||
|
53 | if m.anypats() or len(m.files()) != 1: | |||
|
54 | raise util.Abort(_('can only specify an explicit filename')) | |||
|
55 | path = m.files()[0] | |||
50 | flog = repo.file(path) |
|
56 | flog = repo.file(path) | |
51 | if not len(flog): |
|
57 | if not len(flog): | |
52 | raise util.Abort(_('cannot censor file with no history')) |
|
58 | raise util.Abort(_('cannot censor file with no history')) | |
53 |
|
59 | |||
54 | rev = scmutil.revsingle(repo, rev, rev).rev() |
|
60 | rev = scmutil.revsingle(repo, rev, rev).rev() | |
55 | try: |
|
61 | try: | |
56 | ctx = repo[rev] |
|
62 | ctx = repo[rev] | |
57 | except KeyError: |
|
63 | except KeyError: | |
58 | raise util.Abort(_('invalid revision identifier %s') % rev) |
|
64 | raise util.Abort(_('invalid revision identifier %s') % rev) | |
59 |
|
65 | |||
60 | try: |
|
66 | try: | |
61 | fctx = ctx.filectx(path) |
|
67 | fctx = ctx.filectx(path) | |
62 | except error.LookupError: |
|
68 | except error.LookupError: | |
63 | raise util.Abort(_('file does not exist at revision %s') % rev) |
|
69 | raise util.Abort(_('file does not exist at revision %s') % rev) | |
64 |
|
70 | |||
65 | fnode = fctx.filenode() |
|
71 | fnode = fctx.filenode() | |
66 | headctxs = [repo[c] for c in repo.heads()] |
|
72 | headctxs = [repo[c] for c in repo.heads()] | |
67 | heads = [c for c in headctxs if path in c and c.filenode(path) == fnode] |
|
73 | heads = [c for c in headctxs if path in c and c.filenode(path) == fnode] | |
68 | if heads: |
|
74 | if heads: | |
69 | headlist = ', '.join([short(c.node()) for c in heads]) |
|
75 | headlist = ', '.join([short(c.node()) for c in heads]) | |
70 | raise util.Abort(_('cannot censor file in heads (%s)') % headlist, |
|
76 | raise util.Abort(_('cannot censor file in heads (%s)') % headlist, | |
71 | hint=_('clean/delete and commit first')) |
|
77 | hint=_('clean/delete and commit first')) | |
72 |
|
78 | |||
73 | wctx = repo[None] |
|
|||
74 | wp = wctx.parents() |
|
79 | wp = wctx.parents() | |
75 | if ctx.node() in [p.node() for p in wp]: |
|
80 | if ctx.node() in [p.node() for p in wp]: | |
76 | raise util.Abort(_('cannot censor working directory'), |
|
81 | raise util.Abort(_('cannot censor working directory'), | |
77 | hint=_('clean/delete/update first')) |
|
82 | hint=_('clean/delete/update first')) | |
78 |
|
83 | |||
79 | flogv = flog.version & 0xFFFF |
|
84 | flogv = flog.version & 0xFFFF | |
80 | if flogv != revlog.REVLOGNG: |
|
85 | if flogv != revlog.REVLOGNG: | |
81 | raise util.Abort( |
|
86 | raise util.Abort( | |
82 | _('censor does not support revlog version %d') % (flogv,)) |
|
87 | _('censor does not support revlog version %d') % (flogv,)) | |
83 |
|
88 | |||
84 | tombstone = filelog.packmeta({"censored": tombstone}, "") |
|
89 | tombstone = filelog.packmeta({"censored": tombstone}, "") | |
85 |
|
90 | |||
86 | crev = fctx.filerev() |
|
91 | crev = fctx.filerev() | |
87 |
|
92 | |||
88 | if len(tombstone) > flog.rawsize(crev): |
|
93 | if len(tombstone) > flog.rawsize(crev): | |
89 | raise util.Abort(_( |
|
94 | raise util.Abort(_( | |
90 | 'censor tombstone must be no longer than censored data')) |
|
95 | 'censor tombstone must be no longer than censored data')) | |
91 |
|
96 | |||
92 | # Using two files instead of one makes it easy to rewrite entry-by-entry |
|
97 | # Using two files instead of one makes it easy to rewrite entry-by-entry | |
93 | idxread = repo.svfs(flog.indexfile, 'r') |
|
98 | idxread = repo.svfs(flog.indexfile, 'r') | |
94 | idxwrite = repo.svfs(flog.indexfile, 'wb', atomictemp=True) |
|
99 | idxwrite = repo.svfs(flog.indexfile, 'wb', atomictemp=True) | |
95 | if flog.version & revlog.REVLOGNGINLINEDATA: |
|
100 | if flog.version & revlog.REVLOGNGINLINEDATA: | |
96 | dataread, datawrite = idxread, idxwrite |
|
101 | dataread, datawrite = idxread, idxwrite | |
97 | else: |
|
102 | else: | |
98 | dataread = repo.svfs(flog.datafile, 'r') |
|
103 | dataread = repo.svfs(flog.datafile, 'r') | |
99 | datawrite = repo.svfs(flog.datafile, 'wb', atomictemp=True) |
|
104 | datawrite = repo.svfs(flog.datafile, 'wb', atomictemp=True) | |
100 |
|
105 | |||
101 | # Copy all revlog data up to the entry to be censored. |
|
106 | # Copy all revlog data up to the entry to be censored. | |
102 | rio = revlog.revlogio() |
|
107 | rio = revlog.revlogio() | |
103 | offset = flog.start(crev) |
|
108 | offset = flog.start(crev) | |
104 |
|
109 | |||
105 | for chunk in util.filechunkiter(idxread, limit=crev * rio.size): |
|
110 | for chunk in util.filechunkiter(idxread, limit=crev * rio.size): | |
106 | idxwrite.write(chunk) |
|
111 | idxwrite.write(chunk) | |
107 | for chunk in util.filechunkiter(dataread, limit=offset): |
|
112 | for chunk in util.filechunkiter(dataread, limit=offset): | |
108 | datawrite.write(chunk) |
|
113 | datawrite.write(chunk) | |
109 |
|
114 | |||
110 | def rewriteindex(r, newoffs, newdata=None): |
|
115 | def rewriteindex(r, newoffs, newdata=None): | |
111 | """Rewrite the index entry with a new data offset and optional new data. |
|
116 | """Rewrite the index entry with a new data offset and optional new data. | |
112 |
|
117 | |||
113 | The newdata argument, if given, is a tuple of three positive integers: |
|
118 | The newdata argument, if given, is a tuple of three positive integers: | |
114 | (new compressed, new uncompressed, added flag bits). |
|
119 | (new compressed, new uncompressed, added flag bits). | |
115 | """ |
|
120 | """ | |
116 | offlags, comp, uncomp, base, link, p1, p2, nodeid = flog.index[r] |
|
121 | offlags, comp, uncomp, base, link, p1, p2, nodeid = flog.index[r] | |
117 | flags = revlog.gettype(offlags) |
|
122 | flags = revlog.gettype(offlags) | |
118 | if newdata: |
|
123 | if newdata: | |
119 | comp, uncomp, nflags = newdata |
|
124 | comp, uncomp, nflags = newdata | |
120 | flags |= nflags |
|
125 | flags |= nflags | |
121 | offlags = revlog.offset_type(newoffs, flags) |
|
126 | offlags = revlog.offset_type(newoffs, flags) | |
122 | e = (offlags, comp, uncomp, r, link, p1, p2, nodeid) |
|
127 | e = (offlags, comp, uncomp, r, link, p1, p2, nodeid) | |
123 | idxwrite.write(rio.packentry(e, None, flog.version, r)) |
|
128 | idxwrite.write(rio.packentry(e, None, flog.version, r)) | |
124 | idxread.seek(rio.size, 1) |
|
129 | idxread.seek(rio.size, 1) | |
125 |
|
130 | |||
126 | def rewrite(r, offs, data, nflags=revlog.REVIDX_DEFAULT_FLAGS): |
|
131 | def rewrite(r, offs, data, nflags=revlog.REVIDX_DEFAULT_FLAGS): | |
127 | """Write the given full text to the filelog with the given data offset. |
|
132 | """Write the given full text to the filelog with the given data offset. | |
128 |
|
133 | |||
129 | Returns: |
|
134 | Returns: | |
130 | The integer number of data bytes written, for tracking data offsets. |
|
135 | The integer number of data bytes written, for tracking data offsets. | |
131 | """ |
|
136 | """ | |
132 | flag, compdata = flog.compress(data) |
|
137 | flag, compdata = flog.compress(data) | |
133 | newcomp = len(flag) + len(compdata) |
|
138 | newcomp = len(flag) + len(compdata) | |
134 | rewriteindex(r, offs, (newcomp, len(data), nflags)) |
|
139 | rewriteindex(r, offs, (newcomp, len(data), nflags)) | |
135 | datawrite.write(flag) |
|
140 | datawrite.write(flag) | |
136 | datawrite.write(compdata) |
|
141 | datawrite.write(compdata) | |
137 | dataread.seek(flog.length(r), 1) |
|
142 | dataread.seek(flog.length(r), 1) | |
138 | return newcomp |
|
143 | return newcomp | |
139 |
|
144 | |||
140 | # Rewrite censored revlog entry with (padded) tombstone data. |
|
145 | # Rewrite censored revlog entry with (padded) tombstone data. | |
141 | pad = ' ' * (flog.rawsize(crev) - len(tombstone)) |
|
146 | pad = ' ' * (flog.rawsize(crev) - len(tombstone)) | |
142 | offset += rewrite(crev, offset, tombstone + pad, revlog.REVIDX_ISCENSORED) |
|
147 | offset += rewrite(crev, offset, tombstone + pad, revlog.REVIDX_ISCENSORED) | |
143 |
|
148 | |||
144 | # Rewrite all following filelog revisions fixing up offsets and deltas. |
|
149 | # Rewrite all following filelog revisions fixing up offsets and deltas. | |
145 | for srev in xrange(crev + 1, len(flog)): |
|
150 | for srev in xrange(crev + 1, len(flog)): | |
146 | if crev in flog.parentrevs(srev): |
|
151 | if crev in flog.parentrevs(srev): | |
147 | # Immediate children of censored node must be re-added as fulltext. |
|
152 | # Immediate children of censored node must be re-added as fulltext. | |
148 | try: |
|
153 | try: | |
149 | revdata = flog.revision(srev) |
|
154 | revdata = flog.revision(srev) | |
150 | except error.CensoredNodeError as e: |
|
155 | except error.CensoredNodeError as e: | |
151 | revdata = e.tombstone |
|
156 | revdata = e.tombstone | |
152 | dlen = rewrite(srev, offset, revdata) |
|
157 | dlen = rewrite(srev, offset, revdata) | |
153 | else: |
|
158 | else: | |
154 | # Copy any other revision data verbatim after fixing up the offset. |
|
159 | # Copy any other revision data verbatim after fixing up the offset. | |
155 | rewriteindex(srev, offset) |
|
160 | rewriteindex(srev, offset) | |
156 | dlen = flog.length(srev) |
|
161 | dlen = flog.length(srev) | |
157 | for chunk in util.filechunkiter(dataread, limit=dlen): |
|
162 | for chunk in util.filechunkiter(dataread, limit=dlen): | |
158 | datawrite.write(chunk) |
|
163 | datawrite.write(chunk) | |
159 | offset += dlen |
|
164 | offset += dlen | |
160 |
|
165 | |||
161 | idxread.close() |
|
166 | idxread.close() | |
162 | idxwrite.close() |
|
167 | idxwrite.close() | |
163 | if dataread is not idxread: |
|
168 | if dataread is not idxread: | |
164 | dataread.close() |
|
169 | dataread.close() | |
165 | datawrite.close() |
|
170 | datawrite.close() |
@@ -1,480 +1,485 b'' | |||||
1 | $ cat >> $HGRCPATH <<EOF |
|
1 | $ cat >> $HGRCPATH <<EOF | |
2 | > [extensions] |
|
2 | > [extensions] | |
3 | > censor= |
|
3 | > censor= | |
4 | > EOF |
|
4 | > EOF | |
5 | $ cp $HGRCPATH $HGRCPATH.orig |
|
5 | $ cp $HGRCPATH $HGRCPATH.orig | |
6 |
|
6 | |||
7 | Create repo with unimpeachable content |
|
7 | Create repo with unimpeachable content | |
8 |
|
8 | |||
9 | $ hg init r |
|
9 | $ hg init r | |
10 | $ cd r |
|
10 | $ cd r | |
11 | $ echo 'Initially untainted file' > target |
|
11 | $ echo 'Initially untainted file' > target | |
12 | $ echo 'Normal file here' > bystander |
|
12 | $ echo 'Normal file here' > bystander | |
13 | $ hg add target bystander |
|
13 | $ hg add target bystander | |
14 | $ hg ci -m init |
|
14 | $ hg ci -m init | |
15 |
|
15 | |||
16 | Clone repo so we can test pull later |
|
16 | Clone repo so we can test pull later | |
17 |
|
17 | |||
18 | $ cd .. |
|
18 | $ cd .. | |
19 | $ hg clone r rpull |
|
19 | $ hg clone r rpull | |
20 | updating to branch default |
|
20 | updating to branch default | |
21 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
21 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
22 | $ cd r |
|
22 | $ cd r | |
23 |
|
23 | |||
24 | Introduce content which will ultimately require censorship. Name the first |
|
24 | Introduce content which will ultimately require censorship. Name the first | |
25 | censored node C1, second C2, and so on |
|
25 | censored node C1, second C2, and so on | |
26 |
|
26 | |||
27 | $ echo 'Tainted file' > target |
|
27 | $ echo 'Tainted file' > target | |
28 | $ echo 'Passwords: hunter2' >> target |
|
28 | $ echo 'Passwords: hunter2' >> target | |
29 | $ hg ci -m taint target |
|
29 | $ hg ci -m taint target | |
30 | $ C1=`hg id --debug -i` |
|
30 | $ C1=`hg id --debug -i` | |
31 |
|
31 | |||
32 | $ echo 'hunter3' >> target |
|
32 | $ echo 'hunter3' >> target | |
33 | $ echo 'Normal file v2' > bystander |
|
33 | $ echo 'Normal file v2' > bystander | |
34 | $ hg ci -m moretaint target bystander |
|
34 | $ hg ci -m moretaint target bystander | |
35 | $ C2=`hg id --debug -i` |
|
35 | $ C2=`hg id --debug -i` | |
36 |
|
36 | |||
37 | Add a new sanitized versions to correct our mistake. Name the first head H1, |
|
37 | Add a new sanitized versions to correct our mistake. Name the first head H1, | |
38 | the second head H2, and so on |
|
38 | the second head H2, and so on | |
39 |
|
39 | |||
40 | $ echo 'Tainted file is now sanitized' > target |
|
40 | $ echo 'Tainted file is now sanitized' > target | |
41 | $ hg ci -m sanitized target |
|
41 | $ hg ci -m sanitized target | |
42 | $ H1=`hg id --debug -i` |
|
42 | $ H1=`hg id --debug -i` | |
43 |
|
43 | |||
44 | $ hg update -r $C2 |
|
44 | $ hg update -r $C2 | |
45 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
45 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
46 | $ echo 'Tainted file now super sanitized' > target |
|
46 | $ echo 'Tainted file now super sanitized' > target | |
47 | $ hg ci -m 'super sanitized' target |
|
47 | $ hg ci -m 'super sanitized' target | |
48 | created new head |
|
48 | created new head | |
49 | $ H2=`hg id --debug -i` |
|
49 | $ H2=`hg id --debug -i` | |
50 |
|
50 | |||
51 | Verify target contents before censorship at each revision |
|
51 | Verify target contents before censorship at each revision | |
52 |
|
52 | |||
53 | $ hg cat -r $H1 target |
|
53 | $ hg cat -r $H1 target | |
54 | Tainted file is now sanitized |
|
54 | Tainted file is now sanitized | |
55 | $ hg cat -r $H2 target |
|
55 | $ hg cat -r $H2 target | |
56 | Tainted file now super sanitized |
|
56 | Tainted file now super sanitized | |
57 | $ hg cat -r $C2 target |
|
57 | $ hg cat -r $C2 target | |
58 | Tainted file |
|
58 | Tainted file | |
59 | Passwords: hunter2 |
|
59 | Passwords: hunter2 | |
60 | hunter3 |
|
60 | hunter3 | |
61 | $ hg cat -r $C1 target |
|
61 | $ hg cat -r $C1 target | |
62 | Tainted file |
|
62 | Tainted file | |
63 | Passwords: hunter2 |
|
63 | Passwords: hunter2 | |
64 | $ hg cat -r 0 target |
|
64 | $ hg cat -r 0 target | |
65 | Initially untainted file |
|
65 | Initially untainted file | |
66 |
|
66 | |||
67 | Try to censor revision with too large of a tombstone message |
|
67 | Try to censor revision with too large of a tombstone message | |
68 |
|
68 | |||
69 | $ hg censor -r $C1 -t 'blah blah blah blah blah blah blah blah bla' target |
|
69 | $ hg censor -r $C1 -t 'blah blah blah blah blah blah blah blah bla' target | |
70 | abort: censor tombstone must be no longer than censored data |
|
70 | abort: censor tombstone must be no longer than censored data | |
71 | [255] |
|
71 | [255] | |
72 |
|
72 | |||
73 | Censor revision with 2 offenses |
|
73 | Censor revision with 2 offenses | |
74 |
|
74 | |||
75 | $ hg censor -r $C2 -t "remove password" target |
|
75 | (this also tests file pattern matching: path relative to cwd case) | |
|
76 | ||||
|
77 | $ mkdir -p foo/bar/baz | |||
|
78 | $ hg --cwd foo/bar/baz censor -r $C2 -t "remove password" ../../../target | |||
76 | $ hg cat -r $H1 target |
|
79 | $ hg cat -r $H1 target | |
77 | Tainted file is now sanitized |
|
80 | Tainted file is now sanitized | |
78 | $ hg cat -r $H2 target |
|
81 | $ hg cat -r $H2 target | |
79 | Tainted file now super sanitized |
|
82 | Tainted file now super sanitized | |
80 | $ hg cat -r $C2 target |
|
83 | $ hg cat -r $C2 target | |
81 | abort: censored node: 1e0247a9a4b7 |
|
84 | abort: censored node: 1e0247a9a4b7 | |
82 | (set censor.policy to ignore errors) |
|
85 | (set censor.policy to ignore errors) | |
83 | [255] |
|
86 | [255] | |
84 | $ hg cat -r $C1 target |
|
87 | $ hg cat -r $C1 target | |
85 | Tainted file |
|
88 | Tainted file | |
86 | Passwords: hunter2 |
|
89 | Passwords: hunter2 | |
87 | $ hg cat -r 0 target |
|
90 | $ hg cat -r 0 target | |
88 | Initially untainted file |
|
91 | Initially untainted file | |
89 |
|
92 | |||
90 | Censor revision with 1 offense |
|
93 | Censor revision with 1 offense | |
91 |
|
94 | |||
92 | $ hg censor -r $C1 target |
|
95 | (this also tests file pattern matching: with 'path:' scheme) | |
|
96 | ||||
|
97 | $ hg --cwd foo/bar/baz censor -r $C1 path:target | |||
93 | $ hg cat -r $H1 target |
|
98 | $ hg cat -r $H1 target | |
94 | Tainted file is now sanitized |
|
99 | Tainted file is now sanitized | |
95 | $ hg cat -r $H2 target |
|
100 | $ hg cat -r $H2 target | |
96 | Tainted file now super sanitized |
|
101 | Tainted file now super sanitized | |
97 | $ hg cat -r $C2 target |
|
102 | $ hg cat -r $C2 target | |
98 | abort: censored node: 1e0247a9a4b7 |
|
103 | abort: censored node: 1e0247a9a4b7 | |
99 | (set censor.policy to ignore errors) |
|
104 | (set censor.policy to ignore errors) | |
100 | [255] |
|
105 | [255] | |
101 | $ hg cat -r $C1 target |
|
106 | $ hg cat -r $C1 target | |
102 | abort: censored node: 613bc869fceb |
|
107 | abort: censored node: 613bc869fceb | |
103 | (set censor.policy to ignore errors) |
|
108 | (set censor.policy to ignore errors) | |
104 | [255] |
|
109 | [255] | |
105 | $ hg cat -r 0 target |
|
110 | $ hg cat -r 0 target | |
106 | Initially untainted file |
|
111 | Initially untainted file | |
107 |
|
112 | |||
108 | Can only checkout target at uncensored revisions, -X is workaround for --all |
|
113 | Can only checkout target at uncensored revisions, -X is workaround for --all | |
109 |
|
114 | |||
110 | $ hg revert -r $C2 target |
|
115 | $ hg revert -r $C2 target | |
111 | abort: censored node: 1e0247a9a4b7 |
|
116 | abort: censored node: 1e0247a9a4b7 | |
112 | (set censor.policy to ignore errors) |
|
117 | (set censor.policy to ignore errors) | |
113 | [255] |
|
118 | [255] | |
114 | $ hg revert -r $C1 target |
|
119 | $ hg revert -r $C1 target | |
115 | abort: censored node: 613bc869fceb |
|
120 | abort: censored node: 613bc869fceb | |
116 | (set censor.policy to ignore errors) |
|
121 | (set censor.policy to ignore errors) | |
117 | [255] |
|
122 | [255] | |
118 | $ hg revert -r $C1 --all |
|
123 | $ hg revert -r $C1 --all | |
119 | reverting bystander |
|
124 | reverting bystander | |
120 | reverting target |
|
125 | reverting target | |
121 | abort: censored node: 613bc869fceb |
|
126 | abort: censored node: 613bc869fceb | |
122 | (set censor.policy to ignore errors) |
|
127 | (set censor.policy to ignore errors) | |
123 | [255] |
|
128 | [255] | |
124 | $ hg revert -r $C1 --all -X target |
|
129 | $ hg revert -r $C1 --all -X target | |
125 | $ cat target |
|
130 | $ cat target | |
126 | Tainted file now super sanitized |
|
131 | Tainted file now super sanitized | |
127 | $ hg revert -r 0 --all |
|
132 | $ hg revert -r 0 --all | |
128 | reverting target |
|
133 | reverting target | |
129 | $ cat target |
|
134 | $ cat target | |
130 | Initially untainted file |
|
135 | Initially untainted file | |
131 | $ hg revert -r $H2 --all |
|
136 | $ hg revert -r $H2 --all | |
132 | reverting bystander |
|
137 | reverting bystander | |
133 | reverting target |
|
138 | reverting target | |
134 | $ cat target |
|
139 | $ cat target | |
135 | Tainted file now super sanitized |
|
140 | Tainted file now super sanitized | |
136 |
|
141 | |||
137 | Uncensored file can be viewed at any revision |
|
142 | Uncensored file can be viewed at any revision | |
138 |
|
143 | |||
139 | $ hg cat -r $H1 bystander |
|
144 | $ hg cat -r $H1 bystander | |
140 | Normal file v2 |
|
145 | Normal file v2 | |
141 | $ hg cat -r $C2 bystander |
|
146 | $ hg cat -r $C2 bystander | |
142 | Normal file v2 |
|
147 | Normal file v2 | |
143 | $ hg cat -r $C1 bystander |
|
148 | $ hg cat -r $C1 bystander | |
144 | Normal file here |
|
149 | Normal file here | |
145 | $ hg cat -r 0 bystander |
|
150 | $ hg cat -r 0 bystander | |
146 | Normal file here |
|
151 | Normal file here | |
147 |
|
152 | |||
148 | Can update to children of censored revision |
|
153 | Can update to children of censored revision | |
149 |
|
154 | |||
150 | $ hg update -r $H1 |
|
155 | $ hg update -r $H1 | |
151 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
156 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
152 | $ cat target |
|
157 | $ cat target | |
153 | Tainted file is now sanitized |
|
158 | Tainted file is now sanitized | |
154 | $ hg update -r $H2 |
|
159 | $ hg update -r $H2 | |
155 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
160 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
156 | $ cat target |
|
161 | $ cat target | |
157 | Tainted file now super sanitized |
|
162 | Tainted file now super sanitized | |
158 |
|
163 | |||
159 | Set censor policy to abort in trusted $HGRC so hg verify fails |
|
164 | Set censor policy to abort in trusted $HGRC so hg verify fails | |
160 |
|
165 | |||
161 | $ cp $HGRCPATH.orig $HGRCPATH |
|
166 | $ cp $HGRCPATH.orig $HGRCPATH | |
162 | $ cat >> $HGRCPATH <<EOF |
|
167 | $ cat >> $HGRCPATH <<EOF | |
163 | > [censor] |
|
168 | > [censor] | |
164 | > policy = abort |
|
169 | > policy = abort | |
165 | > EOF |
|
170 | > EOF | |
166 |
|
171 | |||
167 | Repo fails verification due to censorship |
|
172 | Repo fails verification due to censorship | |
168 |
|
173 | |||
169 | $ hg verify |
|
174 | $ hg verify | |
170 | checking changesets |
|
175 | checking changesets | |
171 | checking manifests |
|
176 | checking manifests | |
172 | crosschecking files in changesets and manifests |
|
177 | crosschecking files in changesets and manifests | |
173 | checking files |
|
178 | checking files | |
174 | target@1: censored file data |
|
179 | target@1: censored file data | |
175 | target@2: censored file data |
|
180 | target@2: censored file data | |
176 | 2 files, 5 changesets, 7 total revisions |
|
181 | 2 files, 5 changesets, 7 total revisions | |
177 | 2 integrity errors encountered! |
|
182 | 2 integrity errors encountered! | |
178 | (first damaged changeset appears to be 1) |
|
183 | (first damaged changeset appears to be 1) | |
179 | [1] |
|
184 | [1] | |
180 |
|
185 | |||
181 | Cannot update to revision with censored data |
|
186 | Cannot update to revision with censored data | |
182 |
|
187 | |||
183 | $ hg update -r $C2 |
|
188 | $ hg update -r $C2 | |
184 | abort: censored node: 1e0247a9a4b7 |
|
189 | abort: censored node: 1e0247a9a4b7 | |
185 | (set censor.policy to ignore errors) |
|
190 | (set censor.policy to ignore errors) | |
186 | [255] |
|
191 | [255] | |
187 | $ hg update -r $C1 |
|
192 | $ hg update -r $C1 | |
188 | abort: censored node: 613bc869fceb |
|
193 | abort: censored node: 613bc869fceb | |
189 | (set censor.policy to ignore errors) |
|
194 | (set censor.policy to ignore errors) | |
190 | [255] |
|
195 | [255] | |
191 | $ hg update -r 0 |
|
196 | $ hg update -r 0 | |
192 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
197 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
193 | $ hg update -r $H2 |
|
198 | $ hg update -r $H2 | |
194 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
199 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
195 |
|
200 | |||
196 | Set censor policy to ignore in trusted $HGRC so hg verify passes |
|
201 | Set censor policy to ignore in trusted $HGRC so hg verify passes | |
197 |
|
202 | |||
198 | $ cp $HGRCPATH.orig $HGRCPATH |
|
203 | $ cp $HGRCPATH.orig $HGRCPATH | |
199 | $ cat >> $HGRCPATH <<EOF |
|
204 | $ cat >> $HGRCPATH <<EOF | |
200 | > [censor] |
|
205 | > [censor] | |
201 | > policy = ignore |
|
206 | > policy = ignore | |
202 | > EOF |
|
207 | > EOF | |
203 |
|
208 | |||
204 | Repo passes verification with warnings with explicit config |
|
209 | Repo passes verification with warnings with explicit config | |
205 |
|
210 | |||
206 | $ hg verify |
|
211 | $ hg verify | |
207 | checking changesets |
|
212 | checking changesets | |
208 | checking manifests |
|
213 | checking manifests | |
209 | crosschecking files in changesets and manifests |
|
214 | crosschecking files in changesets and manifests | |
210 | checking files |
|
215 | checking files | |
211 | 2 files, 5 changesets, 7 total revisions |
|
216 | 2 files, 5 changesets, 7 total revisions | |
212 |
|
217 | |||
213 | May update to revision with censored data with explicit config |
|
218 | May update to revision with censored data with explicit config | |
214 |
|
219 | |||
215 | $ hg update -r $C2 |
|
220 | $ hg update -r $C2 | |
216 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
221 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
217 | $ cat target |
|
222 | $ cat target | |
218 | $ hg update -r $C1 |
|
223 | $ hg update -r $C1 | |
219 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
224 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
220 | $ cat target |
|
225 | $ cat target | |
221 | $ hg update -r 0 |
|
226 | $ hg update -r 0 | |
222 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
227 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
223 | $ cat target |
|
228 | $ cat target | |
224 | Initially untainted file |
|
229 | Initially untainted file | |
225 | $ hg update -r $H2 |
|
230 | $ hg update -r $H2 | |
226 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
231 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
227 | $ cat target |
|
232 | $ cat target | |
228 | Tainted file now super sanitized |
|
233 | Tainted file now super sanitized | |
229 |
|
234 | |||
230 | Can merge in revision with censored data. Test requires one branch of history |
|
235 | Can merge in revision with censored data. Test requires one branch of history | |
231 | with the file censored, but we can't censor at a head, so advance H1. |
|
236 | with the file censored, but we can't censor at a head, so advance H1. | |
232 |
|
237 | |||
233 | $ hg update -r $H1 |
|
238 | $ hg update -r $H1 | |
234 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
239 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
235 | $ C3=$H1 |
|
240 | $ C3=$H1 | |
236 | $ echo 'advanced head H1' > target |
|
241 | $ echo 'advanced head H1' > target | |
237 | $ hg ci -m 'advance head H1' target |
|
242 | $ hg ci -m 'advance head H1' target | |
238 | $ H1=`hg id --debug -i` |
|
243 | $ H1=`hg id --debug -i` | |
239 | $ hg censor -r $C3 target |
|
244 | $ hg censor -r $C3 target | |
240 | $ hg update -r $H2 |
|
245 | $ hg update -r $H2 | |
241 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
246 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
242 | $ hg merge -r $C3 |
|
247 | $ hg merge -r $C3 | |
243 | merging target |
|
248 | merging target | |
244 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved |
|
249 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved | |
245 | (branch merge, don't forget to commit) |
|
250 | (branch merge, don't forget to commit) | |
246 |
|
251 | |||
247 | Revisions present in repository heads may not be censored |
|
252 | Revisions present in repository heads may not be censored | |
248 |
|
253 | |||
249 | $ hg update -C -r $H2 |
|
254 | $ hg update -C -r $H2 | |
250 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
255 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
251 | $ hg censor -r $H2 target |
|
256 | $ hg censor -r $H2 target | |
252 | abort: cannot censor file in heads (78a8fc215e79) |
|
257 | abort: cannot censor file in heads (78a8fc215e79) | |
253 | (clean/delete and commit first) |
|
258 | (clean/delete and commit first) | |
254 | [255] |
|
259 | [255] | |
255 | $ echo 'twiddling thumbs' > bystander |
|
260 | $ echo 'twiddling thumbs' > bystander | |
256 | $ hg ci -m 'bystander commit' |
|
261 | $ hg ci -m 'bystander commit' | |
257 | $ H2=`hg id --debug -i` |
|
262 | $ H2=`hg id --debug -i` | |
258 | $ hg censor -r "$H2^" target |
|
263 | $ hg censor -r "$H2^" target | |
259 | abort: cannot censor file in heads (efbe78065929) |
|
264 | abort: cannot censor file in heads (efbe78065929) | |
260 | (clean/delete and commit first) |
|
265 | (clean/delete and commit first) | |
261 | [255] |
|
266 | [255] | |
262 |
|
267 | |||
263 | Cannot censor working directory |
|
268 | Cannot censor working directory | |
264 |
|
269 | |||
265 | $ echo 'seriously no passwords' > target |
|
270 | $ echo 'seriously no passwords' > target | |
266 | $ hg ci -m 'extend second head arbitrarily' target |
|
271 | $ hg ci -m 'extend second head arbitrarily' target | |
267 | $ H2=`hg id --debug -i` |
|
272 | $ H2=`hg id --debug -i` | |
268 | $ hg update -r "$H2^" |
|
273 | $ hg update -r "$H2^" | |
269 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
274 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
270 | $ hg censor -r . target |
|
275 | $ hg censor -r . target | |
271 | abort: cannot censor working directory |
|
276 | abort: cannot censor working directory | |
272 | (clean/delete/update first) |
|
277 | (clean/delete/update first) | |
273 | [255] |
|
278 | [255] | |
274 | $ hg update -r $H2 |
|
279 | $ hg update -r $H2 | |
275 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
280 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
276 |
|
281 | |||
277 | Can re-add file after being deleted + censored |
|
282 | Can re-add file after being deleted + censored | |
278 |
|
283 | |||
279 | $ C4=$H2 |
|
284 | $ C4=$H2 | |
280 | $ hg rm target |
|
285 | $ hg rm target | |
281 | $ hg ci -m 'delete target so it may be censored' |
|
286 | $ hg ci -m 'delete target so it may be censored' | |
282 | $ H2=`hg id --debug -i` |
|
287 | $ H2=`hg id --debug -i` | |
283 | $ hg censor -r $C4 target |
|
288 | $ hg censor -r $C4 target | |
284 | $ hg cat -r $C4 target |
|
289 | $ hg cat -r $C4 target | |
285 | $ hg cat -r "$H2^^" target |
|
290 | $ hg cat -r "$H2^^" target | |
286 | Tainted file now super sanitized |
|
291 | Tainted file now super sanitized | |
287 | $ echo 'fresh start' > target |
|
292 | $ echo 'fresh start' > target | |
288 | $ hg add target |
|
293 | $ hg add target | |
289 | $ hg ci -m reincarnated target |
|
294 | $ hg ci -m reincarnated target | |
290 | $ H2=`hg id --debug -i` |
|
295 | $ H2=`hg id --debug -i` | |
291 | $ hg cat -r $H2 target |
|
296 | $ hg cat -r $H2 target | |
292 | fresh start |
|
297 | fresh start | |
293 | $ hg cat -r "$H2^" target |
|
298 | $ hg cat -r "$H2^" target | |
294 | target: no such file in rev 452ec1762369 |
|
299 | target: no such file in rev 452ec1762369 | |
295 | [1] |
|
300 | [1] | |
296 | $ hg cat -r $C4 target |
|
301 | $ hg cat -r $C4 target | |
297 | $ hg cat -r "$H2^^^" target |
|
302 | $ hg cat -r "$H2^^^" target | |
298 | Tainted file now super sanitized |
|
303 | Tainted file now super sanitized | |
299 |
|
304 | |||
300 | Can censor after revlog has expanded to no longer permit inline storage |
|
305 | Can censor after revlog has expanded to no longer permit inline storage | |
301 |
|
306 | |||
302 | $ for x in `python $TESTDIR/seq.py 0 50000` |
|
307 | $ for x in `python $TESTDIR/seq.py 0 50000` | |
303 | > do |
|
308 | > do | |
304 | > echo "Password: hunter$x" >> target |
|
309 | > echo "Password: hunter$x" >> target | |
305 | > done |
|
310 | > done | |
306 | $ hg ci -m 'add 100k passwords' |
|
311 | $ hg ci -m 'add 100k passwords' | |
307 | $ H2=`hg id --debug -i` |
|
312 | $ H2=`hg id --debug -i` | |
308 | $ C5=$H2 |
|
313 | $ C5=$H2 | |
309 | $ hg revert -r "$H2^" target |
|
314 | $ hg revert -r "$H2^" target | |
310 | $ hg ci -m 'cleaned 100k passwords' |
|
315 | $ hg ci -m 'cleaned 100k passwords' | |
311 | $ H2=`hg id --debug -i` |
|
316 | $ H2=`hg id --debug -i` | |
312 | $ hg censor -r $C5 target |
|
317 | $ hg censor -r $C5 target | |
313 | $ hg cat -r $C5 target |
|
318 | $ hg cat -r $C5 target | |
314 | $ hg cat -r $H2 target |
|
319 | $ hg cat -r $H2 target | |
315 | fresh start |
|
320 | fresh start | |
316 |
|
321 | |||
317 | Repo with censored nodes can be cloned and cloned nodes are censored |
|
322 | Repo with censored nodes can be cloned and cloned nodes are censored | |
318 |
|
323 | |||
319 | $ cd .. |
|
324 | $ cd .. | |
320 | $ hg clone r rclone |
|
325 | $ hg clone r rclone | |
321 | updating to branch default |
|
326 | updating to branch default | |
322 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
327 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
323 | $ cd rclone |
|
328 | $ cd rclone | |
324 | $ hg cat -r $H1 target |
|
329 | $ hg cat -r $H1 target | |
325 | advanced head H1 |
|
330 | advanced head H1 | |
326 | $ hg cat -r $H2~5 target |
|
331 | $ hg cat -r $H2~5 target | |
327 | Tainted file now super sanitized |
|
332 | Tainted file now super sanitized | |
328 | $ hg cat -r $C2 target |
|
333 | $ hg cat -r $C2 target | |
329 | $ hg cat -r $C1 target |
|
334 | $ hg cat -r $C1 target | |
330 | $ hg cat -r 0 target |
|
335 | $ hg cat -r 0 target | |
331 | Initially untainted file |
|
336 | Initially untainted file | |
332 | $ hg verify |
|
337 | $ hg verify | |
333 | checking changesets |
|
338 | checking changesets | |
334 | checking manifests |
|
339 | checking manifests | |
335 | crosschecking files in changesets and manifests |
|
340 | crosschecking files in changesets and manifests | |
336 | checking files |
|
341 | checking files | |
337 | 2 files, 12 changesets, 13 total revisions |
|
342 | 2 files, 12 changesets, 13 total revisions | |
338 |
|
343 | |||
339 | Repo cloned before tainted content introduced can pull censored nodes |
|
344 | Repo cloned before tainted content introduced can pull censored nodes | |
340 |
|
345 | |||
341 | $ cd ../rpull |
|
346 | $ cd ../rpull | |
342 | $ hg cat -r tip target |
|
347 | $ hg cat -r tip target | |
343 | Initially untainted file |
|
348 | Initially untainted file | |
344 | $ hg verify |
|
349 | $ hg verify | |
345 | checking changesets |
|
350 | checking changesets | |
346 | checking manifests |
|
351 | checking manifests | |
347 | crosschecking files in changesets and manifests |
|
352 | crosschecking files in changesets and manifests | |
348 | checking files |
|
353 | checking files | |
349 | 2 files, 1 changesets, 2 total revisions |
|
354 | 2 files, 1 changesets, 2 total revisions | |
350 | $ hg pull -r $H1 -r $H2 |
|
355 | $ hg pull -r $H1 -r $H2 | |
351 | pulling from $TESTTMP/r (glob) |
|
356 | pulling from $TESTTMP/r (glob) | |
352 | searching for changes |
|
357 | searching for changes | |
353 | adding changesets |
|
358 | adding changesets | |
354 | adding manifests |
|
359 | adding manifests | |
355 | adding file changes |
|
360 | adding file changes | |
356 | added 11 changesets with 11 changes to 2 files (+1 heads) |
|
361 | added 11 changesets with 11 changes to 2 files (+1 heads) | |
357 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
362 | (run 'hg heads' to see heads, 'hg merge' to merge) | |
358 | $ hg update 4 |
|
363 | $ hg update 4 | |
359 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
364 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
360 | $ cat target |
|
365 | $ cat target | |
361 | Tainted file now super sanitized |
|
366 | Tainted file now super sanitized | |
362 | $ hg cat -r $H1 target |
|
367 | $ hg cat -r $H1 target | |
363 | advanced head H1 |
|
368 | advanced head H1 | |
364 | $ hg cat -r $H2~5 target |
|
369 | $ hg cat -r $H2~5 target | |
365 | Tainted file now super sanitized |
|
370 | Tainted file now super sanitized | |
366 | $ hg cat -r $C2 target |
|
371 | $ hg cat -r $C2 target | |
367 | $ hg cat -r $C1 target |
|
372 | $ hg cat -r $C1 target | |
368 | $ hg cat -r 0 target |
|
373 | $ hg cat -r 0 target | |
369 | Initially untainted file |
|
374 | Initially untainted file | |
370 | $ hg verify |
|
375 | $ hg verify | |
371 | checking changesets |
|
376 | checking changesets | |
372 | checking manifests |
|
377 | checking manifests | |
373 | crosschecking files in changesets and manifests |
|
378 | crosschecking files in changesets and manifests | |
374 | checking files |
|
379 | checking files | |
375 | 2 files, 12 changesets, 13 total revisions |
|
380 | 2 files, 12 changesets, 13 total revisions | |
376 |
|
381 | |||
377 | Censored nodes can be pushed if they censor previously unexchanged nodes |
|
382 | Censored nodes can be pushed if they censor previously unexchanged nodes | |
378 |
|
383 | |||
379 | $ echo 'Passwords: hunter2hunter2' > target |
|
384 | $ echo 'Passwords: hunter2hunter2' > target | |
380 | $ hg ci -m 're-add password from clone' target |
|
385 | $ hg ci -m 're-add password from clone' target | |
381 | created new head |
|
386 | created new head | |
382 | $ H3=`hg id --debug -i` |
|
387 | $ H3=`hg id --debug -i` | |
383 | $ REV=$H3 |
|
388 | $ REV=$H3 | |
384 | $ echo 'Re-sanitized; nothing to see here' > target |
|
389 | $ echo 'Re-sanitized; nothing to see here' > target | |
385 | $ hg ci -m 're-sanitized' target |
|
390 | $ hg ci -m 're-sanitized' target | |
386 | $ H2=`hg id --debug -i` |
|
391 | $ H2=`hg id --debug -i` | |
387 | $ CLEANREV=$H2 |
|
392 | $ CLEANREV=$H2 | |
388 | $ hg cat -r $REV target |
|
393 | $ hg cat -r $REV target | |
389 | Passwords: hunter2hunter2 |
|
394 | Passwords: hunter2hunter2 | |
390 | $ hg censor -r $REV target |
|
395 | $ hg censor -r $REV target | |
391 | $ hg cat -r $REV target |
|
396 | $ hg cat -r $REV target | |
392 | $ hg cat -r $CLEANREV target |
|
397 | $ hg cat -r $CLEANREV target | |
393 | Re-sanitized; nothing to see here |
|
398 | Re-sanitized; nothing to see here | |
394 | $ hg push -f -r $H2 |
|
399 | $ hg push -f -r $H2 | |
395 | pushing to $TESTTMP/r (glob) |
|
400 | pushing to $TESTTMP/r (glob) | |
396 | searching for changes |
|
401 | searching for changes | |
397 | adding changesets |
|
402 | adding changesets | |
398 | adding manifests |
|
403 | adding manifests | |
399 | adding file changes |
|
404 | adding file changes | |
400 | added 2 changesets with 2 changes to 1 files (+1 heads) |
|
405 | added 2 changesets with 2 changes to 1 files (+1 heads) | |
401 |
|
406 | |||
402 | $ cd ../r |
|
407 | $ cd ../r | |
403 | $ hg cat -r $REV target |
|
408 | $ hg cat -r $REV target | |
404 | $ hg cat -r $CLEANREV target |
|
409 | $ hg cat -r $CLEANREV target | |
405 | Re-sanitized; nothing to see here |
|
410 | Re-sanitized; nothing to see here | |
406 | $ hg update $CLEANREV |
|
411 | $ hg update $CLEANREV | |
407 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
412 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
408 | $ cat target |
|
413 | $ cat target | |
409 | Re-sanitized; nothing to see here |
|
414 | Re-sanitized; nothing to see here | |
410 |
|
415 | |||
411 | Censored nodes can be bundled up and unbundled in another repo |
|
416 | Censored nodes can be bundled up and unbundled in another repo | |
412 |
|
417 | |||
413 | $ hg bundle --base 0 ../pwbundle |
|
418 | $ hg bundle --base 0 ../pwbundle | |
414 | 13 changesets found |
|
419 | 13 changesets found | |
415 | $ cd ../rclone |
|
420 | $ cd ../rclone | |
416 | $ hg unbundle ../pwbundle |
|
421 | $ hg unbundle ../pwbundle | |
417 | adding changesets |
|
422 | adding changesets | |
418 | adding manifests |
|
423 | adding manifests | |
419 | adding file changes |
|
424 | adding file changes | |
420 | added 2 changesets with 2 changes to 2 files (+1 heads) |
|
425 | added 2 changesets with 2 changes to 2 files (+1 heads) | |
421 | (run 'hg heads .' to see heads, 'hg merge' to merge) |
|
426 | (run 'hg heads .' to see heads, 'hg merge' to merge) | |
422 | $ hg cat -r $REV target |
|
427 | $ hg cat -r $REV target | |
423 | $ hg cat -r $CLEANREV target |
|
428 | $ hg cat -r $CLEANREV target | |
424 | Re-sanitized; nothing to see here |
|
429 | Re-sanitized; nothing to see here | |
425 | $ hg update $CLEANREV |
|
430 | $ hg update $CLEANREV | |
426 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
431 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
427 | $ cat target |
|
432 | $ cat target | |
428 | Re-sanitized; nothing to see here |
|
433 | Re-sanitized; nothing to see here | |
429 | $ hg verify |
|
434 | $ hg verify | |
430 | checking changesets |
|
435 | checking changesets | |
431 | checking manifests |
|
436 | checking manifests | |
432 | crosschecking files in changesets and manifests |
|
437 | crosschecking files in changesets and manifests | |
433 | checking files |
|
438 | checking files | |
434 | 2 files, 14 changesets, 15 total revisions |
|
439 | 2 files, 14 changesets, 15 total revisions | |
435 |
|
440 | |||
436 | Censored nodes can be imported on top of censored nodes, consecutively |
|
441 | Censored nodes can be imported on top of censored nodes, consecutively | |
437 |
|
442 | |||
438 | $ hg init ../rimport |
|
443 | $ hg init ../rimport | |
439 | $ hg bundle --base 1 ../rimport/splitbundle |
|
444 | $ hg bundle --base 1 ../rimport/splitbundle | |
440 | 12 changesets found |
|
445 | 12 changesets found | |
441 | $ cd ../rimport |
|
446 | $ cd ../rimport | |
442 | $ hg pull -r $H1 -r $H2 ../r |
|
447 | $ hg pull -r $H1 -r $H2 ../r | |
443 | pulling from ../r |
|
448 | pulling from ../r | |
444 | adding changesets |
|
449 | adding changesets | |
445 | adding manifests |
|
450 | adding manifests | |
446 | adding file changes |
|
451 | adding file changes | |
447 | added 8 changesets with 10 changes to 2 files (+1 heads) |
|
452 | added 8 changesets with 10 changes to 2 files (+1 heads) | |
448 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
453 | (run 'hg heads' to see heads, 'hg merge' to merge) | |
449 | $ hg unbundle splitbundle |
|
454 | $ hg unbundle splitbundle | |
450 | adding changesets |
|
455 | adding changesets | |
451 | adding manifests |
|
456 | adding manifests | |
452 | adding file changes |
|
457 | adding file changes | |
453 | added 6 changesets with 5 changes to 2 files (+1 heads) |
|
458 | added 6 changesets with 5 changes to 2 files (+1 heads) | |
454 | (run 'hg heads .' to see heads, 'hg merge' to merge) |
|
459 | (run 'hg heads .' to see heads, 'hg merge' to merge) | |
455 | $ hg update $H2 |
|
460 | $ hg update $H2 | |
456 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
461 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
457 | $ cat target |
|
462 | $ cat target | |
458 | Re-sanitized; nothing to see here |
|
463 | Re-sanitized; nothing to see here | |
459 | $ hg verify |
|
464 | $ hg verify | |
460 | checking changesets |
|
465 | checking changesets | |
461 | checking manifests |
|
466 | checking manifests | |
462 | crosschecking files in changesets and manifests |
|
467 | crosschecking files in changesets and manifests | |
463 | checking files |
|
468 | checking files | |
464 | 2 files, 14 changesets, 15 total revisions |
|
469 | 2 files, 14 changesets, 15 total revisions | |
465 | $ cd ../r |
|
470 | $ cd ../r | |
466 |
|
471 | |||
467 | Can import bundle where first revision of a file is censored |
|
472 | Can import bundle where first revision of a file is censored | |
468 |
|
473 | |||
469 | $ hg init ../rinit |
|
474 | $ hg init ../rinit | |
470 | $ hg censor -r 0 target |
|
475 | $ hg censor -r 0 target | |
471 | $ hg bundle -r 0 --base null ../rinit/initbundle |
|
476 | $ hg bundle -r 0 --base null ../rinit/initbundle | |
472 | 1 changesets found |
|
477 | 1 changesets found | |
473 | $ cd ../rinit |
|
478 | $ cd ../rinit | |
474 | $ hg unbundle initbundle |
|
479 | $ hg unbundle initbundle | |
475 | adding changesets |
|
480 | adding changesets | |
476 | adding manifests |
|
481 | adding manifests | |
477 | adding file changes |
|
482 | adding file changes | |
478 | added 1 changesets with 2 changes to 2 files |
|
483 | added 1 changesets with 2 changes to 2 files | |
479 | (run 'hg update' to get a working copy) |
|
484 | (run 'hg update' to get a working copy) | |
480 | $ hg cat -r 0 target |
|
485 | $ hg cat -r 0 target |
General Comments 0
You need to be logged in to leave comments.
Login now