Patchwork [3,of,3] commit: try hard to reuse p1 manifest if nothing changed

login
register
mail settings
Submitter Yuya Nishihara
Date Aug. 15, 2018, 12:47 a.m.
Message ID <ed903661203305cb8c0d.1534294068@mimosa>
Download mbox | patch
Permalink /patch/33731/
State Accepted
Headers show

Comments

Yuya Nishihara - Aug. 15, 2018, 12:47 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1530970839 -32400
#      Sat Jul 07 22:40:39 2018 +0900
# Node ID ed903661203305cb8c0d44f420aa3ace06c4f46e
# Parent  242bf65ae76ad839d89dbae348eec5f28990b663
commit: try hard to reuse p1 manifest if nothing changed

This is all for commit reproducibility on "hg convert".

With this change, p1 manifest is reused if ctx.files() *to be committed* is
empty, and if new manifest entry is identical to p1. This is important
property for "hg convert" since memctx.files() built from a convert source
may be either a) more narrowed thanks to a committed ctx.files() which
provides more accurate status, or b) containing redundant files because of
sloppy filtering on e.g. octopus merge.
Augie Fackler - Aug. 15, 2018, 9:09 p.m.
> On Aug 14, 2018, at 8:47 PM, Yuya Nishihara <yuya@tcha.org> wrote:
> 
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1530970839 -32400
> #      Sat Jul 07 22:40:39 2018 +0900
> # Node ID ed903661203305cb8c0d44f420aa3ace06c4f46e
> # Parent  242bf65ae76ad839d89dbae348eec5f28990b663
> commit: try hard to reuse p1 manifest if nothing changed

queued, thanks

Patch

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -2039,6 +2039,11 @@  class localrepository(object):
     def commitctx(self, ctx, error=False):
         """Add a new revision to current 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().
         """
 
         tr = None
@@ -2091,15 +2096,29 @@  class localrepository(object):
                         raise
 
                 # update manifest
-                self.ui.note(_("committing manifest\n"))
                 removed = [f for f in sorted(removed) if f in m1 or f in m2]
                 drop = [f for f in removed if f in m]
                 for f in drop:
                     del m[f]
-                mn = mctx.write(trp, linkrev,
-                                p1.manifestnode(), p2.manifestnode(),
-                                added, drop)
                 files = changed + removed
+                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(self, ctx.files()))
+                if not files and md:
+                    self.ui.debug('not reusing manifest (no file change in '
+                                  'changelog, but manifest differs)\n')
+                if files or md:
+                    self.ui.note(_("committing manifest\n"))
+                    mn = mctx.write(trp, linkrev,
+                                    p1.manifestnode(), p2.manifestnode(),
+                                    added, drop)
+                else:
+                    self.ui.debug('reusing manifest form p1 (listed files '
+                                  'actually unchanged)\n')
+                    mn = p1.manifestnode()
             else:
                 self.ui.debug('reusing manifest from p1 (no file change)\n')
                 mn = p1.manifestnode()
diff --git a/tests/test-convert-bzr-merges.t b/tests/test-convert-bzr-merges.t
--- a/tests/test-convert-bzr-merges.t
+++ b/tests/test-convert-bzr-merges.t
@@ -83,20 +83,17 @@  test multiple merges at once
   $ hg -R hg2hg out source-hg -T compact
   comparing with source-hg
   searching for changes
-  5[tip]:4,3   6bd55e826939   2009-10-10 08:00 +0100   foo
-    (octopus merge fixup)
-  
-XXX: The manifest lines should probably agree, to avoid changing the hash when
-converting hg -> hg
+  no changes found
+  [1]
 
   $ hg -R source-hg log --debug -r tip
-  changeset:   5:b209510f11b2c987f920749cd8e352aa4b3230f2
+  changeset:   5:6bd55e8269392769783345686faf7ff7b3b0215d
   branch:      source
   tag:         tip
   phase:       draft
   parent:      4:1dc38c377bb35eeea4fa955056fbe4440d54a743
   parent:      3:4aaba1bfb426b8941bbf63f9dd52301152695164
