Patchwork D8977: merge: check for dir rename dest before adding ACTION_KEEP

login
register
mail settings
Submitter phabricator
Date Sept. 2, 2020, 11:55 a.m.
Message ID <differential-rev-PHID-DREV-p5pikqvhjn5aaj2x2lgi-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/47083/
State New
Headers show

Comments

phabricator - Sept. 2, 2020, 11:55 a.m.
pulkit created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  A previous patch in the series blindly uses `ACTION_KEEP` if the file is not
  present on both remote and ancestor. This was wrong.
  
  We tries to detect directory renames and in some graft cases, it can be possible
  that file is not present on both sides but is created in rename destination of
  other directory which exists on remote. In such cases, we need to merge the
  rename source from remote with rename dest from local.
  
  This patch makes sure we checks for such rename cases before falling back to
  `ACTION_KEEP`.
  
  Also, we moved the adding of action for the destination file while processing
  the destination file which makes things much simpler as an action for file will
  only be added while processing it. And we added a `ACTION_KEEP_ABSENT` for the
  rename source because otherwise an action for that was missing.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8977

AFFECTED FILES
  mercurial/merge.py

CHANGE DETAILS




To: pulkit, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -933,12 +933,41 @@ 
                         f, mergestatemod.ACTION_REMOVE, None, b'other deleted',
                     )
             else:  # file not in ancestor, not in remote
-                mresult.addfile(
-                    f,
-                    mergestatemod.ACTION_KEEP,
-                    None,
-                    b'ancestor missing, remote missing',
-                )
+                rename_found = False
+                for source, dest in branch_copies1.dirmove.items():
+                    if f.startswith(dest):
+                        # this directory in which this file is created
+                        # is moved from somewhere else
+                        # we should check if the source file exists on
+                        # remote side
+                        sf = source + f[len(dest) :]
+                        if sf in m2:
+                            rename_found = True
+                            if m2[sf] == ma[sf]:
+                                mresult.addfile(
+                                    f,
+                                    mergestatemod.ACTION_KEEP,
+                                    None,
+                                    b'file is rename dest and rename source'
+                                    b' did not change',
+                                )
+                            else:
+                                mresult.addfile(
+                                    f,
+                                    mergestatemod.ACTION_MERGE,
+                                    (f, sf, sf, False, pa.node()),
+                                    b'local directory rename - respect move '
+                                    b'from %s' % sf,
+                                )
+                            break
+
+                if not rename_found:
+                    mresult.addfile(
+                        f,
+                        mergestatemod.ACTION_KEEP,
+                        None,
+                        b'ancestor missing, remote missing',
+                    )
 
         elif n2:  # file exists only on remote side
             if f in copied1:
@@ -1010,12 +1039,16 @@ 
                         df = branch_copies1.dirmove[d] + f[len(d) :]
                         break
                 if df is not None and df in m1:
+                    # this file is not present in local however its a source
+                    # of rename for another file. keep this file not
+                    # present in local. Action for rename dest is written
+                    # while processing it
                     mresult.addfile(
-                        df,
-                        mergestatemod.ACTION_MERGE,
-                        (df, f, f, False, pa.node()),
-                        b'local directory rename - respect move '
-                        b'from %s' % f,
+                        f,
+                        mergestatemod.ACTION_KEEP_ABSENT,
+                        None,
+                        b'remote directory is rename source - respect move '
+                        b'to %s' % df,
                     )
                 elif acceptremote:
                     mresult.addfile(