# HG changeset patch # User Mark Thomas # Date 2017-10-02 21:05:30 # Node ID 33c8a68371810f06ebcee3d84efcc7520f37f7b1 # Parent 1609a5afc4f52e840da6f693773d608ae5fc78f0 merge: check for path conflicts when updating (issue5628) When updating to a new revision, check for path conflicts caused by unknown files in the working directory, and handle these by backing up the file or directory and replacing it. Differential Revision: https://phab.mercurial-scm.org/D781 diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -676,6 +676,7 @@ def _checkunknownfiles(repo, wctx, mctx, choose a different action. """ fileconflicts = set() + pathconflicts = set() warnconflicts = set() abortconflicts = set() unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown') @@ -691,11 +692,15 @@ def _checkunknownfiles(repo, wctx, mctx, if m in ('c', 'dc'): if _checkunknownfile(repo, wctx, mctx, f): fileconflicts.add(f) + elif f not in wctx: + path = _checkunknowndirs(repo, f) + if path is not None: + pathconflicts.add(path) elif m == 'dg': if _checkunknownfile(repo, wctx, mctx, f, args[0]): fileconflicts.add(f) - allconflicts = fileconflicts + allconflicts = fileconflicts | pathconflicts ignoredconflicts = set([c for c in allconflicts if repo.dirstate._ignore(c)]) unknownconflicts = allconflicts - ignoredconflicts @@ -745,8 +750,9 @@ def _checkunknownfiles(repo, wctx, mctx, repo.ui.warn(_("%s: replacing untracked file\n") % f) for f, (m, args, msg) in actions.iteritems(): - backup = f in fileconflicts if m == 'c': + backup = (f in fileconflicts or f in pathconflicts or + any(p in pathconflicts for p in util.finddirs(f))) flags, = args actions[f] = ('g', (flags, backup), msg) diff --git a/tests/test-merge1.t b/tests/test-merge1.t --- a/tests/test-merge1.t +++ b/tests/test-merge1.t @@ -30,17 +30,17 @@ of the files in a commit we're updating $ mkdir b && touch b/nonempty $ hg up - abort: *: '$TESTTMP/t/b' (glob) + b: untracked file differs + abort: untracked files in working directory differ from files in requested revision [255] $ hg ci - abort: last update was interrupted - (use 'hg update' to get a consistent checkout) - [255] + nothing changed + [1] $ hg sum parent: 0:538afb845929 commit #0 branch: default - commit: 1 unknown (interrupted update) + commit: 1 unknown (clean) update: 1 new changesets (update) phases: 2 draft $ rm b/nonempty diff --git a/tests/test-pathconflicts-basic.t b/tests/test-pathconflicts-basic.t --- a/tests/test-pathconflicts-basic.t +++ b/tests/test-pathconflicts-basic.t @@ -37,7 +37,8 @@ Basic update - local directory conflicts $ mkdir a $ echo 3 > a/b $ hg up file - abort: *: '$TESTTMP/repo/a' (glob) + a: untracked file differs + abort: untracked files in working directory differ from files in requested revision [255] $ hg up --clean file abort: *: '$TESTTMP/repo/a' (glob) @@ -53,13 +54,9 @@ Basic update - untracked file conflicts $ hg up -q 0 $ echo untracked > a $ hg up --config merge.checkunknown=warn dir - abort: *: '$TESTTMP/repo/a/b' (glob) - [255] - -Repo is in a very bad state now - recover manually - - $ rm -f a - $ hg up -q --clean 0 + a: replacing untracked file + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + (activating bookmark dir) Basic clean update - local directory conflicts with changed remote file diff --git a/tests/test-update-names.t b/tests/test-update-names.t --- a/tests/test-update-names.t +++ b/tests/test-update-names.t @@ -50,7 +50,8 @@ make sure that this does not erase untra $ hg st ? name/file $ hg up 1 - abort: *: '$TESTTMP/r1/r2/name' (glob) + name: untracked file differs + abort: untracked files in working directory differ from files in requested revision [255] $ cd ..