Bug 5962 - hg update inconsistencies when untracked/ignored files are in the way
Summary: hg update inconsistencies when untracked/ignored files are in the way
Status: RESOLVED FIXED
Alias: None
Product: Mercurial
Classification: Unclassified
Component: Mercurial (show other bugs)
Version: 4.6
Hardware: PC Linux
: urgent bug
Assignee: Bugzilla
URL:
Keywords: regression
Depends on:
Blocks:
 
Reported: 2018-08-16 14:26 UTC by vgatien-baron
Modified: 2018-08-24 17:17 UTC (History)
2 users (show)

See Also:
Python Version: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description vgatien-baron 2018-08-16 14:26 UTC
The documented behavior of hg update is: when hg update needs to write a file, but there's already untracked/ignored file by that name, it complains (assuming the contents are not the same).
This is controlled by the config options merge.checkignored and merge.checkunknown.

Unrelatedly, until 4.3 inclusive, hg update would always fail when there's a directory at a path where the destination has a tracked file. 4.4 contains some changes to improve this, which AFAICT, are not documented at a high level (need to look at commit messages), so it's hard to understand what behavior is intended.

Now the problem: the observed behavior since 4.4 is that hg deletes untracked and ignored files with no backup, in the cases where hg update used to fail, so no respect for the merge.check* config options.

I don't care so much about the ignored files, but deleting untracked files seems pretty bad. And I worry that even the behavior on ignored files is subject to change (if someone that does care reports this) because it's not really the documented behavior.

There's also some weirdness where one use of hg update used to break, then deleted files, then starting breaking again.

I made the test below to show concretely the behavior I'm talking about.

Ideally, hg update's should retain its ability to work in the face of these file/dir issue (this has caused much pain), but either the current behavior would get documented if it is in fact intended, or perhaps the way to avoid these update failures should change (rename directories that get in the way with a .conflict-with-tracked suffix?).



  $ hg init r
  $ cd r
  $ cat > .hgignore <<EOF
  > syntax: glob
  > *.orig
  > *.ignored
  > EOF
  $ hg commit -A -m0 -q
  $ echo a > a
  $ echo a.ignored > a.ignored
  $ hg add a.ignored
  $ hg commit -A -m1 -q
  $ hg rm a; mkdir a; echo a/something > a/something
  $ hg commit -A -m2 -q
  $ hg up -r 0 -q
  $ cd ..
  $ show () {
  >   hg st -A | grep -v hgignore
  >   echo -
  >   hg st -A -n | grep -v hgignore | xargs -r grep -H ''
  > }

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
GOOD untracked file -> tracked file conflict
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  $ hg clone -q r r2 -u 0 && cd r2
  $ echo important-stuff > a
  $ hg up -q 1
  a: untracked file differs
  abort: untracked files in working directory differ from files in requested revision
  [255]
  $ show
  ? a
  -
  a:important-stuff
  $ cd ../ && rm -rf r2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
GOOD ignored file -> tracked file conflict
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  $ hg clone -q r r2 -u 0 && cd r2
  $ echo important-stuff > a.ignored
  $ hg up -q -r 1
  a.ignored: untracked file differs
  abort: untracked files in working directory differ from files in requested revision
  [255]
  $ show
  I a.ignored
  -
  a.ignored:important-stuff
  $ cd ../ && rm -rf r2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
BEHAVIOR KEEPS CHANGING untracked file -> tracked dir conflict
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# 4.7 4.6.2 4.3.2
  $ hg clone -q r r2 -u 0 && cd r2
  $ echo important-stuff > a
  $ hg up -q 2
  abort: $ENOTDIR$: '$TESTTMP/r2/a/something'
  [255]
  $ show
  ? a
  I a.ignored
  -
  a:important-stuff
  a.ignored:a.ignored
  $ cd ../ && rm -rf r2

# # 4.5.2 4.4.2
#   $ hg clone -q r r2 -u 0 && cd r2
#   $ echo important-stuff > a
#   $ hg up -q 2
#   $ show
#   C a.ignored
#   C a/something
#   -
#   a.ignored:a.ignored
#   a/something:a/something
#   $ cd ../ && rm -rf r2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DELETE FILE WITH NO BACKUP untracked file in dir -> dir is replaced by file
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  $ hg clone -q r r2 -u 2 && cd r2
  $ echo important-stuff > a/untracked
  $ hg up -r 1
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  $ show
  C a
  C a.ignored
  -
  a:a
  a.ignored:a.ignored
  $ cd ../ && rm -rf r2

# # 4.3.2
#   $ hg clone -q r r2 -u 2 && cd r2
#   $ echo important-stuff > a/untracked
#   $ hg up -r 1
#   abort: Directory not empty: '$TESTTMP/r2/a'
#   [255]
#   $ show
#   ! a/something
#   ? a/untracked
#   C a.ignored
#   -
#   grep: a/something: No such file or directory
#   a/untracked:important-stuff
#   a.ignored:a.ignored
#   [123]
#   $ cd ../ && rm -rf r2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DELETE FILE WITH NO BACKUP ignored file in dir -> dir is replaced by file
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  $ hg clone -q r r2 -u 2 && cd r2
  $ echo important-stuff > a/bla.ignored
  $ hg up -r 1
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  $ show
  C a
  C a.ignored
  -
  a:a
  a.ignored:a.ignored
  $ cd ../ && rm -rf r2

# # 4.3.2
#   $ hg clone -q r r2 -u 2 && cd r2
#   $ echo important-stuff > a/bla.ignored
#   $ hg up -r 1
#   abort: Directory not empty: '$TESTTMP/r2/a'
#   [255]
#   $ show
#   ! a/something
#   I a/bla.ignored
#   C a.ignored
#   -
#   grep: a/something: No such file or directory
#   a/bla.ignored:important-stuff
#   a.ignored:a.ignored
#   [123]
#   $ cd ../ && rm -rf r2
Comment 1 Yuya Nishihara 2018-08-18 21:29 UTC
Bisected for this particular case between 4.3 and 4.4, which says the first
bad revision is:
2a774cae3a03 "merge: disable path conflict checking by default (issue5716)"

  $ hg clone -q r r2 -u 2 && cd r2
  $ echo important-stuff > a/untracked
  $ hg up -r 1 2>/dev/null
  [255]
  $ cat a/untracked
  important-stuff

Perhaps, some part of new path conflict handling is *enabled* without the
safety check disabled by default.
Comment 2 HG Bot 2018-08-22 12:50 UTC
Fixed by https://mercurial-scm.org/repo/hg/rev/8c6775e812d8
Yuya Nishihara <yuya@tcha.org>
merge: do not delete untracked files silently (issue5962)

37450a122128, 2a774cae3a03, and 656ac240f392 weren't enough to prevent data
loss. No unknown "files" weren't deleted before 7a8a16f8ea22, "context: also
consider path conflicts when clearing unknown files."

(please test the fix)
Comment 3 vgatien-baron 2018-08-22 17:48 UTC
Thanks, the behavior seems to be consistent now (though I wished one could update past file/directory conflict).
Comment 4 Yuya Nishihara 2018-08-23 08:54 UTC
> wished one could update past file/directory conflict

Perhaps that can be achieved by experimental.merge.checkpathconflicts=1?

Maybe we should move this option to [merge] and make it documented.
Comment 5 vgatien-baron 2018-08-24 17:17 UTC
I tried the test above with experimental.merge.checkpathconflicts=1, and it doesn't seem to help (hg update still aborts in the last two cases, though with a different error), even with merge.checkignored=ignore.