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