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