diff --git a/hggit/git_handler.py b/hggit/git_handler.py index 8b05466e..03c55256 100644 --- a/hggit/git_handler.py +++ b/hggit/git_handler.py @@ -499,14 +499,38 @@ def import_git_commit(self, commit): oldenc = self.swap_out_encoding() - def getfilectx(repo, memctx, f): - delete, mode, sha = files[f] - if delete: - raise IOError + def findconvergedfiles(p1, p2): + # If any files have the same contents in both parents of a merge + # (and are therefore not reported as changed by Git) but are at + # different file revisions in Mercurial (because they arrived at + # those contents in different ways), we need to include them in + # the list of changed files so that Mercurial can join up their + # filelog histories (same as if the merge was done in Mercurial to + # begin with). + if p2 == nullid: + return [] + manifest1 = self.repo.changectx(p1).manifest() + manifest2 = self.repo.changectx(p2).manifest() + return [path for path, node1 in manifest1.iteritems() + if path not in files and manifest2.get(path, node1) != node1] - data = self.git[sha].data - copied_path = hg_renames.get(f) - e = self.convert_git_int_mode(mode) + def getfilectx(repo, memctx, f): + info = files.get(f) + if info != None: + # it's a file reported as modified from Git + delete, mode, sha = info + if delete: + raise IOError + + data = self.git[sha].data + copied_path = hg_renames.get(f) + e = self.convert_git_int_mode(mode) + else: + # it's a converged file + fc = context.filectx(self.repo, f, changeid=memctx.p1().rev()) + data = fc.data() + e = fc.flags() + copied_path = fc.renamed() return context.memfilectx(f, data, 'l' in e, 'x' in e, copied_path) @@ -517,8 +541,9 @@ def getfilectx(repo, memctx, f): if len(gparents) > 1: # merge, possibly octopus def commit_octopus(p1, p2): - ctx = context.memctx(self.repo, (p1, p2), text, list(files), getfilectx, - author, date, {'hg-git': 'octopus'}) + ctx = context.memctx(self.repo, (p1, p2), text, + list(files) + findconvergedfiles(p1, p2), + getfilectx, author, date, {'hg-git': 'octopus'}) return hex(self.repo.commitctx(ctx)) octopus = len(gparents) > 2 @@ -567,8 +592,9 @@ def repo_contains(n): if not (repo_contains(p1) and repo_contains(p2)): raise hgutil.Abort(_('you appear to have run strip - ' 'please run hg git-cleanup')) - ctx = context.memctx(self.repo, (p1, p2), text, list(files), getfilectx, - author, date, extra) + ctx = context.memctx(self.repo, (p1, p2), text, + list(files) + findconvergedfiles(p1, p2), + getfilectx, author, date, extra) node = self.repo.commitctx(ctx) diff --git a/tests/test-conflict-1 b/tests/test-conflict-1 new file mode 100755 index 00000000..a708e8c0 --- /dev/null +++ b/tests/test-conflict-1 @@ -0,0 +1,63 @@ +#!/bin/sh + +# Fails for some reason, need to investigate +# "$TESTDIR/hghave" git || exit 80 + +# bail if the user does not have dulwich +python -c 'import dulwich, dulwich.repo' || exit 80 + +# bail early if the user is already running git-daemon +echo hi | nc localhost 9418 2>/dev/null && exit 80 + +echo "[extensions]" >> $HGRCPATH +echo "hggit=$(echo $(dirname $(dirname $0)))/hggit" >> $HGRCPATH +echo 'hgext.graphlog =' >> $HGRCPATH +echo 'hgext.bookmarks =' >> $HGRCPATH + +hg init hgrepo1 +cd hgrepo1 +echo A > afile +hg add afile +hg ci -m "origin" + +echo B > afile +hg ci -m "A->B" + +hg up -r0 +echo C > afile +hg ci -m "A->C" + +hg merge -r1 +# resolve using first parent +echo C > afile +hg resolve -m afile +hg ci -m "merge to C" + +hg log --graph --style compact | sed 's/\[.*\]//g' + +cd .. + +mkdir gitrepo +cd gitrepo +git init --bare | python -c "import sys; print sys.stdin.read().replace('$(dirname $(pwd))/', '')" + +# dulwich does not presently support local git repos, workaround +cd .. +git daemon --base-path="$(pwd)"\ + --listen=localhost\ + --export-all\ + --pid-file="$DAEMON_PIDS" \ + --detach --reuseaddr \ + --enable=receive-pack + +cd hgrepo1 +hg bookmark -r tip master +hg push -r master git://localhost/gitrepo +cd .. + +hg clone git://localhost/gitrepo hgrepo2 | grep -v '^updating' +cd hgrepo2 +echo % expect the same revision ids as above +hg log --graph --style compact | sed 's/\[.*\]//g' + +cd .. diff --git a/tests/test-conflict-1.out b/tests/test-conflict-1.out new file mode 100644 index 00000000..f2b2d1b5 --- /dev/null +++ b/tests/test-conflict-1.out @@ -0,0 +1,42 @@ +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +created new head +merging afile +warning: conflicts during merge. +merging afile failed! +0 files updated, 0 files merged, 0 files removed, 1 files unresolved +use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon +@ 3:2,1 6c53bc0f062f 1970-01-01 00:00 +0000 test +|\ merge to C +| | +| o 2:0 ea82b67264a1 1970-01-01 00:00 +0000 test +| | A->C +| | +o | 1 7205e83b5a3f 1970-01-01 00:00 +0000 test +|/ A->B +| +o 0 5d1a6b64f9d0 1970-01-01 00:00 +0000 test + origin + +Initialized empty Git repository in gitrepo/ + +pushing to git://localhost/gitrepo +exporting hg objects to git +creating and sending data +Counting objects: 10, done. +Compressing objects: 25% (1/4) Compressing objects: 50% (2/4) Compressing objects: 75% (3/4) Compressing objects: 100% (4/4) Compressing objects: 100% (4/4), done. +Total 10 (delta 0), reused 0 (delta 0) +importing git objects into hg +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% expect the same revision ids as above +@ 3:1,2 6c53bc0f062f 1970-01-01 00:00 +0000 test +|\ merge to C +| | +| o 2:0 7205e83b5a3f 1970-01-01 00:00 +0000 test +| | A->B +| | +o | 1 ea82b67264a1 1970-01-01 00:00 +0000 test +|/ A->C +| +o 0 5d1a6b64f9d0 1970-01-01 00:00 +0000 test + origin + diff --git a/tests/test-conflict-2 b/tests/test-conflict-2 new file mode 100755 index 00000000..debdbe31 --- /dev/null +++ b/tests/test-conflict-2 @@ -0,0 +1,63 @@ +#!/bin/sh + +# Fails for some reason, need to investigate +# "$TESTDIR/hghave" git || exit 80 + +# bail if the user does not have dulwich +python -c 'import dulwich, dulwich.repo' || exit 80 + +# bail early if the user is already running git-daemon +echo hi | nc localhost 9418 2>/dev/null && exit 80 + +echo "[extensions]" >> $HGRCPATH +echo "hggit=$(echo $(dirname $(dirname $0)))/hggit" >> $HGRCPATH +echo 'hgext.graphlog =' >> $HGRCPATH +echo 'hgext.bookmarks =' >> $HGRCPATH + +hg init hgrepo1 +cd hgrepo1 +echo A > afile +hg add afile +hg ci -m "origin" + +echo B > afile +hg ci -m "A->B" + +hg up -r0 +echo C > afile +hg ci -m "A->C" + +hg merge -r1 +# resolve using second parent +echo B > afile +hg resolve -m afile +hg ci -m "merge to B" + +hg log --graph --style compact | sed 's/\[.*\]//g' + +cd .. + +mkdir gitrepo +cd gitrepo +git init --bare | python -c "import sys; print sys.stdin.read().replace('$(dirname $(pwd))/', '')" + +# dulwich does not presently support local git repos, workaround +cd .. +git daemon --base-path="$(pwd)"\ + --listen=localhost\ + --export-all\ + --pid-file="$DAEMON_PIDS" \ + --detach --reuseaddr \ + --enable=receive-pack + +cd hgrepo1 +hg bookmark -r tip master +hg push -r master git://localhost/gitrepo +cd .. + +hg clone git://localhost/gitrepo hgrepo2 | grep -v '^updating' +cd hgrepo2 +echo % expect the same revision ids as above +hg log --graph --style compact | sed 's/\[.*\]//g' + +cd .. diff --git a/tests/test-conflict-2.out b/tests/test-conflict-2.out new file mode 100644 index 00000000..454472e0 --- /dev/null +++ b/tests/test-conflict-2.out @@ -0,0 +1,42 @@ +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +created new head +merging afile +warning: conflicts during merge. +merging afile failed! +0 files updated, 0 files merged, 0 files removed, 1 files unresolved +use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon +@ 3:2,1 120385945d08 1970-01-01 00:00 +0000 test +|\ merge to B +| | +| o 2:0 ea82b67264a1 1970-01-01 00:00 +0000 test +| | A->C +| | +o | 1 7205e83b5a3f 1970-01-01 00:00 +0000 test +|/ A->B +| +o 0 5d1a6b64f9d0 1970-01-01 00:00 +0000 test + origin + +Initialized empty Git repository in gitrepo/ + +pushing to git://localhost/gitrepo +exporting hg objects to git +creating and sending data +Counting objects: 10, done. +Compressing objects: 25% (1/4) Compressing objects: 50% (2/4) Compressing objects: 75% (3/4) Compressing objects: 100% (4/4) Compressing objects: 100% (4/4), done. +Total 10 (delta 0), reused 0 (delta 0) +importing git objects into hg +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% expect the same revision ids as above +@ 3:1,2 120385945d08 1970-01-01 00:00 +0000 test +|\ merge to B +| | +| o 2:0 7205e83b5a3f 1970-01-01 00:00 +0000 test +| | A->B +| | +o | 1 ea82b67264a1 1970-01-01 00:00 +0000 test +|/ A->C +| +o 0 5d1a6b64f9d0 1970-01-01 00:00 +0000 test + origin + diff --git a/tests/test-convergedmerge b/tests/test-convergedmerge new file mode 100755 index 00000000..e2156912 --- /dev/null +++ b/tests/test-convergedmerge @@ -0,0 +1,63 @@ +#!/bin/sh + +# Fails for some reason, need to investigate +# "$TESTDIR/hghave" git || exit 80 + +# bail if the user does not have dulwich +python -c 'import dulwich, dulwich.repo' || exit 80 + +# bail early if the user is already running git-daemon +echo hi | nc localhost 9418 2>/dev/null && exit 80 + +echo "[extensions]" >> $HGRCPATH +echo "hggit=$(echo $(dirname $(dirname $0)))/hggit" >> $HGRCPATH +echo 'hgext.graphlog =' >> $HGRCPATH +echo 'hgext.bookmarks =' >> $HGRCPATH + +hg init hgrepo1 +cd hgrepo1 +echo A > afile +hg add afile +hg ci -m "origin" + +echo B > afile +hg ci -m "A->B" + +echo C > afile +hg ci -m "B->C" + +hg up -r0 +echo C > afile +hg ci -m "A->C" + +hg merge -r2 +hg ci -m "merge" + +hg log --graph --style compact | sed 's/\[.*\]//g' + +cd .. + +mkdir gitrepo +cd gitrepo +git init --bare | python -c "import sys; print sys.stdin.read().replace('$(dirname $(pwd))/', '')" + +# dulwich does not presently support local git repos, workaround +cd .. +git daemon --base-path="$(pwd)"\ + --listen=localhost\ + --export-all\ + --pid-file="$DAEMON_PIDS" \ + --detach --reuseaddr \ + --enable=receive-pack + +cd hgrepo1 +hg bookmark -r4 master +hg push -r master git://localhost/gitrepo +cd .. + +hg clone git://localhost/gitrepo hgrepo2 | grep -v '^updating' +cd hgrepo2 +echo % expect the same revision ids as above +hg log --graph --style compact | sed 's/\[.*\]//g' + +cd .. diff --git a/tests/test-convergedmerge.out b/tests/test-convergedmerge.out new file mode 100644 index 00000000..e34a6580 --- /dev/null +++ b/tests/test-convergedmerge.out @@ -0,0 +1,45 @@ +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +created new head +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +@ 4:3,2 eaa21d002113 1970-01-01 00:00 +0000 test +|\ merge +| | +| o 3:0 ea82b67264a1 1970-01-01 00:00 +0000 test +| | A->C +| | +o | 2 0dbe4ac1a758 1970-01-01 00:00 +0000 test +| | B->C +| | +o | 1 7205e83b5a3f 1970-01-01 00:00 +0000 test +|/ A->B +| +o 0 5d1a6b64f9d0 1970-01-01 00:00 +0000 test + origin + +Initialized empty Git repository in gitrepo/ + +pushing to git://localhost/gitrepo +exporting hg objects to git +creating and sending data +Counting objects: 11, done. +Compressing objects: 20% (1/5) Compressing objects: 40% (2/5) Compressing objects: 60% (3/5) Compressing objects: 80% (4/5) Compressing objects: 100% (5/5) Compressing objects: 100% (5/5), done. +Total 11 (delta 0), reused 0 (delta 0) +importing git objects into hg +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% expect the same revision ids as above +@ 4:1,3 eaa21d002113 1970-01-01 00:00 +0000 test +|\ merge +| | +| o 3 0dbe4ac1a758 1970-01-01 00:00 +0000 test +| | B->C +| | +| o 2:0 7205e83b5a3f 1970-01-01 00:00 +0000 test +| | A->B +| | +o | 1 ea82b67264a1 1970-01-01 00:00 +0000 test +|/ A->C +| +o 0 5d1a6b64f9d0 1970-01-01 00:00 +0000 test + origin +