--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/commit.py Mon Jul 06 23:14:52 2020 +0200
@@ -0,0 +1,215 @@
+# commit.py - fonction to perform commit
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+import errno
+import weakref
+
+from .i18n import _
+from .node import (
+ hex,
+ nullrev,
+)
+
+from . import (
+ metadata,
+ phases,
+ scmutil,
+ subrepoutil,
+)
+
+
+def commitctx(repo, ctx, error=False, origctx=None):
+ """Add a new revision to the target repository.
+ Revision information is passed via the context argument.
+
+ ctx.files() should list all files involved in this commit, i.e.
+ modified/added/removed files. On merge, it may be wider than the
+ ctx.files() to be committed, since any file nodes derived directly
+ from p1 or p2 are excluded from the committed ctx.files().
+
+ origctx is for convert to work around the problem that bug
+ fixes to the files list in changesets change hashes. For
+ convert to be the identity, it can pass an origctx and this
+ function will use the same files list when it makes sense to
+ do so.
+ """
+ repo = repo.unfiltered()
+
+ p1, p2 = ctx.p1(), ctx.p2()
+ user = ctx.user()
+
+ if repo.filecopiesmode == b'changeset-sidedata':
+ writechangesetcopy = True
+ writefilecopymeta = True
+ writecopiesto = None
+ else:
+ writecopiesto = repo.ui.config(b'experimental', b'copies.write-to')
+ writefilecopymeta = writecopiesto != b'changeset-only'
+ writechangesetcopy = writecopiesto in (
+ b'changeset-only',
+ b'compatibility',
+ )
+ p1copies, p2copies = None, None
+ if writechangesetcopy:
+ p1copies = ctx.p1copies()
+ p2copies = ctx.p2copies()
+ filesadded, filesremoved = None, None
+ with repo.lock(), repo.transaction(b"commit") as tr:
+ trp = weakref.proxy(tr)
+
+ if ctx.manifestnode():
+ # reuse an existing manifest revision
+ repo.ui.debug(b'reusing known manifest\n')
+ mn = ctx.manifestnode()
+ files = ctx.files()
+ if writechangesetcopy:
+ filesadded = ctx.filesadded()
+ filesremoved = ctx.filesremoved()
+ elif not ctx.files():
+ repo.ui.debug(b'reusing manifest from p1 (no file change)\n')
+ mn = p1.manifestnode()
+ files = []
+ else:
+ m1ctx = p1.manifestctx()
+ m2ctx = p2.manifestctx()
+ mctx = m1ctx.copy()
+
+ m = mctx.read()
+ m1 = m1ctx.read()
+ m2 = m2ctx.read()
+
+ # check in files
+ added = []
+ filesadded = []
+ removed = list(ctx.removed())
+ touched = []
+ linkrev = len(repo)
+ repo.ui.note(_(b"committing files:\n"))
+ uipathfn = scmutil.getuipathfn(repo)
+ for f in sorted(ctx.modified() + ctx.added()):
+ repo.ui.note(uipathfn(f) + b"\n")
+ try:
+ fctx = ctx[f]
+ if fctx is None:
+ removed.append(f)
+ else:
+ added.append(f)
+ m[f], is_touched = repo._filecommit(
+ fctx, m1, m2, linkrev, trp, writefilecopymeta,
+ )
+ if is_touched:
+ touched.append(f)
+ if writechangesetcopy and is_touched == 'added':
+ filesadded.append(f)
+ m.setflag(f, fctx.flags())
+ except OSError:
+ repo.ui.warn(_(b"trouble committing %s!\n") % uipathfn(f))
+ raise
+ except IOError as inst:
+ errcode = getattr(inst, 'errno', errno.ENOENT)
+ if error or errcode and errcode != errno.ENOENT:
+ repo.ui.warn(
+ _(b"trouble committing %s!\n") % uipathfn(f)
+ )
+ raise
+
+ # update manifest
+ removed = [f for f in removed if f in m1 or f in m2]
+ drop = sorted([f for f in removed if f in m])
+ for f in drop:
+ del m[f]
+ if p2.rev() != nullrev:
+ rf = metadata.get_removal_filter(ctx, (p1, p2, m1, m2))
+ removed = [f for f in removed if not rf(f)]
+
+ touched.extend(removed)
+
+ if writechangesetcopy:
+ filesremoved = removed
+
+ files = touched
+ md = None
+ if not files:
+ # if no "files" actually changed in terms of the changelog,
+ # try hard to detect unmodified manifest entry so that the
+ # exact same commit can be reproduced later on convert.
+ md = m1.diff(m, scmutil.matchfiles(repo, ctx.files()))
+ if not files and md:
+ repo.ui.debug(
+ b'not reusing manifest (no file change in '
+ b'changelog, but manifest differs)\n'
+ )
+ if files or md:
+ repo.ui.note(_(b"committing manifest\n"))
+ # we're using narrowmatch here since it's already applied at
+ # other stages (such as dirstate.walk), so we're already
+ # ignoring things outside of narrowspec in most cases. The
+ # one case where we might have files outside the narrowspec
+ # at this point is merges, and we already error out in the
+ # case where the merge has files outside of the narrowspec,
+ # so this is safe.
+ mn = mctx.write(
+ trp,
+ linkrev,
+ p1.manifestnode(),
+ p2.manifestnode(),
+ added,
+ drop,
+ match=repo.narrowmatch(),
+ )
+ else:
+ repo.ui.debug(
+ b'reusing manifest from p1 (listed files '
+ b'actually unchanged)\n'
+ )
+ mn = p1.manifestnode()
+
+ if writecopiesto == b'changeset-only':
+ # If writing only to changeset extras, use None to indicate that
+ # no entry should be written. If writing to both, write an empty
+ # entry to prevent the reader from falling back to reading
+ # filelogs.
+ p1copies = p1copies or None
+ p2copies = p2copies or None
+ filesadded = filesadded or None
+ filesremoved = filesremoved or None
+
+ if origctx and origctx.manifestnode() == mn:
+ files = origctx.files()
+
+ # update changelog
+ repo.ui.note(_(b"committing changelog\n"))
+ repo.changelog.delayupdate(tr)
+ n = repo.changelog.add(
+ mn,
+ files,
+ ctx.description(),
+ trp,
+ p1.node(),
+ p2.node(),
+ user,
+ ctx.date(),
+ ctx.extra().copy(),
+ p1copies,
+ p2copies,
+ filesadded,
+ filesremoved,
+ )
+ xp1, xp2 = p1.hex(), p2 and p2.hex() or b''
+ repo.hook(
+ b'pretxncommit', throw=True, node=hex(n), parent1=xp1, parent2=xp2,
+ )
+ # set the new commit is proper phase
+ targetphase = subrepoutil.newcommitphase(repo.ui, ctx)
+ if targetphase:
+ # retract boundary do not alter parent changeset.
+ # if a parent have higher the resulting phase will
+ # be compliant anyway
+ #
+ # if minimal phase was 0 we don't need to retract anything
+ phases.registernew(repo, tr, targetphase, [n])
+ return n