# HG changeset patch
# User Siddharth Agarwal <sid0@fb.com>
# Date 1417564641 28800
#      Tue Dec 02 15:57:21 2014 -0800
# Node ID da804eac2b00d10c76fa12cca95176a54680873f
# Parent  cf9dd81b61dcac87c807364560e05b233b503d7f
git_handler.get_files_changed: detect renames when asked to do so

We use Dulwich's rename detector to detect any renames over the specified
similarity threshold.

This isn't fully bidirectional yet -- when the commit is exported to Git
the hashes will no longer be the same. That's why that isn't tested here. In
upcoming patches we'll make sure it's bidirectional and will add the
corresponding tests.

diff --git a/hggit/git_handler.py b/hggit/git_handler.py
--- a/hggit/git_handler.py
+++ b/hggit/git_handler.py
@@ -1298,12 +1298,16 @@
         if commit.parents:
             btree = self.git[commit.parents[0]].tree
 
-        changes = diff_tree.tree_changes(self.git.object_store, btree, tree)
         files = {}
         gitlinks = {}
         renames = None
+        rename_detector = None
         if detect_renames:
             renames = {}
+            rename_detector = self._rename_detector
+
+        changes = diff_tree.tree_changes(self.git.object_store, btree, tree,
+                                         rename_detector=rename_detector)
 
         for change in changes:
             oldfile, oldmode, oldsha = change.old
@@ -1322,6 +1326,10 @@
             if newmode == 0160000:
                 # new = gitlink
                 gitlinks[newfile] = newsha
+                if change.type == diff_tree.CHANGE_RENAME:
+                    # don't record the rename because only file -> file renames
+                    # make sense in Mercurial
+                    gitlinks[oldfile] = None
                 if oldmode is not None and oldmode != 0160000:
                     # file -> gitlink
                     files[oldfile] = True, None, None
@@ -1333,6 +1341,10 @@
             if newfile is not None:
                 # new = file
                 files[newfile] = False, newmode, newsha
+                if renames is not None and newfile != oldfile:
+                    renames[newfile] = oldfile
+                    if change.type == diff_tree.CHANGE_RENAME:
+                        files[oldfile] = True, None, None
             else:
                 # old = file
                 files[oldfile] = True, None, None
@@ -1357,7 +1369,7 @@
 
         find_copies_harder = self.ui.configbool('git', 'findcopiesharder',
                                                 default=False)
