##// END OF EJS Templates
commitctx: rename files to touched in a couple of place...
marmoute -
r45810:efe8a677 default
parent child Browse files
Show More
@@ -1,445 +1,445 b''
1 # commit.py - fonction to perform commit
1 # commit.py - fonction to perform commit
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 import errno
8 import errno
9
9
10 from .i18n import _
10 from .i18n import _
11 from .node import (
11 from .node import (
12 hex,
12 hex,
13 nullid,
13 nullid,
14 nullrev,
14 nullrev,
15 )
15 )
16
16
17 from . import (
17 from . import (
18 context,
18 context,
19 mergestate,
19 mergestate,
20 metadata,
20 metadata,
21 phases,
21 phases,
22 scmutil,
22 scmutil,
23 subrepoutil,
23 subrepoutil,
24 )
24 )
25
25
26
26
27 def _write_copy_meta(repo):
27 def _write_copy_meta(repo):
28 """return a (changelog, filelog) boolean tuple
28 """return a (changelog, filelog) boolean tuple
29
29
30 changelog: copy related information should be stored in the changeset
30 changelog: copy related information should be stored in the changeset
31 filelof: copy related information should be written in the file revision
31 filelof: copy related information should be written in the file revision
32 """
32 """
33 if repo.filecopiesmode == b'changeset-sidedata':
33 if repo.filecopiesmode == b'changeset-sidedata':
34 writechangesetcopy = True
34 writechangesetcopy = True
35 writefilecopymeta = True
35 writefilecopymeta = True
36 else:
36 else:
37 writecopiesto = repo.ui.config(b'experimental', b'copies.write-to')
37 writecopiesto = repo.ui.config(b'experimental', b'copies.write-to')
38 writefilecopymeta = writecopiesto != b'changeset-only'
38 writefilecopymeta = writecopiesto != b'changeset-only'
39 writechangesetcopy = writecopiesto in (
39 writechangesetcopy = writecopiesto in (
40 b'changeset-only',
40 b'changeset-only',
41 b'compatibility',
41 b'compatibility',
42 )
42 )
43 return writechangesetcopy, writefilecopymeta
43 return writechangesetcopy, writefilecopymeta
44
44
45
45
46 def commitctx(repo, ctx, error=False, origctx=None):
46 def commitctx(repo, ctx, error=False, origctx=None):
47 """Add a new revision to the target repository.
47 """Add a new revision to the target repository.
48 Revision information is passed via the context argument.
48 Revision information is passed via the context argument.
49
49
50 ctx.files() should list all files involved in this commit, i.e.
50 ctx.files() should list all files involved in this commit, i.e.
51 modified/added/removed files. On merge, it may be wider than the
51 modified/added/removed files. On merge, it may be wider than the
52 ctx.files() to be committed, since any file nodes derived directly
52 ctx.files() to be committed, since any file nodes derived directly
53 from p1 or p2 are excluded from the committed ctx.files().
53 from p1 or p2 are excluded from the committed ctx.files().
54
54
55 origctx is for convert to work around the problem that bug
55 origctx is for convert to work around the problem that bug
56 fixes to the files list in changesets change hashes. For
56 fixes to the files list in changesets change hashes. For
57 convert to be the identity, it can pass an origctx and this
57 convert to be the identity, it can pass an origctx and this
58 function will use the same files list when it makes sense to
58 function will use the same files list when it makes sense to
59 do so.
59 do so.
60 """
60 """
61 repo = repo.unfiltered()
61 repo = repo.unfiltered()
62
62
63 p1, p2 = ctx.p1(), ctx.p2()
63 p1, p2 = ctx.p1(), ctx.p2()
64 user = ctx.user()
64 user = ctx.user()
65
65
66 with repo.lock(), repo.transaction(b"commit") as tr:
66 with repo.lock(), repo.transaction(b"commit") as tr:
67 r = _prepare_files(tr, ctx, error=error, origctx=origctx)
67 r = _prepare_files(tr, ctx, error=error, origctx=origctx)
68 mn, files, p1copies, p2copies, filesadded, filesremoved = r
68 mn, files, p1copies, p2copies, filesadded, filesremoved = r
69
69
70 extra = ctx.extra().copy()
70 extra = ctx.extra().copy()
71
71
72 files = sorted(files)
72 files = sorted(files)
73 if extra is not None:
73 if extra is not None:
74 for name in (
74 for name in (
75 b'p1copies',
75 b'p1copies',
76 b'p2copies',
76 b'p2copies',
77 b'filesadded',
77 b'filesadded',
78 b'filesremoved',
78 b'filesremoved',
79 ):
79 ):
80 extra.pop(name, None)
80 extra.pop(name, None)
81 if repo.changelog._copiesstorage == b'extra':
81 if repo.changelog._copiesstorage == b'extra':
82 extra = _extra_with_copies(
82 extra = _extra_with_copies(
83 repo, extra, files, p1copies, p2copies, filesadded, filesremoved
83 repo, extra, files, p1copies, p2copies, filesadded, filesremoved
84 )
84 )
85
85
86 # update changelog
86 # update changelog
87 repo.ui.note(_(b"committing changelog\n"))
87 repo.ui.note(_(b"committing changelog\n"))
88 repo.changelog.delayupdate(tr)
88 repo.changelog.delayupdate(tr)
89 n = repo.changelog.add(
89 n = repo.changelog.add(
90 mn,
90 mn,
91 files,
91 files,
92 ctx.description(),
92 ctx.description(),
93 tr,
93 tr,
94 p1.node(),
94 p1.node(),
95 p2.node(),
95 p2.node(),
96 user,
96 user,
97 ctx.date(),
97 ctx.date(),
98 extra,
98 extra,
99 p1copies,
99 p1copies,
100 p2copies,
100 p2copies,
101 filesadded,
101 filesadded,
102 filesremoved,
102 filesremoved,
103 )
103 )
104 xp1, xp2 = p1.hex(), p2 and p2.hex() or b''
104 xp1, xp2 = p1.hex(), p2 and p2.hex() or b''
105 repo.hook(
105 repo.hook(
106 b'pretxncommit', throw=True, node=hex(n), parent1=xp1, parent2=xp2,
106 b'pretxncommit', throw=True, node=hex(n), parent1=xp1, parent2=xp2,
107 )
107 )
108 # set the new commit is proper phase
108 # set the new commit is proper phase
109 targetphase = subrepoutil.newcommitphase(repo.ui, ctx)
109 targetphase = subrepoutil.newcommitphase(repo.ui, ctx)
110 if targetphase:
110 if targetphase:
111 # retract boundary do not alter parent changeset.
111 # retract boundary do not alter parent changeset.
112 # if a parent have higher the resulting phase will
112 # if a parent have higher the resulting phase will
113 # be compliant anyway
113 # be compliant anyway
114 #
114 #
115 # if minimal phase was 0 we don't need to retract anything
115 # if minimal phase was 0 we don't need to retract anything
116 phases.registernew(repo, tr, targetphase, [n])
116 phases.registernew(repo, tr, targetphase, [n])
117 return n
117 return n
118
118
119
119
120 def _prepare_files(tr, ctx, error=False, origctx=None):
120 def _prepare_files(tr, ctx, error=False, origctx=None):
121 repo = ctx.repo()
121 repo = ctx.repo()
122 p1 = ctx.p1()
122 p1 = ctx.p1()
123
123
124 writechangesetcopy, writefilecopymeta = _write_copy_meta(repo)
124 writechangesetcopy, writefilecopymeta = _write_copy_meta(repo)
125
125
126 p1copies, p2copies = None, None
126 p1copies, p2copies = None, None
127 if writechangesetcopy:
127 if writechangesetcopy:
128 p1copies = ctx.p1copies()
128 p1copies = ctx.p1copies()
129 p2copies = ctx.p2copies()
129 p2copies = ctx.p2copies()
130 filesadded, filesremoved = None, None
130 filesadded, filesremoved = None, None
131 if ctx.manifestnode():
131 if ctx.manifestnode():
132 # reuse an existing manifest revision
132 # reuse an existing manifest revision
133 repo.ui.debug(b'reusing known manifest\n')
133 repo.ui.debug(b'reusing known manifest\n')
134 mn = ctx.manifestnode()
134 mn = ctx.manifestnode()
135 files = ctx.files()
135 touched = ctx.files()
136 if writechangesetcopy:
136 if writechangesetcopy:
137 filesadded = ctx.filesadded()
137 filesadded = ctx.filesadded()
138 filesremoved = ctx.filesremoved()
138 filesremoved = ctx.filesremoved()
139 elif not ctx.files():
139 elif not ctx.files():
140 repo.ui.debug(b'reusing manifest from p1 (no file change)\n')
140 repo.ui.debug(b'reusing manifest from p1 (no file change)\n')
141 mn = p1.manifestnode()
141 mn = p1.manifestnode()
142 files = []
142 touched = []
143 else:
143 else:
144 mn, files, added, removed = _process_files(tr, ctx, error=error)
144 mn, touched, added, removed = _process_files(tr, ctx, error=error)
145 if writechangesetcopy:
145 if writechangesetcopy:
146 filesremoved = removed
146 filesremoved = removed
147 filesadded = added
147 filesadded = added
148
148
149 if origctx and origctx.manifestnode() == mn:
149 if origctx and origctx.manifestnode() == mn:
150 files = origctx.files()
150 touched = origctx.files()
151
151
152 if not writefilecopymeta:
152 if not writefilecopymeta:
153 # If writing only to changeset extras, use None to indicate that
153 # If writing only to changeset extras, use None to indicate that
154 # no entry should be written. If writing to both, write an empty
154 # no entry should be written. If writing to both, write an empty
155 # entry to prevent the reader from falling back to reading
155 # entry to prevent the reader from falling back to reading
156 # filelogs.
156 # filelogs.
157 p1copies = p1copies or None
157 p1copies = p1copies or None
158 p2copies = p2copies or None
158 p2copies = p2copies or None
159 filesadded = filesadded or None
159 filesadded = filesadded or None
160 filesremoved = filesremoved or None
160 filesremoved = filesremoved or None
161
161
162 return mn, files, p1copies, p2copies, filesadded, filesremoved
162 return mn, touched, p1copies, p2copies, filesadded, filesremoved
163
163
164
164
165 def _process_files(tr, ctx, error=False):
165 def _process_files(tr, ctx, error=False):
166 repo = ctx.repo()
166 repo = ctx.repo()
167 p1 = ctx.p1()
167 p1 = ctx.p1()
168 p2 = ctx.p2()
168 p2 = ctx.p2()
169
169
170 writechangesetcopy, writefilecopymeta = _write_copy_meta(repo)
170 writechangesetcopy, writefilecopymeta = _write_copy_meta(repo)
171
171
172 m1ctx = p1.manifestctx()
172 m1ctx = p1.manifestctx()
173 m2ctx = p2.manifestctx()
173 m2ctx = p2.manifestctx()
174 mctx = m1ctx.copy()
174 mctx = m1ctx.copy()
175
175
176 m = mctx.read()
176 m = mctx.read()
177 m1 = m1ctx.read()
177 m1 = m1ctx.read()
178 m2 = m2ctx.read()
178 m2 = m2ctx.read()
179
179
180 # check in files
180 # check in files
181 added = []
181 added = []
182 filesadded = []
182 filesadded = []
183 removed = list(ctx.removed())
183 removed = list(ctx.removed())
184 touched = []
184 touched = []
185 linkrev = len(repo)
185 linkrev = len(repo)
186 repo.ui.note(_(b"committing files:\n"))
186 repo.ui.note(_(b"committing files:\n"))
187 uipathfn = scmutil.getuipathfn(repo)
187 uipathfn = scmutil.getuipathfn(repo)
188 for f in sorted(ctx.modified() + ctx.added()):
188 for f in sorted(ctx.modified() + ctx.added()):
189 repo.ui.note(uipathfn(f) + b"\n")
189 repo.ui.note(uipathfn(f) + b"\n")
190 try:
190 try:
191 fctx = ctx[f]
191 fctx = ctx[f]
192 if fctx is None:
192 if fctx is None:
193 removed.append(f)
193 removed.append(f)
194 else:
194 else:
195 added.append(f)
195 added.append(f)
196 m[f], is_touched = _filecommit(
196 m[f], is_touched = _filecommit(
197 repo, fctx, m1, m2, linkrev, tr, writefilecopymeta,
197 repo, fctx, m1, m2, linkrev, tr, writefilecopymeta,
198 )
198 )
199 if is_touched:
199 if is_touched:
200 touched.append(f)
200 touched.append(f)
201 if is_touched == 'added':
201 if is_touched == 'added':
202 filesadded.append(f)
202 filesadded.append(f)
203 m.setflag(f, fctx.flags())
203 m.setflag(f, fctx.flags())
204 except OSError:
204 except OSError:
205 repo.ui.warn(_(b"trouble committing %s!\n") % uipathfn(f))
205 repo.ui.warn(_(b"trouble committing %s!\n") % uipathfn(f))
206 raise
206 raise
207 except IOError as inst:
207 except IOError as inst:
208 errcode = getattr(inst, 'errno', errno.ENOENT)
208 errcode = getattr(inst, 'errno', errno.ENOENT)
209 if error or errcode and errcode != errno.ENOENT:
209 if error or errcode and errcode != errno.ENOENT:
210 repo.ui.warn(_(b"trouble committing %s!\n") % uipathfn(f))
210 repo.ui.warn(_(b"trouble committing %s!\n") % uipathfn(f))
211 raise
211 raise
212
212
213 # update manifest
213 # update manifest
214 removed = [f for f in removed if f in m1 or f in m2]
214 removed = [f for f in removed if f in m1 or f in m2]
215 drop = sorted([f for f in removed if f in m])
215 drop = sorted([f for f in removed if f in m])
216 for f in drop:
216 for f in drop:
217 del m[f]
217 del m[f]
218 if p2.rev() != nullrev:
218 if p2.rev() != nullrev:
219 rf = metadata.get_removal_filter(ctx, (p1, p2, m1, m2))
219 rf = metadata.get_removal_filter(ctx, (p1, p2, m1, m2))
220 removed = [f for f in removed if not rf(f)]
220 removed = [f for f in removed if not rf(f)]
221
221
222 touched.extend(removed)
222 touched.extend(removed)
223
223
224 files = touched
224 files = touched
225 mn = _commit_manifest(tr, linkrev, ctx, mctx, m, files, added, drop)
225 mn = _commit_manifest(tr, linkrev, ctx, mctx, m, files, added, drop)
226
226
227 return mn, files, filesadded, removed
227 return mn, files, filesadded, removed
228
228
229
229
230 def _filecommit(
230 def _filecommit(
231 repo, fctx, manifest1, manifest2, linkrev, tr, includecopymeta,
231 repo, fctx, manifest1, manifest2, linkrev, tr, includecopymeta,
232 ):
232 ):
233 """
233 """
234 commit an individual file as part of a larger transaction
234 commit an individual file as part of a larger transaction
235
235
236 input:
236 input:
237
237
238 fctx: a file context with the content we are trying to commit
238 fctx: a file context with the content we are trying to commit
239 manifest1: manifest of changeset first parent
239 manifest1: manifest of changeset first parent
240 manifest2: manifest of changeset second parent
240 manifest2: manifest of changeset second parent
241 linkrev: revision number of the changeset being created
241 linkrev: revision number of the changeset being created
242 tr: current transation
242 tr: current transation
243 individual: boolean, set to False to skip storing the copy data
243 individual: boolean, set to False to skip storing the copy data
244 (only used by the Google specific feature of using
244 (only used by the Google specific feature of using
245 changeset extra as copy source of truth).
245 changeset extra as copy source of truth).
246
246
247 output: (filenode, touched)
247 output: (filenode, touched)
248
248
249 filenode: the filenode that should be used by this changeset
249 filenode: the filenode that should be used by this changeset
250 touched: one of: None (mean untouched), 'added' or 'modified'
250 touched: one of: None (mean untouched), 'added' or 'modified'
251 """
251 """
252
252
253 fname = fctx.path()
253 fname = fctx.path()
254 fparent1 = manifest1.get(fname, nullid)
254 fparent1 = manifest1.get(fname, nullid)
255 fparent2 = manifest2.get(fname, nullid)
255 fparent2 = manifest2.get(fname, nullid)
256 touched = None
256 touched = None
257 if fparent1 == fparent2 == nullid:
257 if fparent1 == fparent2 == nullid:
258 touched = 'added'
258 touched = 'added'
259
259
260 if isinstance(fctx, context.filectx):
260 if isinstance(fctx, context.filectx):
261 # This block fast path most comparisons which are usually done. It
261 # This block fast path most comparisons which are usually done. It
262 # assumes that bare filectx is used and no merge happened, hence no
262 # assumes that bare filectx is used and no merge happened, hence no
263 # need to create a new file revision in this case.
263 # need to create a new file revision in this case.
264 node = fctx.filenode()
264 node = fctx.filenode()
265 if node in [fparent1, fparent2]:
265 if node in [fparent1, fparent2]:
266 repo.ui.debug(b'reusing %s filelog entry\n' % fname)
266 repo.ui.debug(b'reusing %s filelog entry\n' % fname)
267 if (
267 if (
268 fparent1 != nullid and manifest1.flags(fname) != fctx.flags()
268 fparent1 != nullid and manifest1.flags(fname) != fctx.flags()
269 ) or (
269 ) or (
270 fparent2 != nullid and manifest2.flags(fname) != fctx.flags()
270 fparent2 != nullid and manifest2.flags(fname) != fctx.flags()
271 ):
271 ):
272 touched = 'modified'
272 touched = 'modified'
273 return node, touched
273 return node, touched
274
274
275 flog = repo.file(fname)
275 flog = repo.file(fname)
276 meta = {}
276 meta = {}
277 cfname = fctx.copysource()
277 cfname = fctx.copysource()
278 fnode = None
278 fnode = None
279
279
280 if cfname and cfname != fname:
280 if cfname and cfname != fname:
281 # Mark the new revision of this file as a copy of another
281 # Mark the new revision of this file as a copy of another
282 # file. This copy data will effectively act as a parent
282 # file. This copy data will effectively act as a parent
283 # of this new revision. If this is a merge, the first
283 # of this new revision. If this is a merge, the first
284 # parent will be the nullid (meaning "look up the copy data")
284 # parent will be the nullid (meaning "look up the copy data")
285 # and the second one will be the other parent. For example:
285 # and the second one will be the other parent. For example:
286 #
286 #
287 # 0 --- 1 --- 3 rev1 changes file foo
287 # 0 --- 1 --- 3 rev1 changes file foo
288 # \ / rev2 renames foo to bar and changes it
288 # \ / rev2 renames foo to bar and changes it
289 # \- 2 -/ rev3 should have bar with all changes and
289 # \- 2 -/ rev3 should have bar with all changes and
290 # should record that bar descends from
290 # should record that bar descends from
291 # bar in rev2 and foo in rev1
291 # bar in rev2 and foo in rev1
292 #
292 #
293 # this allows this merge to succeed:
293 # this allows this merge to succeed:
294 #
294 #
295 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
295 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
296 # \ / merging rev3 and rev4 should use bar@rev2
296 # \ / merging rev3 and rev4 should use bar@rev2
297 # \- 2 --- 4 as the merge base
297 # \- 2 --- 4 as the merge base
298 #
298 #
299
299
300 cnode = manifest1.get(cfname)
300 cnode = manifest1.get(cfname)
301 newfparent = fparent2
301 newfparent = fparent2
302
302
303 if manifest2: # branch merge
303 if manifest2: # branch merge
304 if fparent2 == nullid or cnode is None: # copied on remote side
304 if fparent2 == nullid or cnode is None: # copied on remote side
305 if cfname in manifest2:
305 if cfname in manifest2:
306 cnode = manifest2[cfname]
306 cnode = manifest2[cfname]
307 newfparent = fparent1
307 newfparent = fparent1
308
308
309 # Here, we used to search backwards through history to try to find
309 # Here, we used to search backwards through history to try to find
310 # where the file copy came from if the source of a copy was not in
310 # where the file copy came from if the source of a copy was not in
311 # the parent directory. However, this doesn't actually make sense to
311 # the parent directory. However, this doesn't actually make sense to
312 # do (what does a copy from something not in your working copy even
312 # do (what does a copy from something not in your working copy even
313 # mean?) and it causes bugs (eg, issue4476). Instead, we will warn
313 # mean?) and it causes bugs (eg, issue4476). Instead, we will warn
314 # the user that copy information was dropped, so if they didn't
314 # the user that copy information was dropped, so if they didn't
315 # expect this outcome it can be fixed, but this is the correct
315 # expect this outcome it can be fixed, but this is the correct
316 # behavior in this circumstance.
316 # behavior in this circumstance.
317
317
318 if cnode:
318 if cnode:
319 repo.ui.debug(b" %s: copy %s:%s\n" % (fname, cfname, hex(cnode)))
319 repo.ui.debug(b" %s: copy %s:%s\n" % (fname, cfname, hex(cnode)))
320 if includecopymeta:
320 if includecopymeta:
321 meta[b"copy"] = cfname
321 meta[b"copy"] = cfname
322 meta[b"copyrev"] = hex(cnode)
322 meta[b"copyrev"] = hex(cnode)
323 fparent1, fparent2 = nullid, newfparent
323 fparent1, fparent2 = nullid, newfparent
324 else:
324 else:
325 repo.ui.warn(
325 repo.ui.warn(
326 _(
326 _(
327 b"warning: can't find ancestor for '%s' "
327 b"warning: can't find ancestor for '%s' "
328 b"copied from '%s'!\n"
328 b"copied from '%s'!\n"
329 )
329 )
330 % (fname, cfname)
330 % (fname, cfname)
331 )
331 )
332
332
333 elif fparent1 == nullid:
333 elif fparent1 == nullid:
334 fparent1, fparent2 = fparent2, nullid
334 fparent1, fparent2 = fparent2, nullid
335 elif fparent2 != nullid:
335 elif fparent2 != nullid:
336 # is one parent an ancestor of the other?
336 # is one parent an ancestor of the other?
337 fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
337 fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
338 if fparent1 in fparentancestors:
338 if fparent1 in fparentancestors:
339 fparent1, fparent2 = fparent2, nullid
339 fparent1, fparent2 = fparent2, nullid
340 elif fparent2 in fparentancestors:
340 elif fparent2 in fparentancestors:
341 fparent2 = nullid
341 fparent2 = nullid
342 elif not fparentancestors:
342 elif not fparentancestors:
343 # TODO: this whole if-else might be simplified much more
343 # TODO: this whole if-else might be simplified much more
344 ms = mergestate.mergestate.read(repo)
344 ms = mergestate.mergestate.read(repo)
345 if (
345 if (
346 fname in ms
346 fname in ms
347 and ms[fname] == mergestate.MERGE_RECORD_MERGED_OTHER
347 and ms[fname] == mergestate.MERGE_RECORD_MERGED_OTHER
348 ):
348 ):
349 fparent1, fparent2 = fparent2, nullid
349 fparent1, fparent2 = fparent2, nullid
350
350
351 # is the file changed?
351 # is the file changed?
352 text = fctx.data()
352 text = fctx.data()
353 if fparent2 != nullid or meta or flog.cmp(fparent1, text):
353 if fparent2 != nullid or meta or flog.cmp(fparent1, text):
354 if touched is None: # do not overwrite added
354 if touched is None: # do not overwrite added
355 touched = 'modified'
355 touched = 'modified'
356 fnode = flog.add(text, meta, tr, linkrev, fparent1, fparent2)
356 fnode = flog.add(text, meta, tr, linkrev, fparent1, fparent2)
357 # are just the flags changed during merge?
357 # are just the flags changed during merge?
358 elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
358 elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
359 touched = 'modified'
359 touched = 'modified'
360 fnode = fparent1
360 fnode = fparent1
361 else:
361 else:
362 fnode = fparent1
362 fnode = fparent1
363 return fnode, touched
363 return fnode, touched
364
364
365
365
366 def _commit_manifest(tr, linkrev, ctx, mctx, manifest, files, added, drop):
366 def _commit_manifest(tr, linkrev, ctx, mctx, manifest, files, added, drop):
367 """make a new manifest entry (or reuse a new one)
367 """make a new manifest entry (or reuse a new one)
368
368
369 given an initialised manifest context and precomputed list of
369 given an initialised manifest context and precomputed list of
370 - files: files affected by the commit
370 - files: files affected by the commit
371 - added: new entries in the manifest
371 - added: new entries in the manifest
372 - drop: entries present in parents but absent of this one
372 - drop: entries present in parents but absent of this one
373
373
374 Create a new manifest revision, reuse existing ones if possible.
374 Create a new manifest revision, reuse existing ones if possible.
375
375
376 Return the nodeid of the manifest revision.
376 Return the nodeid of the manifest revision.
377 """
377 """
378 repo = ctx.repo()
378 repo = ctx.repo()
379
379
380 md = None
380 md = None
381
381
382 # all this is cached, so it is find to get them all from the ctx.
382 # all this is cached, so it is find to get them all from the ctx.
383 p1 = ctx.p1()
383 p1 = ctx.p1()
384 p2 = ctx.p2()
384 p2 = ctx.p2()
385 m1ctx = p1.manifestctx()
385 m1ctx = p1.manifestctx()
386
386
387 m1 = m1ctx.read()
387 m1 = m1ctx.read()
388
388
389 if not files:
389 if not files:
390 # if no "files" actually changed in terms of the changelog,
390 # if no "files" actually changed in terms of the changelog,
391 # try hard to detect unmodified manifest entry so that the
391 # try hard to detect unmodified manifest entry so that the
392 # exact same commit can be reproduced later on convert.
392 # exact same commit can be reproduced later on convert.
393 md = m1.diff(manifest, scmutil.matchfiles(repo, ctx.files()))
393 md = m1.diff(manifest, scmutil.matchfiles(repo, ctx.files()))
394 if not files and md:
394 if not files and md:
395 repo.ui.debug(
395 repo.ui.debug(
396 b'not reusing manifest (no file change in '
396 b'not reusing manifest (no file change in '
397 b'changelog, but manifest differs)\n'
397 b'changelog, but manifest differs)\n'
398 )
398 )
399 if files or md:
399 if files or md:
400 repo.ui.note(_(b"committing manifest\n"))
400 repo.ui.note(_(b"committing manifest\n"))
401 # we're using narrowmatch here since it's already applied at
401 # we're using narrowmatch here since it's already applied at
402 # other stages (such as dirstate.walk), so we're already
402 # other stages (such as dirstate.walk), so we're already
403 # ignoring things outside of narrowspec in most cases. The
403 # ignoring things outside of narrowspec in most cases. The
404 # one case where we might have files outside the narrowspec
404 # one case where we might have files outside the narrowspec
405 # at this point is merges, and we already error out in the
405 # at this point is merges, and we already error out in the
406 # case where the merge has files outside of the narrowspec,
406 # case where the merge has files outside of the narrowspec,
407 # so this is safe.
407 # so this is safe.
408 mn = mctx.write(
408 mn = mctx.write(
409 tr,
409 tr,
410 linkrev,
410 linkrev,
411 p1.manifestnode(),
411 p1.manifestnode(),
412 p2.manifestnode(),
412 p2.manifestnode(),
413 added,
413 added,
414 drop,
414 drop,
415 match=repo.narrowmatch(),
415 match=repo.narrowmatch(),
416 )
416 )
417 else:
417 else:
418 repo.ui.debug(
418 repo.ui.debug(
419 b'reusing manifest from p1 (listed files ' b'actually unchanged)\n'
419 b'reusing manifest from p1 (listed files ' b'actually unchanged)\n'
420 )
420 )
421 mn = p1.manifestnode()
421 mn = p1.manifestnode()
422
422
423 return mn
423 return mn
424
424
425
425
426 def _extra_with_copies(
426 def _extra_with_copies(
427 repo, extra, files, p1copies, p2copies, filesadded, filesremoved
427 repo, extra, files, p1copies, p2copies, filesadded, filesremoved
428 ):
428 ):
429 """encode copy information into a `extra` dictionnary"""
429 """encode copy information into a `extra` dictionnary"""
430 extrasentries = p1copies, p2copies, filesadded, filesremoved
430 extrasentries = p1copies, p2copies, filesadded, filesremoved
431 if extra is None and any(x is not None for x in extrasentries):
431 if extra is None and any(x is not None for x in extrasentries):
432 extra = {}
432 extra = {}
433 if p1copies is not None:
433 if p1copies is not None:
434 p1copies = metadata.encodecopies(files, p1copies)
434 p1copies = metadata.encodecopies(files, p1copies)
435 extra[b'p1copies'] = p1copies
435 extra[b'p1copies'] = p1copies
436 if p2copies is not None:
436 if p2copies is not None:
437 p2copies = metadata.encodecopies(files, p2copies)
437 p2copies = metadata.encodecopies(files, p2copies)
438 extra[b'p2copies'] = p2copies
438 extra[b'p2copies'] = p2copies
439 if filesadded is not None:
439 if filesadded is not None:
440 filesadded = metadata.encodefileindices(files, filesadded)
440 filesadded = metadata.encodefileindices(files, filesadded)
441 extra[b'filesadded'] = filesadded
441 extra[b'filesadded'] = filesadded
442 if filesremoved is not None:
442 if filesremoved is not None:
443 filesremoved = metadata.encodefileindices(files, filesremoved)
443 filesremoved = metadata.encodefileindices(files, filesremoved)
444 extra[b'filesremoved'] = filesremoved
444 extra[b'filesremoved'] = filesremoved
445 return extra
445 return extra
General Comments 0
You need to be logged in to leave comments. Login now