-  manifest:    5:1109e42bdcbd1f51baa69bc91079011d77057dbb
+  manifest:    4:daa315d56a98ba20811fdd0d9d575861f65cfa8c
   user:        Foo Bar <foo.bar@example.com>
   date:        Sat Oct 10 08:00:04 2009 +0100
   extra:       branch=source
diff --git a/tests/test-convert-filemap.t b/tests/test-convert-filemap.t
--- a/tests/test-convert-filemap.t
+++ b/tests/test-convert-filemap.t
@@ -780,7 +780,7 @@  example because filemap changed.
   converting...
   0 3
   $ hg -R .-hg log -G -T '{shortest(node)} {desc}\n{files % "- {file}\n"}\n'
-  o    e9ed 3
+  o    bbfe 3
   |\
   | o  33a0 2
   | |  - f
diff --git a/tests/test-convert-svn-branches.t b/tests/test-convert-svn-branches.t
--- a/tests/test-convert-svn-branches.t
+++ b/tests/test-convert-svn-branches.t
@@ -85,8 +85,8 @@  Convert again
   $ hg branches
   newbranch                     11:a6d7cc050ad1
   default                       10:6e2b33404495
-  old                            9:93c4b0f99529
-  old2                           8:b52884d7bead (inactive)
+  old                            9:1b494af68c0b
+  old2                           8:5be40b8dcbf6 (inactive)
   $ hg tags -q
   tip
   $ cd ..
diff --git a/tests/test-fix.t b/tests/test-fix.t
--- a/tests/test-fix.t
+++ b/tests/test-fix.t
@@ -851,9 +851,9 @@  no ancestors that are replaced.
   
   $ hg fix -r 0:2
   $ hg log --graph --template '{node|shortest} {files}'
-  o  3801 bar.whole
+  o  b4e2 bar.whole
   |
-  o  38cc
+  o  59f4
   |
   | @  bc05 bar.whole
   | |
diff --git a/tests/test-graft.t b/tests/test-graft.t
--- a/tests/test-graft.t
+++ b/tests/test-graft.t
@@ -699,8 +699,23 @@  Transplants of grafts can find a destina
   summary:     2
   
 ... grafts of grafts unfortunately can't
-  $ hg graft -q 13
+  $ hg graft -q 13 --debug
+  scanning for duplicate grafts
+  grafting 13:7a4785234d87 "2"
+    searching for copies back to rev 12
+    unmatched files in other (from topological common ancestor):
+     g
+    unmatched files new in both:
+     b
+  resolving manifests
+   branchmerge: True, force: True, partial: False
+   ancestor: b592ea63bb0c, local: 7e61b508e709+, remote: 7a4785234d87
+  committing files:
+  b
   warning: can't find ancestor for 'b' copied from 'a'!
+  reusing manifest form p1 (listed files actually unchanged)
+  committing changelog
+  updating the branch cache
   $ hg log -r 'destination(13)'
 All copies of a cset
   $ hg log -r 'origin(13) or destination(origin(13))'
@@ -731,7 +746,7 @@  All copies of a cset
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     2
   
-  changeset:   22:d1cb6591fa4b
+  changeset:   22:3a4e92d81b97
   branch:      dev
   tag:         tip
   user:        foo
@@ -743,8 +758,8 @@  graft works on complex revset
 
   $ hg graft 'origin(13) or destination(origin(13))'
   skipping ancestor revision 21:7e61b508e709
-  skipping ancestor revision 22:d1cb6591fa4b
-  skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
+  skipping ancestor revision 22:3a4e92d81b97
+  skipping revision 2:5c095ad7e90f (already grafted to 22:3a4e92d81b97)
   grafting 7:ef0ef43d49e7 "2"
   warning: can't find ancestor for 'b' copied from 'a'!
   grafting 13:7a4785234d87 "2"