-        return diff_tree.RenameDetector(
+        return diff_tree.RenameDetector(self.git.object_store,
             rename_threshold=similarity, max_files=max_files,
             find_copies_harder=find_copies_harder)
 
diff --git a/tests/test-renames.t b/tests/test-renames.t
new file mode 100644
--- /dev/null
+++ b/tests/test-renames.t
@@ -0,0 +1,160 @@
+Test that rename detection works
+  $ . "$TESTDIR/testutil"
+
+  $ cat >> $HGRCPATH <<EOF
+  > [diff]
+  > git = True
+  > [git]
+  > similarity = 50
+  > EOF
+
+  $ git init -q gitrepo
+  $ cd gitrepo
+  $ for i in $(seq 1 10); do echo $i >> alpha; done
+  $ git add alpha
+  $ fn_git_commit -malpha
+
+Rename a file
+  $ git mv alpha beta
+  $ echo 11 >> beta
+  $ git add beta
+  $ fn_git_commit -mbeta
+
+Copy a file
+  $ cp beta gamma
+  $ echo 12 >> beta
+  $ echo 13 >> gamma
+  $ git add beta gamma
+  $ fn_git_commit -mgamma
+
+Add a submodule (gitlink) and move it to a different spot:
+  $ cd ..
+  $ git init -q gitsubmodule
+  $ cd gitsubmodule
+  $ touch subalpha
+  $ git add subalpha
+  $ fn_git_commit -msubalpha
+  $ cd ../gitrepo
+
+  $ rmpwd="import sys; print sys.stdin.read().replace('$(dirname $(pwd))/', '')"
+  $ clonefilt='s/Cloning into/Initialized empty Git repository in/;s/in .*/in .../'
+
+  $ git submodule add ../gitsubmodule 2>&1 | python -c "$rmpwd" | sed "$clonefilt" | egrep -v '^done\.$'
+  Initialized empty Git repository in ...
+  
+  $ fn_git_commit -m 'add submodule'
+  $ sed -e 's/path = gitsubmodule/path = gitsubmodule2/' .gitmodules > .gitmodules-new
+  $ mv .gitmodules-new .gitmodules
+  $ mv gitsubmodule gitsubmodule2
+  $ git add .gitmodules gitsubmodule2
+  $ git rm --cached gitsubmodule
+  rm 'gitsubmodule'
+  $ fn_git_commit -m 'move submodule'
+
+  $ cd ..
+  $ hg clone -q gitrepo hgrepo
+  $ cd hgrepo
+  $ hg log -p --graph --template "{rev} {node} {desc|firstline}\n{join(extras, ' ')}\n\n"
+  @  4 8ef5468692d8a63a2a56d35540ccc2a83970daf1 move submodule
+  |  branch=default
+  |
+  |  diff --git a/.gitmodules b/.gitmodules
+  |  --- a/.gitmodules
+  |  +++ b/.gitmodules
+  |  @@ -1,3 +1,3 @@
+  |   [submodule "gitsubmodule"]
+  |  -	path = gitsubmodule
+  |  +	path = gitsubmodule2
+  |   	url = ../gitsubmodule
+  |  diff --git a/.hgsub b/.hgsub
+  |  --- a/.hgsub
+  |  +++ b/.hgsub
+  |  @@ -1,1 +1,1 @@
+  |  -gitsubmodule = [git]../gitsubmodule
+  |  +gitsubmodule2 = [git]../gitsubmodule
+  |  diff --git a/.hgsubstate b/.hgsubstate
+  |  --- a/.hgsubstate
+  |  +++ b/.hgsubstate
+  |  @@ -1,1 +1,1 @@
+  |  -5944b31ff85b415573d1a43eb942e2dea30ab8be gitsubmodule
+  |  +5944b31ff85b415573d1a43eb942e2dea30ab8be gitsubmodule2
+  |
+  o  3 82b69d514926123f7d83b6a8fb5b041bc79c5af9 add submodule
+  |  branch=default
+  |
+  |  diff --git a/.gitmodules b/.gitmodules
+  |  new file mode 100644
+  |  --- /dev/null
+  |  +++ b/.gitmodules
+  |  @@ -0,0 +1,3 @@
+  |  +[submodule "gitsubmodule"]
+  |  +	path = gitsubmodule
+  |  +	url = ../gitsubmodule
+  |  diff --git a/.hgsub b/.hgsub
+  |  new file mode 100644
+  |  --- /dev/null
+  |  +++ b/.hgsub
+  |  @@ -0,0 +1,1 @@
+  |  +gitsubmodule = [git]../gitsubmodule
+  |  diff --git a/.hgsubstate b/.hgsubstate
+  |  new file mode 100644
+  |  --- /dev/null
+  |  +++ b/.hgsubstate
+  |  @@ -0,0 +1,1 @@
+  |  +5944b31ff85b415573d1a43eb942e2dea30ab8be gitsubmodule
+  |
+  o  2 79563b42ed93cd47601aec11694f4e0df48457e7 gamma
+  |  branch=default
+  |
+  |  diff --git a/beta b/beta
+  |  --- a/beta
+  |  +++ b/beta
+  |  @@ -9,3 +9,4 @@
+  |   9
+  |   10
+  |   11
+  |  +12
+  |  diff --git a/beta b/gamma
+  |  copy from beta
+  |  copy to gamma
+  |  --- a/beta
+  |  +++ b/gamma
+  |  @@ -9,3 +9,4 @@
+  |   9
+  |   10
+  |   11
+  |  +13
+  |
+  o  1 d1c40364c3c996350da6963e605df8269db8e311 beta
+  |  branch=default
+  |
+  |  diff --git a/alpha b/beta
+  |  rename from alpha
+  |  rename to beta
+  |  --- a/alpha
+  |  +++ b/beta
+  |  @@ -8,3 +8,4 @@
+  |   8
+  |   9
+  |   10
+  |  +11
+  |
+  o  0 0c233c2e91d64435bf329075bc0e7e858bc3b07c alpha
+     branch=default
+  
+     diff --git a/alpha b/alpha
+     new file mode 100644
+     --- /dev/null
+     +++ b/alpha
+     @@ -0,0 +1,10 @@
+     +1
+     +2
+     +3
+     +4
+     +5
+     +6
+     +7
+     +8
+     +9
+     +10
+