# HG changeset patch # User Kyle Lippincott # Date 2019-11-27 00:10:21 # Node ID 5558e3437872ea4bb2fa8368f62003fcd7753230 # Parent 32d11a23c9cf124c5b7dc722e4c068d15ce8a4ac amend: check for file modifications when updating dirstate (issue6233) Previously, we called dirstate.normal(f), which would put information into the dirstate claiming that the file on disk is what it "should be" for the current checkout, and it would have the size and timestamp of the most recent modification to the file (which is not necessarily the one we just committed). If the file was modified while the commit message editor was open, we would put incorrect information into the dirstate. Differential Revision: https://phab.mercurial-scm.org/D7521 diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -3054,11 +3054,13 @@ def amend(ui, repo, old, extra, pats, op # selectively update the dirstate only for the amended files. dirstate = repo.dirstate - # Update the state of the files which were added and - # and modified in the amend to "normal" in the dirstate. + # Update the state of the files which were added and modified in the + # amend to "normal" in the dirstate. We need to use "normallookup" since + # the files may have changed since the command started; using "normal" + # would mark them as clean but with uncommitted contents. normalfiles = set(wctx.modified() + wctx.added()) & filestoamend for f in normalfiles: - dirstate.normal(f) + dirstate.normallookup(f) # Update the state of files which were removed in the amend # to "removed" in the dirstate. diff --git a/tests/test-amend.t b/tests/test-amend.t --- a/tests/test-amend.t +++ b/tests/test-amend.t @@ -476,3 +476,33 @@ hg used to include the changes to `a` an a | 2 +- b | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) + +Modifying a file while the editor is open can cause dirstate corruption +(issue6233) + + $ cd $TESTTMP + $ hg init modify-during-amend; cd modify-during-amend + $ echo r0 > foo; hg commit -qAm "r0" + $ echo alpha > foo; hg commit -qm "alpha" + $ echo beta >> foo + $ cat > $TESTTMP/sleepy_editor.sh < echo hi > "\$1" + > sleep 3 + > EOF + $ HGEDITOR="sh $TESTTMP/sleepy_editor.sh" hg commit --amend & + $ sleep 1 + $ echo delta >> foo + $ sleep 3 + $ if (hg diff -c . | grep 'delta' >/dev/null) || [[ -n "$(hg status)" ]]; then + > echo "OK." + > else + > echo "Bug detected. 'delta' is not part of the commit OR the wdir" + > echo "Diff and status before rebuild:" + > hg diff + > hg status + > hg debugrebuilddirstate + > echo "Diff and status after rebuild:" + > hg diff + > hg status + > fi + OK.