Mercurial > hg
diff mercurial/commit.py @ 48716:f1eb77dceb36
narrow: allow merging non-conflicting change outside of the narrow spec
We use the mergestate to carry information about these merge action and
reprocess them at commit time to apply the necessary update.
The dirstate itself is never affected and remains "pure", with content only in
the narrow-spec. This file involved in such merge are therefor not listed in `hg
status`.
The current testing is based on a modification of the previous testing, that
refused to do such merges. As a result it is a bit simple and more extensive
code and testing testing will have to be introduced later. I am planning to do
this extra testing, soon.
In addition, this only works for flat manifest. Support for tree manifest will
need more work. I am not currently planning to do this work.
Differential Revision: https://phab.mercurial-scm.org/D12119
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Thu, 03 Feb 2022 18:14:11 +0100 |
parents | 5b9de38a0356 |
children | 18e69f224e4b |
line wrap: on
line diff
--- a/mercurial/commit.py Sun Jan 30 06:01:42 2022 +0100 +++ b/mercurial/commit.py Thu Feb 03 18:14:11 2022 +0100 @@ -134,7 +134,13 @@ for s in salvaged: files.mark_salvaged(s) - if ctx.manifestnode(): + narrow_files = {} + if not ctx.repo().narrowmatch().always(): + for f, e in ms.allextras().items(): + action = e.get(b'outside-narrow-merge-action') + if action is not None: + narrow_files[f] = action + if ctx.manifestnode() and not narrow_files: # reuse an existing manifest revision repo.ui.debug(b'reusing known manifest\n') mn = ctx.manifestnode() @@ -142,11 +148,11 @@ if writechangesetcopy: files.update_added(ctx.filesadded()) files.update_removed(ctx.filesremoved()) - elif not ctx.files(): + elif not ctx.files() and not narrow_files: repo.ui.debug(b'reusing manifest from p1 (no file change)\n') mn = p1.manifestnode() else: - mn = _process_files(tr, ctx, ms, files, error=error) + mn = _process_files(tr, ctx, ms, files, narrow_files, error=error) if origctx and origctx.manifestnode() == mn: origfiles = origctx.files() @@ -177,7 +183,7 @@ return salvaged -def _process_files(tr, ctx, ms, files, error=False): +def _process_files(tr, ctx, ms, files, narrow_files=None, error=False): repo = ctx.repo() p1 = ctx.p1() p2 = ctx.p2() @@ -198,8 +204,24 @@ linkrev = len(repo) repo.ui.note(_(b"committing files:\n")) uipathfn = scmutil.getuipathfn(repo) - for f in sorted(ctx.modified() + ctx.added()): + all_files = ctx.modified() + ctx.added() + all_files.extend(narrow_files.keys()) + all_files.sort() + for f in all_files: repo.ui.note(uipathfn(f) + b"\n") + if f in narrow_files: + narrow_action = narrow_files.get(f) + if narrow_action == mergestate.CHANGE_MODIFIED: + files.mark_touched(f) + added.append(f) + m[f] = m2[f] + flags = m2ctx.find(f)[1] or b'' + m.setflag(f, flags) + else: + msg = _(b"corrupted mergestate, unknown narrow action: %b") + hint = _(b"restart the merge") + raise error.Abort(msg, hint=hint) + continue try: fctx = ctx[f] if fctx is None: @@ -239,7 +261,17 @@ if not rf(f): files.mark_removed(f) - mn = _commit_manifest(tr, linkrev, ctx, mctx, m, files.touched, added, drop) + mn = _commit_manifest( + tr, + linkrev, + ctx, + mctx, + m, + files.touched, + added, + drop, + bool(narrow_files), + ) return mn @@ -409,7 +441,17 @@ return fnode, touched -def _commit_manifest(tr, linkrev, ctx, mctx, manifest, files, added, drop): +def _commit_manifest( + tr, + linkrev, + ctx, + mctx, + manifest, + files, + added, + drop, + has_some_narrow_action=False, +): """make a new manifest entry (or reuse a new one) given an initialised manifest context and precomputed list of @@ -451,6 +493,10 @@ # 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. + if has_some_narrow_action: + match = None + else: + match = repo.narrowmatch() mn = mctx.write( tr, linkrev, @@ -458,7 +504,7 @@ p2.manifestnode(), added, drop, - match=repo.narrowmatch(), + match=match, ) else: repo.ui.debug(