Show More
@@ -0,0 +1,381 b'' | |||||
|
1 | # record.py | |||
|
2 | # | |||
|
3 | # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms of | |||
|
6 | # the GNU General Public License, incorporated herein by reference. | |||
|
7 | ||||
|
8 | '''interactive change selection during commit''' | |||
|
9 | ||||
|
10 | from mercurial.i18n import _ | |||
|
11 | from mercurial import cmdutil, commands, cmdutil, hg, mdiff, patch, revlog | |||
|
12 | from mercurial import util | |||
|
13 | import copy, cStringIO, errno, operator, os, re, shutil, tempfile | |||
|
14 | ||||
|
15 | lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)') | |||
|
16 | ||||
|
17 | def scanpatch(fp): | |||
|
18 | lr = patch.linereader(fp) | |||
|
19 | ||||
|
20 | def scanwhile(first, p): | |||
|
21 | lines = [first] | |||
|
22 | while True: | |||
|
23 | line = lr.readline() | |||
|
24 | if not line: | |||
|
25 | break | |||
|
26 | if p(line): | |||
|
27 | lines.append(line) | |||
|
28 | else: | |||
|
29 | lr.push(line) | |||
|
30 | break | |||
|
31 | return lines | |||
|
32 | ||||
|
33 | while True: | |||
|
34 | line = lr.readline() | |||
|
35 | if not line: | |||
|
36 | break | |||
|
37 | if line.startswith('diff --git a/'): | |||
|
38 | def notheader(line): | |||
|
39 | s = line.split(None, 1) | |||
|
40 | return not s or s[0] not in ('---', 'diff') | |||
|
41 | header = scanwhile(line, notheader) | |||
|
42 | fromfile = lr.readline() | |||
|
43 | if fromfile.startswith('---'): | |||
|
44 | tofile = lr.readline() | |||
|
45 | header += [fromfile, tofile] | |||
|
46 | else: | |||
|
47 | lr.push(fromfile) | |||
|
48 | yield 'file', header | |||
|
49 | elif line[0] == ' ': | |||
|
50 | yield 'context', scanwhile(line, lambda l: l[0] in ' \\') | |||
|
51 | elif line[0] in '-+': | |||
|
52 | yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\') | |||
|
53 | else: | |||
|
54 | m = lines_re.match(line) | |||
|
55 | if m: | |||
|
56 | yield 'range', m.groups() | |||
|
57 | else: | |||
|
58 | raise patch.PatchError('unknown patch content: %r' % line) | |||
|
59 | ||||
|
60 | class header(object): | |||
|
61 | diff_re = re.compile('diff --git a/(.*) b/(.*)$') | |||
|
62 | allhunks_re = re.compile('(?:index|new file|deleted file) ') | |||
|
63 | pretty_re = re.compile('(?:new file|deleted file) ') | |||
|
64 | special_re = re.compile('(?:index|new|deleted|copy|rename) ') | |||
|
65 | ||||
|
66 | def __init__(self, header): | |||
|
67 | self.header = header | |||
|
68 | self.hunks = [] | |||
|
69 | ||||
|
70 | def binary(self): | |||
|
71 | for h in self.header: | |||
|
72 | if h.startswith('index '): | |||
|
73 | return True | |||
|
74 | ||||
|
75 | def pretty(self, fp): | |||
|
76 | for h in self.header: | |||
|
77 | if h.startswith('index '): | |||
|
78 | fp.write(_('this modifies a binary file (all or nothing)\n')) | |||
|
79 | break | |||
|
80 | if self.pretty_re.match(h): | |||
|
81 | fp.write(h) | |||
|
82 | if self.binary(): | |||
|
83 | fp.write(_('this is a binary file\n')) | |||
|
84 | break | |||
|
85 | if h.startswith('---'): | |||
|
86 | fp.write(_('%d hunks, %d lines changed\n') % | |||
|
87 | (len(self.hunks), | |||
|
88 | sum([h.added + h.removed for h in self.hunks]))) | |||
|
89 | break | |||
|
90 | fp.write(h) | |||
|
91 | ||||
|
92 | def write(self, fp): | |||
|
93 | fp.write(''.join(self.header)) | |||
|
94 | ||||
|
95 | def allhunks(self): | |||
|
96 | for h in self.header: | |||
|
97 | if self.allhunks_re.match(h): | |||
|
98 | return True | |||
|
99 | ||||
|
100 | def files(self): | |||
|
101 | fromfile, tofile = self.diff_re.match(self.header[0]).groups() | |||
|
102 | if fromfile == tofile: | |||
|
103 | return [fromfile] | |||
|
104 | return [fromfile, tofile] | |||
|
105 | ||||
|
106 | def filename(self): | |||
|
107 | return self.files()[-1] | |||
|
108 | ||||
|
109 | def __repr__(self): | |||
|
110 | return '<header %s>' % (' '.join(map(repr, self.files()))) | |||
|
111 | ||||
|
112 | def special(self): | |||
|
113 | for h in self.header: | |||
|
114 | if self.special_re.match(h): | |||
|
115 | return True | |||
|
116 | ||||
|
117 | def countchanges(hunk): | |||
|
118 | add = len([h for h in hunk if h[0] == '+']) | |||
|
119 | rem = len([h for h in hunk if h[0] == '-']) | |||
|
120 | return add, rem | |||
|
121 | ||||
|
122 | class hunk(object): | |||
|
123 | maxcontext = 3 | |||
|
124 | ||||
|
125 | def __init__(self, header, fromline, toline, proc, before, hunk, after): | |||
|
126 | def trimcontext(number, lines): | |||
|
127 | delta = len(lines) - self.maxcontext | |||
|
128 | if False and delta > 0: | |||
|
129 | return number + delta, lines[:self.maxcontext] | |||
|
130 | return number, lines | |||
|
131 | ||||
|
132 | self.header = header | |||
|
133 | self.fromline, self.before = trimcontext(fromline, before) | |||
|
134 | self.toline, self.after = trimcontext(toline, after) | |||
|
135 | self.proc = proc | |||
|
136 | self.hunk = hunk | |||
|
137 | self.added, self.removed = countchanges(self.hunk) | |||
|
138 | ||||
|
139 | def write(self, fp): | |||
|
140 | delta = len(self.before) + len(self.after) | |||
|
141 | fromlen = delta + self.removed | |||
|
142 | tolen = delta + self.added | |||
|
143 | fp.write('@@ -%d,%d +%d,%d @@%s\n' % | |||
|
144 | (self.fromline, fromlen, self.toline, tolen, | |||
|
145 | self.proc and (' ' + self.proc))) | |||
|
146 | fp.write(''.join(self.before + self.hunk + self.after)) | |||
|
147 | ||||
|
148 | pretty = write | |||
|
149 | ||||
|
150 | def filename(self): | |||
|
151 | return self.header.filename() | |||
|
152 | ||||
|
153 | def __repr__(self): | |||
|
154 | return '<hunk %r@%d>' % (self.filename(), self.fromline) | |||
|
155 | ||||
|
156 | def parsepatch(fp): | |||
|
157 | class parser(object): | |||
|
158 | def __init__(self): | |||
|
159 | self.fromline = 0 | |||
|
160 | self.toline = 0 | |||
|
161 | self.proc = '' | |||
|
162 | self.header = None | |||
|
163 | self.context = [] | |||
|
164 | self.before = [] | |||
|
165 | self.hunk = [] | |||
|
166 | self.stream = [] | |||
|
167 | ||||
|
168 | def addrange(self, (fromstart, fromend, tostart, toend, proc)): | |||
|
169 | self.fromline = int(fromstart) | |||
|
170 | self.toline = int(tostart) | |||
|
171 | self.proc = proc | |||
|
172 | ||||
|
173 | def addcontext(self, context): | |||
|
174 | if self.hunk: | |||
|
175 | h = hunk(self.header, self.fromline, self.toline, self.proc, | |||
|
176 | self.before, self.hunk, context) | |||
|
177 | self.header.hunks.append(h) | |||
|
178 | self.stream.append(h) | |||
|
179 | self.fromline += len(self.before) + h.removed | |||
|
180 | self.toline += len(self.before) + h.added | |||
|
181 | self.before = [] | |||
|
182 | self.hunk = [] | |||
|
183 | self.proc = '' | |||
|
184 | self.context = context | |||
|
185 | ||||
|
186 | def addhunk(self, hunk): | |||
|
187 | if self.context: | |||
|
188 | self.before = self.context | |||
|
189 | self.context = [] | |||
|
190 | self.hunk = data | |||
|
191 | ||||
|
192 | def newfile(self, hdr): | |||
|
193 | self.addcontext([]) | |||
|
194 | h = header(hdr) | |||
|
195 | self.stream.append(h) | |||
|
196 | self.header = h | |||
|
197 | ||||
|
198 | def finished(self): | |||
|
199 | self.addcontext([]) | |||
|
200 | return self.stream | |||
|
201 | ||||
|
202 | transitions = { | |||
|
203 | 'file': {'context': addcontext, | |||
|
204 | 'file': newfile, | |||
|
205 | 'hunk': addhunk, | |||
|
206 | 'range': addrange}, | |||
|
207 | 'context': {'file': newfile, | |||
|
208 | 'hunk': addhunk, | |||
|
209 | 'range': addrange}, | |||
|
210 | 'hunk': {'context': addcontext, | |||
|
211 | 'file': newfile, | |||
|
212 | 'range': addrange}, | |||
|
213 | 'range': {'context': addcontext, | |||
|
214 | 'hunk': addhunk}, | |||
|
215 | } | |||
|
216 | ||||
|
217 | p = parser() | |||
|
218 | ||||
|
219 | state = 'context' | |||
|
220 | for newstate, data in scanpatch(fp): | |||
|
221 | try: | |||
|
222 | p.transitions[state][newstate](p, data) | |||
|
223 | except KeyError: | |||
|
224 | raise patch.PatchError('unhandled transition: %s -> %s' % | |||
|
225 | (state, newstate)) | |||
|
226 | state = newstate | |||
|
227 | return p.finished() | |||
|
228 | ||||
|
229 | def filterpatch(ui, chunks): | |||
|
230 | chunks = list(chunks) | |||
|
231 | chunks.reverse() | |||
|
232 | seen = {} | |||
|
233 | def consumefile(): | |||
|
234 | consumed = [] | |||
|
235 | while chunks: | |||
|
236 | if isinstance(chunks[-1], header): | |||
|
237 | break | |||
|
238 | else: | |||
|
239 | consumed.append(chunks.pop()) | |||
|
240 | return consumed | |||
|
241 | resp = None | |||
|
242 | applied = {} | |||
|
243 | while chunks: | |||
|
244 | chunk = chunks.pop() | |||
|
245 | if isinstance(chunk, header): | |||
|
246 | fixoffset = 0 | |||
|
247 | hdr = ''.join(chunk.header) | |||
|
248 | if hdr in seen: | |||
|
249 | consumefile() | |||
|
250 | continue | |||
|
251 | seen[hdr] = True | |||
|
252 | if not resp: | |||
|
253 | chunk.pretty(ui) | |||
|
254 | r = resp or ui.prompt(_('record changes to %s? [y]es [n]o') % | |||
|
255 | _(' and ').join(map(repr, chunk.files())), | |||
|
256 | '(?:|[yYnNqQaA])$') or 'y' | |||
|
257 | if r in 'aA': | |||
|
258 | r = 'y' | |||
|
259 | resp = 'y' | |||
|
260 | if r in 'qQ': | |||
|
261 | raise util.Abort(_('user quit')) | |||
|
262 | if r in 'yY': | |||
|
263 | applied[chunk.filename()] = [chunk] | |||
|
264 | if chunk.allhunks(): | |||
|
265 | applied[chunk.filename()] += consumefile() | |||
|
266 | else: | |||
|
267 | consumefile() | |||
|
268 | else: | |||
|
269 | if not resp: | |||
|
270 | chunk.pretty(ui) | |||
|
271 | r = resp or ui.prompt(_('record this change to %r? [y]es [n]o') % | |||
|
272 | chunk.filename(), '(?:|[yYnNqQaA])$') or 'y' | |||
|
273 | if r in 'aA': | |||
|
274 | r = 'y' | |||
|
275 | resp = 'y' | |||
|
276 | if r in 'qQ': | |||
|
277 | raise util.Abort(_('user quit')) | |||
|
278 | if r in 'yY': | |||
|
279 | if fixoffset: | |||
|
280 | chunk = copy.copy(chunk) | |||
|
281 | chunk.toline += fixoffset | |||
|
282 | applied[chunk.filename()].append(chunk) | |||
|
283 | else: | |||
|
284 | fixoffset += chunk.removed - chunk.added | |||
|
285 | return reduce(operator.add, [h for h in applied.itervalues() | |||
|
286 | if h[0].special() or len(h) > 1], []) | |||
|
287 | ||||
|
288 | def record(ui, repo, *pats, **opts): | |||
|
289 | '''interactively select changes to commit''' | |||
|
290 | ||||
|
291 | if not ui.interactive: | |||
|
292 | raise util.Abort(_('running non-interactively, use commit instead')) | |||
|
293 | ||||
|
294 | def recordfunc(ui, repo, files, message, match, opts): | |||
|
295 | if files: | |||
|
296 | changes = None | |||
|
297 | else: | |||
|
298 | changes = repo.status(files=files, match=match)[:5] | |||
|
299 | modified, added, removed = changes[:3] | |||
|
300 | files = modified + added + removed | |||
|
301 | diffopts = mdiff.diffopts(git=True, nodates=True) | |||
|
302 | fp = cStringIO.StringIO() | |||
|
303 | patch.diff(repo, repo.dirstate.parents()[0], files=files, | |||
|
304 | match=match, changes=changes, opts=diffopts, fp=fp) | |||
|
305 | fp.seek(0) | |||
|
306 | ||||
|
307 | chunks = filterpatch(ui, parsepatch(fp)) | |||
|
308 | del fp | |||
|
309 | ||||
|
310 | contenders = {} | |||
|
311 | for h in chunks: | |||
|
312 | try: contenders.update(dict.fromkeys(h.files())) | |||
|
313 | except AttributeError: pass | |||
|
314 | ||||
|
315 | newfiles = [f for f in files if f in contenders] | |||
|
316 | ||||
|
317 | if not newfiles: | |||
|
318 | ui.status(_('no changes to record\n')) | |||
|
319 | return 0 | |||
|
320 | ||||
|
321 | if changes is None: | |||
|
322 | changes = repo.status(files=newfiles, match=match)[:5] | |||
|
323 | modified = dict.fromkeys(changes[0]) | |||
|
324 | ||||
|
325 | backups = {} | |||
|
326 | backupdir = repo.join('record-backups') | |||
|
327 | try: | |||
|
328 | os.mkdir(backupdir) | |||
|
329 | except OSError, err: | |||
|
330 | if err.errno == errno.EEXIST: | |||
|
331 | pass | |||
|
332 | try: | |||
|
333 | for f in newfiles: | |||
|
334 | if f not in modified: | |||
|
335 | continue | |||
|
336 | fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.', | |||
|
337 | dir=backupdir) | |||
|
338 | os.close(fd) | |||
|
339 | ui.debug('backup %r as %r\n' % (f, tmpname)) | |||
|
340 | util.copyfile(repo.wjoin(f), tmpname) | |||
|
341 | backups[f] = tmpname | |||
|
342 | ||||
|
343 | fp = cStringIO.StringIO() | |||
|
344 | for c in chunks: | |||
|
345 | if c.filename() in backups: | |||
|
346 | c.write(fp) | |||
|
347 | dopatch = fp.tell() | |||
|
348 | fp.seek(0) | |||
|
349 | ||||
|
350 | if backups: | |||
|
351 | hg.revert(repo, repo.dirstate.parents()[0], backups.has_key) | |||
|
352 | ||||
|
353 | if dopatch: | |||
|
354 | ui.debug('applying patch\n') | |||
|
355 | ui.debug(fp.getvalue()) | |||
|
356 | patch.internalpatch(fp, ui, 1, repo.root) | |||
|
357 | del fp | |||
|
358 | ||||
|
359 | repo.commit(newfiles, message, opts['user'], opts['date'], match, | |||
|
360 | force_editor=opts.get('force_editor')) | |||
|
361 | return 0 | |||
|
362 | finally: | |||
|
363 | try: | |||
|
364 | for realname, tmpname in backups.iteritems(): | |||
|
365 | ui.debug('restoring %r to %r\n' % (tmpname, realname)) | |||
|
366 | util.copyfile(tmpname, realname) | |||
|
367 | os.unlink(tmpname) | |||
|
368 | os.rmdir(backupdir) | |||
|
369 | except OSError: | |||
|
370 | pass | |||
|
371 | return cmdutil.commit(ui, repo, recordfunc, pats, opts) | |||
|
372 | ||||
|
373 | cmdtable = { | |||
|
374 | 'record': | |||
|
375 | (record, [('A', 'addremove', None, | |||
|
376 | _('mark new/missing files as added/removed before committing')), | |||
|
377 | ('d', 'date', '', _('record datecode as commit date')), | |||
|
378 | ('u', 'user', '', _('record user as commiter')), | |||
|
379 | ] + commands.walkopts + commands.commitopts, | |||
|
380 | _('hg record [FILE]...')), | |||
|
381 | } |
@@ -0,0 +1,204 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | echo "[ui]" >> $HGRCPATH | |||
|
4 | echo "interactive=true" >> $HGRCPATH | |||
|
5 | echo "[extensions]" >> $HGRCPATH | |||
|
6 | echo "record=" >> $HGRCPATH | |||
|
7 | ||||
|
8 | echo % help | |||
|
9 | ||||
|
10 | hg help record | |||
|
11 | ||||
|
12 | hg init a | |||
|
13 | cd a | |||
|
14 | ||||
|
15 | echo % select no files | |||
|
16 | ||||
|
17 | touch empty-rw | |||
|
18 | hg add empty-rw | |||
|
19 | hg record empty-rw<<EOF | |||
|
20 | n | |||
|
21 | EOF | |||
|
22 | echo; hg tip -p | |||
|
23 | ||||
|
24 | echo % select files but no hunks | |||
|
25 | ||||
|
26 | hg record empty-rw<<EOF | |||
|
27 | y | |||
|
28 | n | |||
|
29 | EOF | |||
|
30 | echo; hg tip -p | |||
|
31 | ||||
|
32 | echo % record empty file | |||
|
33 | ||||
|
34 | hg record -d '0 0' -m empty empty-rw<<EOF | |||
|
35 | y | |||
|
36 | y | |||
|
37 | EOF | |||
|
38 | echo; hg tip -p | |||
|
39 | ||||
|
40 | echo % rename empty file | |||
|
41 | ||||
|
42 | hg mv empty-rw empty-rename | |||
|
43 | hg record -d '1 0' -m rename<<EOF | |||
|
44 | y | |||
|
45 | EOF | |||
|
46 | echo; hg tip -p | |||
|
47 | ||||
|
48 | echo % copy empty file | |||
|
49 | ||||
|
50 | hg cp empty-rename empty-copy | |||
|
51 | hg record -d '2 0' -m copy<<EOF | |||
|
52 | y | |||
|
53 | EOF | |||
|
54 | echo; hg tip -p | |||
|
55 | ||||
|
56 | echo % delete empty file | |||
|
57 | ||||
|
58 | hg rm empty-copy | |||
|
59 | hg record -d '3 0' -m delete<<EOF | |||
|
60 | y | |||
|
61 | EOF | |||
|
62 | echo; hg tip -p | |||
|
63 | ||||
|
64 | echo % add binary file | |||
|
65 | ||||
|
66 | hg bundle --base -2 tip.bundle | |||
|
67 | hg add tip.bundle | |||
|
68 | hg record -d '4 0' -m binary<<EOF | |||
|
69 | y | |||
|
70 | EOF | |||
|
71 | echo; hg tip -p | |||
|
72 | ||||
|
73 | echo % change binary file | |||
|
74 | ||||
|
75 | hg bundle --base -2 tip.bundle | |||
|
76 | hg record -d '5 0' -m binary-change<<EOF | |||
|
77 | y | |||
|
78 | EOF | |||
|
79 | echo; hg tip -p | |||
|
80 | ||||
|
81 | echo % rename and change binary file | |||
|
82 | ||||
|
83 | hg mv tip.bundle top.bundle | |||
|
84 | hg bundle --base -2 top.bundle | |||
|
85 | hg record -d '6 0' -m binary-change-rename<<EOF | |||
|
86 | y | |||
|
87 | EOF | |||
|
88 | echo; hg tip -p | |||
|
89 | ||||
|
90 | echo % add plain file | |||
|
91 | ||||
|
92 | for i in 1 2 3 4 5 6 7 8 9 10; do | |||
|
93 | echo $i >> plain | |||
|
94 | done | |||
|
95 | ||||
|
96 | hg add plain | |||
|
97 | hg record -d '7 0' -m plain plain<<EOF | |||
|
98 | y | |||
|
99 | y | |||
|
100 | EOF | |||
|
101 | echo; hg tip -p | |||
|
102 | ||||
|
103 | echo % modify end of plain file | |||
|
104 | ||||
|
105 | echo 11 >> plain | |||
|
106 | hg record -d '8 0' -m end plain <<EOF | |||
|
107 | y | |||
|
108 | y | |||
|
109 | EOF | |||
|
110 | ||||
|
111 | echo % modify end of plain file, no EOL | |||
|
112 | ||||
|
113 | hg tip --template '{node}' >> plain | |||
|
114 | hg record -d '9 0' -m noeol plain <<EOF | |||
|
115 | y | |||
|
116 | y | |||
|
117 | EOF | |||
|
118 | ||||
|
119 | echo % modify end of plain file, add EOL | |||
|
120 | ||||
|
121 | echo >> plain | |||
|
122 | hg record -d '10 0' -m eol plain <<EOF | |||
|
123 | y | |||
|
124 | y | |||
|
125 | y | |||
|
126 | EOF | |||
|
127 | ||||
|
128 | echo % modify beginning, trim end, record both | |||
|
129 | ||||
|
130 | rm plain | |||
|
131 | for i in 2 2 3 4 5 6 7 8 9 10; do | |||
|
132 | echo $i >> plain | |||
|
133 | done | |||
|
134 | ||||
|
135 | hg record -d '10 0' -m begin-and-end plain <<EOF | |||
|
136 | y | |||
|
137 | y | |||
|
138 | y | |||
|
139 | EOF | |||
|
140 | echo; hg tip -p | |||
|
141 | ||||
|
142 | echo % trim beginning, modify end | |||
|
143 | ||||
|
144 | rm plain | |||
|
145 | for i in 4 5 6 7 8 9 10.new; do | |||
|
146 | echo $i >> plain | |||
|
147 | done | |||
|
148 | ||||
|
149 | echo % record end | |||
|
150 | ||||
|
151 | hg record -d '11 0' -m end-only plain <<EOF | |||
|
152 | y | |||
|
153 | n | |||
|
154 | y | |||
|
155 | EOF | |||
|
156 | echo; hg tip -p | |||
|
157 | ||||
|
158 | echo % record beginning | |||
|
159 | ||||
|
160 | hg record -d '12 0' -m begin-only plain <<EOF | |||
|
161 | y | |||
|
162 | y | |||
|
163 | EOF | |||
|
164 | echo; hg tip -p | |||
|
165 | ||||
|
166 | echo % add to beginning, trim from end | |||
|
167 | ||||
|
168 | rm plain | |||
|
169 | for i in 1 2 3 4 5 6 7 8 9; do | |||
|
170 | echo $i >> plain | |||
|
171 | done | |||
|
172 | ||||
|
173 | echo % record end | |||
|
174 | ||||
|
175 | hg record --traceback -d '13 0' -m end-again plain<<EOF | |||
|
176 | y | |||
|
177 | n | |||
|
178 | y | |||
|
179 | EOF | |||
|
180 | ||||
|
181 | echo % add to beginning, middle, end | |||
|
182 | ||||
|
183 | rm plain | |||
|
184 | for i in 1 2 3 4 5 5.new 5.reallynew 6 7 8 9 10 11; do | |||
|
185 | echo $i >> plain | |||
|
186 | done | |||
|
187 | ||||
|
188 | echo % record beginning, middle | |||
|
189 | ||||
|
190 | hg record -d '14 0' -m middle-only plain <<EOF | |||
|
191 | y | |||
|
192 | y | |||
|
193 | y | |||
|
194 | n | |||
|
195 | EOF | |||
|
196 | echo; hg tip -p | |||
|
197 | ||||
|
198 | echo % record end | |||
|
199 | ||||
|
200 | hg record -d '15 0' -m end-only plain <<EOF | |||
|
201 | y | |||
|
202 | y | |||
|
203 | EOF | |||
|
204 | echo; hg tip -p |
@@ -0,0 +1,383 b'' | |||||
|
1 | % help | |||
|
2 | hg record [FILE]... | |||
|
3 | ||||
|
4 | interactively select changes to commit | |||
|
5 | ||||
|
6 | options: | |||
|
7 | ||||
|
8 | -A --addremove mark new/missing files as added/removed before committing | |||
|
9 | -d --date record datecode as commit date | |||
|
10 | -u --user record user as commiter | |||
|
11 | -I --include include names matching the given patterns | |||
|
12 | -X --exclude exclude names matching the given patterns | |||
|
13 | -m --message use <text> as commit message | |||
|
14 | -l --logfile read commit message from <file> | |||
|
15 | ||||
|
16 | use "hg -v help record" to show global options | |||
|
17 | % select no files | |||
|
18 | diff --git a/empty-rw b/empty-rw | |||
|
19 | new file mode 100644 | |||
|
20 | record changes to 'empty-rw'? [y]es [n]o no changes to record | |||
|
21 | ||||
|
22 | changeset: -1:000000000000 | |||
|
23 | tag: tip | |||
|
24 | user: | |||
|
25 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
26 | ||||
|
27 | ||||
|
28 | % select files but no hunks | |||
|
29 | diff --git a/empty-rw b/empty-rw | |||
|
30 | new file mode 100644 | |||
|
31 | record changes to 'empty-rw'? [y]es [n]o transaction abort! | |||
|
32 | rollback completed | |||
|
33 | ||||
|
34 | changeset: -1:000000000000 | |||
|
35 | tag: tip | |||
|
36 | user: | |||
|
37 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
38 | ||||
|
39 | ||||
|
40 | % record empty file | |||
|
41 | diff --git a/empty-rw b/empty-rw | |||
|
42 | new file mode 100644 | |||
|
43 | record changes to 'empty-rw'? [y]es [n]o | |||
|
44 | changeset: 0:c0708cf4e46e | |||
|
45 | tag: tip | |||
|
46 | user: test | |||
|
47 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
48 | summary: empty | |||
|
49 | ||||
|
50 | ||||
|
51 | % rename empty file | |||
|
52 | diff --git a/empty-rw b/empty-rename | |||
|
53 | rename from empty-rw | |||
|
54 | rename to empty-rename | |||
|
55 | record changes to 'empty-rw' and 'empty-rename'? [y]es [n]o | |||
|
56 | changeset: 1:df251d174da3 | |||
|
57 | tag: tip | |||
|
58 | user: test | |||
|
59 | date: Thu Jan 01 00:00:01 1970 +0000 | |||
|
60 | summary: rename | |||
|
61 | ||||
|
62 | ||||
|
63 | % copy empty file | |||
|
64 | diff --git a/empty-rename b/empty-copy | |||
|
65 | copy from empty-rename | |||
|
66 | copy to empty-copy | |||
|
67 | record changes to 'empty-rename' and 'empty-copy'? [y]es [n]o | |||
|
68 | changeset: 2:b63ea3939f8d | |||
|
69 | tag: tip | |||
|
70 | user: test | |||
|
71 | date: Thu Jan 01 00:00:02 1970 +0000 | |||
|
72 | summary: copy | |||
|
73 | ||||
|
74 | ||||
|
75 | % delete empty file | |||
|
76 | diff --git a/empty-copy b/empty-copy | |||
|
77 | deleted file mode 100644 | |||
|
78 | record changes to 'empty-copy'? [y]es [n]o | |||
|
79 | changeset: 3:a2546574bce9 | |||
|
80 | tag: tip | |||
|
81 | user: test | |||
|
82 | date: Thu Jan 01 00:00:03 1970 +0000 | |||
|
83 | summary: delete | |||
|
84 | ||||
|
85 | ||||
|
86 | % add binary file | |||
|
87 | diff --git a/tip.bundle b/tip.bundle | |||
|
88 | new file mode 100644 | |||
|
89 | this is a binary file | |||
|
90 | record changes to 'tip.bundle'? [y]es [n]o | |||
|
91 | changeset: 4:9e998a545a8b | |||
|
92 | tag: tip | |||
|
93 | user: test | |||
|
94 | date: Thu Jan 01 00:00:04 1970 +0000 | |||
|
95 | summary: binary | |||
|
96 | ||||
|
97 | diff -r a2546574bce9 -r 9e998a545a8b tip.bundle | |||
|
98 | Binary file tip.bundle has changed | |||
|
99 | ||||
|
100 | % change binary file | |||
|
101 | diff --git a/tip.bundle b/tip.bundle | |||
|
102 | this modifies a binary file (all or nothing) | |||
|
103 | record changes to 'tip.bundle'? [y]es [n]o | |||
|
104 | changeset: 5:93d05561507d | |||
|
105 | tag: tip | |||
|
106 | user: test | |||
|
107 | date: Thu Jan 01 00:00:05 1970 +0000 | |||
|
108 | summary: binary-change | |||
|
109 | ||||
|
110 | diff -r 9e998a545a8b -r 93d05561507d tip.bundle | |||
|
111 | Binary file tip.bundle has changed | |||
|
112 | ||||
|
113 | % rename and change binary file | |||
|
114 | diff --git a/tip.bundle b/top.bundle | |||
|
115 | rename from tip.bundle | |||
|
116 | rename to top.bundle | |||
|
117 | this modifies a binary file (all or nothing) | |||
|
118 | record changes to 'tip.bundle' and 'top.bundle'? [y]es [n]o | |||
|
119 | changeset: 6:699cc1bea9aa | |||
|
120 | tag: tip | |||
|
121 | user: test | |||
|
122 | date: Thu Jan 01 00:00:06 1970 +0000 | |||
|
123 | summary: binary-change-rename | |||
|
124 | ||||
|
125 | diff -r 93d05561507d -r 699cc1bea9aa tip.bundle | |||
|
126 | Binary file tip.bundle has changed | |||
|
127 | diff -r 93d05561507d -r 699cc1bea9aa top.bundle | |||
|
128 | Binary file top.bundle has changed | |||
|
129 | ||||
|
130 | % add plain file | |||
|
131 | diff --git a/plain b/plain | |||
|
132 | new file mode 100644 | |||
|
133 | record changes to 'plain'? [y]es [n]o | |||
|
134 | changeset: 7:118ed744216b | |||
|
135 | tag: tip | |||
|
136 | user: test | |||
|
137 | date: Thu Jan 01 00:00:07 1970 +0000 | |||
|
138 | summary: plain | |||
|
139 | ||||
|
140 | diff -r 699cc1bea9aa -r 118ed744216b plain | |||
|
141 | --- /dev/null Thu Jan 01 00:00:00 1970 +0000 | |||
|
142 | +++ b/plain Thu Jan 01 00:00:07 1970 +0000 | |||
|
143 | @@ -0,0 +1,10 @@ | |||
|
144 | +1 | |||
|
145 | +2 | |||
|
146 | +3 | |||
|
147 | +4 | |||
|
148 | +5 | |||
|
149 | +6 | |||
|
150 | +7 | |||
|
151 | +8 | |||
|
152 | +9 | |||
|
153 | +10 | |||
|
154 | ||||
|
155 | % modify end of plain file | |||
|
156 | diff --git a/plain b/plain | |||
|
157 | 1 hunks, 1 lines changed | |||
|
158 | record changes to 'plain'? [y]es [n]o @@ -8,3 +8,4 @@ 8 | |||
|
159 | 8 | |||
|
160 | 9 | |||
|
161 | 10 | |||
|
162 | +11 | |||
|
163 | record this change to 'plain'? [y]es [n]o % modify end of plain file, no EOL | |||
|
164 | diff --git a/plain b/plain | |||
|
165 | 1 hunks, 1 lines changed | |||
|
166 | record changes to 'plain'? [y]es [n]o @@ -9,3 +9,4 @@ 9 | |||
|
167 | 9 | |||
|
168 | 10 | |||
|
169 | 11 | |||
|
170 | +cf81a2760718a74d44c0c2eecb72f659e63a69c5 | |||
|
171 | \ No newline at end of file | |||
|
172 | record this change to 'plain'? [y]es [n]o % modify end of plain file, add EOL | |||
|
173 | diff --git a/plain b/plain | |||
|
174 | 1 hunks, 2 lines changed | |||
|
175 | record changes to 'plain'? [y]es [n]o @@ -9,4 +9,4 @@ 9 | |||
|
176 | 9 | |||
|
177 | 10 | |||
|
178 | 11 | |||
|
179 | -cf81a2760718a74d44c0c2eecb72f659e63a69c5 | |||
|
180 | \ No newline at end of file | |||
|
181 | +cf81a2760718a74d44c0c2eecb72f659e63a69c5 | |||
|
182 | record this change to 'plain'? [y]es [n]o % modify beginning, trim end, record both | |||
|
183 | diff --git a/plain b/plain | |||
|
184 | 2 hunks, 4 lines changed | |||
|
185 | record changes to 'plain'? [y]es [n]o @@ -1,4 +1,4 @@ 1 | |||
|
186 | -1 | |||
|
187 | +2 | |||
|
188 | 2 | |||
|
189 | 3 | |||
|
190 | 4 | |||
|
191 | record this change to 'plain'? [y]es [n]o @@ -8,5 +8,3 @@ 8 | |||
|
192 | 8 | |||
|
193 | 9 | |||
|
194 | 10 | |||
|
195 | -11 | |||
|
196 | -cf81a2760718a74d44c0c2eecb72f659e63a69c5 | |||
|
197 | record this change to 'plain'? [y]es [n]o | |||
|
198 | changeset: 11:d09ab1967dab | |||
|
199 | tag: tip | |||
|
200 | user: test | |||
|
201 | date: Thu Jan 01 00:00:10 1970 +0000 | |||
|
202 | summary: begin-and-end | |||
|
203 | ||||
|
204 | diff -r e2ecd9b0b78d -r d09ab1967dab plain | |||
|
205 | --- a/plain Thu Jan 01 00:00:10 1970 +0000 | |||
|
206 | +++ b/plain Thu Jan 01 00:00:10 1970 +0000 | |||
|
207 | @@ -1,4 +1,4 @@ 1 | |||
|
208 | -1 | |||
|
209 | +2 | |||
|
210 | 2 | |||
|
211 | 3 | |||
|
212 | 4 | |||
|
213 | @@ -8,5 +8,3 @@ 8 | |||
|
214 | 8 | |||
|
215 | 9 | |||
|
216 | 10 | |||
|
217 | -11 | |||
|
218 | -cf81a2760718a74d44c0c2eecb72f659e63a69c5 | |||
|
219 | ||||
|
220 | % trim beginning, modify end | |||
|
221 | % record end | |||
|
222 | diff --git a/plain b/plain | |||
|
223 | 2 hunks, 5 lines changed | |||
|
224 | record changes to 'plain'? [y]es [n]o @@ -1,9 +1,6 @@ 2 | |||
|
225 | -2 | |||
|
226 | -2 | |||
|
227 | -3 | |||
|
228 | 4 | |||
|
229 | 5 | |||
|
230 | 6 | |||
|
231 | 7 | |||
|
232 | 8 | |||
|
233 | 9 | |||
|
234 | record this change to 'plain'? [y]es [n]o @@ -4,7 +1,7 @@ | |||
|
235 | 4 | |||
|
236 | 5 | |||
|
237 | 6 | |||
|
238 | 7 | |||
|
239 | 8 | |||
|
240 | 9 | |||
|
241 | -10 | |||
|
242 | +10.new | |||
|
243 | record this change to 'plain'? [y]es [n]o | |||
|
244 | changeset: 12:44516c9708ae | |||
|
245 | tag: tip | |||
|
246 | user: test | |||
|
247 | date: Thu Jan 01 00:00:11 1970 +0000 | |||
|
248 | summary: end-only | |||
|
249 | ||||
|
250 | diff -r d09ab1967dab -r 44516c9708ae plain | |||
|
251 | --- a/plain Thu Jan 01 00:00:10 1970 +0000 | |||
|
252 | +++ b/plain Thu Jan 01 00:00:11 1970 +0000 | |||
|
253 | @@ -7,4 +7,4 @@ 7 | |||
|
254 | 7 | |||
|
255 | 8 | |||
|
256 | 9 | |||
|
257 | -10 | |||
|
258 | +10.new | |||
|
259 | ||||
|
260 | % record beginning | |||
|
261 | diff --git a/plain b/plain | |||
|
262 | 1 hunks, 3 lines changed | |||
|
263 | record changes to 'plain'? [y]es [n]o @@ -1,6 +1,3 @@ 2 | |||
|
264 | -2 | |||
|
265 | -2 | |||
|
266 | -3 | |||
|
267 | 4 | |||
|
268 | 5 | |||
|
269 | 6 | |||
|
270 | record this change to 'plain'? [y]es [n]o | |||
|
271 | changeset: 13:3ebbace64a8d | |||
|
272 | tag: tip | |||
|
273 | user: test | |||
|
274 | date: Thu Jan 01 00:00:12 1970 +0000 | |||
|
275 | summary: begin-only | |||
|
276 | ||||
|
277 | diff -r 44516c9708ae -r 3ebbace64a8d plain | |||
|
278 | --- a/plain Thu Jan 01 00:00:11 1970 +0000 | |||
|
279 | +++ b/plain Thu Jan 01 00:00:12 1970 +0000 | |||
|
280 | @@ -1,6 +1,3 @@ 2 | |||
|
281 | -2 | |||
|
282 | -2 | |||
|
283 | -3 | |||
|
284 | 4 | |||
|
285 | 5 | |||
|
286 | 6 | |||
|
287 | ||||
|
288 | % add to beginning, trim from end | |||
|
289 | % record end | |||
|
290 | diff --git a/plain b/plain | |||
|
291 | 2 hunks, 4 lines changed | |||
|
292 | record changes to 'plain'? [y]es [n]o @@ -1,6 +1,9 @@ 4 | |||
|
293 | +1 | |||
|
294 | +2 | |||
|
295 | +3 | |||
|
296 | 4 | |||
|
297 | 5 | |||
|
298 | 6 | |||
|
299 | 7 | |||
|
300 | 8 | |||
|
301 | 9 | |||
|
302 | record this change to 'plain'? [y]es [n]o @@ -1,7 +4,6 @@ | |||
|
303 | 4 | |||
|
304 | 5 | |||
|
305 | 6 | |||
|
306 | 7 | |||
|
307 | 8 | |||
|
308 | 9 | |||
|
309 | -10.new | |||
|
310 | record this change to 'plain'? [y]es [n]o % add to beginning, middle, end | |||
|
311 | % record beginning, middle | |||
|
312 | diff --git a/plain b/plain | |||
|
313 | 3 hunks, 7 lines changed | |||
|
314 | record changes to 'plain'? [y]es [n]o @@ -1,2 +1,5 @@ 4 | |||
|
315 | +1 | |||
|
316 | +2 | |||
|
317 | +3 | |||
|
318 | 4 | |||
|
319 | 5 | |||
|
320 | record this change to 'plain'? [y]es [n]o @@ -1,6 +4,8 @@ | |||
|
321 | 4 | |||
|
322 | 5 | |||
|
323 | +5.new | |||
|
324 | +5.reallynew | |||
|
325 | 6 | |||
|
326 | 7 | |||
|
327 | 8 | |||
|
328 | 9 | |||
|
329 | record this change to 'plain'? [y]es [n]o @@ -3,4 +8,6 @@ | |||
|
330 | 6 | |||
|
331 | 7 | |||
|
332 | 8 | |||
|
333 | 9 | |||
|
334 | +10 | |||
|
335 | +11 | |||
|
336 | record this change to 'plain'? [y]es [n]o | |||
|
337 | changeset: 15:c1c639d8b268 | |||
|
338 | tag: tip | |||
|
339 | user: test | |||
|
340 | date: Thu Jan 01 00:00:14 1970 +0000 | |||
|
341 | summary: middle-only | |||
|
342 | ||||
|
343 | diff -r efc0dad7bd9f -r c1c639d8b268 plain | |||
|
344 | --- a/plain Thu Jan 01 00:00:13 1970 +0000 | |||
|
345 | +++ b/plain Thu Jan 01 00:00:14 1970 +0000 | |||
|
346 | @@ -1,5 +1,10 @@ 4 | |||
|
347 | +1 | |||
|
348 | +2 | |||
|
349 | +3 | |||
|
350 | 4 | |||
|
351 | 5 | |||
|
352 | +5.new | |||
|
353 | +5.reallynew | |||
|
354 | 6 | |||
|
355 | 7 | |||
|
356 | 8 | |||
|
357 | ||||
|
358 | % record end | |||
|
359 | diff --git a/plain b/plain | |||
|
360 | 1 hunks, 2 lines changed | |||
|
361 | record changes to 'plain'? [y]es [n]o @@ -9,3 +9,5 @@ 7 | |||
|
362 | 7 | |||
|
363 | 8 | |||
|
364 | 9 | |||
|
365 | +10 | |||
|
366 | +11 | |||
|
367 | record this change to 'plain'? [y]es [n]o | |||
|
368 | changeset: 16:80b74bbc7808 | |||
|
369 | tag: tip | |||
|
370 | user: test | |||
|
371 | date: Thu Jan 01 00:00:15 1970 +0000 | |||
|
372 | summary: end-only | |||
|
373 | ||||
|
374 | diff -r c1c639d8b268 -r 80b74bbc7808 plain | |||
|
375 | --- a/plain Thu Jan 01 00:00:14 1970 +0000 | |||
|
376 | +++ b/plain Thu Jan 01 00:00:15 1970 +0000 | |||
|
377 | @@ -9,3 +9,5 @@ 7 | |||
|
378 | 7 | |||
|
379 | 8 | |||
|
380 | 9 | |||
|
381 | +10 | |||
|
382 | +11 | |||
|
383 |
General Comments 0
You need to be logged in to leave comments.
Login now