[PATCH 5 of 5] largefiles: update lfdirstate for unchanged largefiles at linear merging

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Fri Aug 15 06:32:15 CDT 2014


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1408102131 -32400
#      Fri Aug 15 20:28:51 2014 +0900
# Node ID 623b6ef36438c72f1c8bfb8361a10e11bc19113f
# Parent  e10443a703bf8f6e3e02c1a396c1ca91c504d371
largefiles: update lfdirstate for unchanged largefiles at linear merging

Before this patch, linear merging of modified largefile causes
unexpected result, if (1) largefile collides with same name normal one
in the target revision and (2) "local" largefile is chosen, even
though branch merging between such revisions doesn't.

Expected result of such linear merging is marking largefile as
(re-)"added", but actual result is marking it as "modified".

The standin of modified "local largefile" is not changed by linear
merging, and updating/merging update lfdirstate entries only for
largefiles of which standins are changed.

This patch adds the code path to update lfdirstate only for largefiles
of which standins are not changed.

In this case, "synclfdirstate" should be invoked with True as
"normallookup" argument always to force using "normallookup" on
dirstate for "n" files, because "normal" may mark target files as
"clean" unexpectedly.

To reduce cost of "lfile not in filelist", this patch converts
"filelist" to "set" object: "filelist" is used only in (1) the newly
added code path and (2) the next line of "filelist = set(filelist)".

This is a temporary way to fix with less changes. For fundamental
resolution of this kind of problems in the future, "lfdirstate" should
be updated with "dirstate" simultaneously while "merge.update"
execution: maybe by hooking "recordupdates" (+ total refactoring
around lfdirstate handling)

diff --git a/hgext/largefiles/lfcommands.py b/hgext/largefiles/lfcommands.py
--- a/hgext/largefiles/lfcommands.py
+++ b/hgext/largefiles/lfcommands.py
@@ -443,6 +443,7 @@
         lfiles = set(lfutil.listlfiles(repo)) | set(lfdirstate)
 
         if filelist is not None:
+            filelist = set(filelist)
             lfiles = [f for f in lfiles if f in filelist]
 
         update = {}
@@ -512,6 +513,19 @@
 
             lfutil.synclfdirstate(repo, lfdirstate, lfile, normallookup)
 
+        if filelist is not None:
+            # If "local largefile" is chosen at file merging, it is
+            # not listed up in "filelist" (= dirstate syncing is
+            # omitted), because standin file is not changed before and
+            # after merging.
+            # But the status of such file may have to be changed by
+            # merging. For example, locally modified ("M") largefile
+            # has to become re-added("A"), if it is "normal" file in
+            # the target revision of linear-merging.
+            for lfile in lfdirstate:
+                if lfile not in filelist:
+                    lfutil.synclfdirstate(repo, lfdirstate, lfile, True)
+
         lfdirstate.write()
         if printmessage and lfiles:
             ui.status(_('%d largefiles updated, %d removed\n') % (updated,
diff --git a/tests/test-largefiles-update.t b/tests/test-largefiles-update.t
--- a/tests/test-largefiles-update.t
+++ b/tests/test-largefiles-update.t
@@ -247,6 +247,8 @@
   $ hg debugdirstate --nodates | grep large2
   a   0         -1 .hglf/large2
   r   0          0 large2
+  $ hg status -A large2
+  A large2
   $ cat large2
   modified large2 for linear merge
 
@@ -261,6 +263,8 @@
   $ hg debugdirstate --nodates | grep large3
   a   0         -1 .hglf/large3
   r   0          0 large3
+  $ hg status -A large3
+  A large3
   $ cat large3
   large3 as large file for linear merge
 


More information about the Mercurial-devel mailing list