@@ -758,7 +773,7 @@  graft with --force (still doesn't graft 
   $ hg graft 19 0 6
   skipping ungraftable merge revision 6
   skipping ancestor revision 0:68795b066622
-  skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
+  skipping already grafted revision 19:9627f653b421 (22:3a4e92d81b97 also has origin 2:5c095ad7e90f)
   [255]
   $ hg graft 19 0 6 --force
   skipping ungraftable merge revision 6
@@ -773,12 +788,12 @@  graft --force after backout
   $ hg ci -m 28
   $ hg backout 28
   reverting a
-  changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
+  changeset 29:9d95e865b00c backs out changeset 28:cc20d29aec8d
   $ hg graft 28
-  skipping ancestor revision 28:50a516bb8b57
+  skipping ancestor revision 28:cc20d29aec8d
   [255]
   $ hg graft 28 --force
-  grafting 28:50a516bb8b57 "28"
+  grafting 28:cc20d29aec8d "28"
   merging a
   $ cat a
   abc
@@ -788,7 +803,7 @@  graft --continue after --force
   $ echo def > a
   $ hg ci -m 31
   $ hg graft 28 --force --tool internal:fail
-  grafting 28:50a516bb8b57 "28"
+  grafting 28:cc20d29aec8d "28"
   abort: unresolved conflicts, can't continue
   (use 'hg resolve' and 'hg graft --continue')
   [255]
@@ -801,7 +816,7 @@  graft --continue after --force
   (no more unresolved files)
   continue: hg graft --continue
   $ hg graft -c
-  grafting 28:50a516bb8b57 "28"
+  grafting 28:cc20d29aec8d "28"
   $ cat a
   abc
 
@@ -822,8 +837,8 @@  Empty graft
   $ hg tag -f something
   $ hg graft -qr 27
   $ hg graft -f 27
-  grafting 27:ed6c7e54e319 "28"
-  note: graft of 27:ed6c7e54e319 created no changes to commit
+  grafting 27:17d42b8f5d50 "28"
+  note: graft of 27:17d42b8f5d50 created no changes to commit
 
   $ cd ..
 
diff --git a/tests/test-merge-no-file-change.t b/tests/test-merge-no-file-change.t
--- a/tests/test-merge-no-file-change.t
+++ b/tests/test-merge-no-file-change.t
@@ -30,6 +30,7 @@  Files added at both parents:
   $ hg ci --debug -m merge
   committing files:
   b
+  not reusing manifest (no file change in changelog, but manifest differs)
   committing manifest
   committing changelog
   updating the branch cache
@@ -136,12 +137,12 @@  An identical file added at both parents,
   $ hg ci --debug -m merge
   committing files:
   b
-  committing manifest
+  reusing manifest form p1 (listed files actually unchanged)
   committing changelog
   updating the branch cache
-  committed changeset 3:4bfaad7f925b7f17f60524dc5d4e605f7bfbba3f
+  committed changeset 3:c8d50407916ef8a5a97cb6e36ca9bc844a6ee13e
   $ hg log -GTl
-  @    3:4bfaad7f925b p=2,1 m=3:a3a9fe23a5b8 f=[]
+  @    3:c8d50407916e p=2,1 m=2:36b69ba4b24b f=[]
   |\
   | o  2:99451f16b3f5 p=0,-1 m=2:36b69ba4b24b f=["b"]
   | |
@@ -155,16 +156,6 @@  An identical file added at both parents,
 
   $ cd ..
   $ check_convert_identity flag-change-take-p1
-  3:c8d50407916e
-  *** BUG: hash changes on convert ***
-  o    3:c8d50407916e p=2,1 m=2:36b69ba4b24b f=[]
-  |\
-  | o  2:99451f16b3f5 p=0,-1 m=2:36b69ba4b24b f=["b"]
-  | |
-  o |  1:64d01526d4c2 p=0,-1 m=1:686dbf0aeca4 f=["b"]
-  |/
-  o  0:487a0a245cea p=-1,-1 m=0:8515d4bfda76 f=["a"]
-  
 
 An identical file added at both parents, but the flag differs. Take other:
 
@@ -226,6 +217,7 @@  An identical file added at both parents,
   $ hg ci --debug -m merge
   committing files:
   c
+  not reusing manifest (no file change in changelog, but manifest differs)
   committing manifest
   committing changelog
   updating the branch cache
@@ -299,6 +291,7 @@  A file added at p2, a named branch creat
   $ hg ci --debug -m merge
   committing files:
   b
+  not reusing manifest (no file change in changelog, but manifest differs)
   committing manifest
   committing changelog
   updating the branch cache