From patchwork Sat Jun 28 15:11:21 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [STABLE] convert: detect removal of ".gitmodules" at git source revisions correctly From: Katsunori FUJIWARA X-Patchwork-Id: 5077 Message-Id: To: mercurial-devel@selenic.com Date: Sun, 29 Jun 2014 00:11:21 +0900 # HG changeset patch # User FUJIWARA Katsunori # Date 1403966784 -32400 # Sat Jun 28 23:46:24 2014 +0900 # Branch stable # Node ID cb8567d0c76d7c0e66d2fe32607acc8621d2389f # Parent a4b67bf1f0a5051736c14d9c13fae50fd5f5e464 convert: detect removal of ".gitmodules" at git source revisions correctly Before this patch, all operations applied on ".gitmodules" at git source revisions are treated as modification, even if they are actually removal of it. If removal of ".gitmodules" is treated as modification unexpectedly, "hg convert" is aborted by the exception raised in "retrievegitmodules()" for ".gitmodules" at the git source revision removing it, because that revision doesn't have any information of ".gitmodules". This patch detects removal of ".gitmodules" at git source revisions correctly. If ".gitmodules" is removed at the git source revision, this patch records "hex(nullid)" as the contents hash value for ".hgsub" and ".hgsubstate" at the destination revision. This patch makes "getfile()" raise IOError also for ".hgstatus" and ".hgsubstate" if the contents hash value is "hex(nullid)", and this tells removal of ".hgstatus" and ".hgsubstate" at the destination revision to "localrepository.commitctx()" correctly. For files other than ".hgstatus" and ".hgsubstate", checking the contents hash value in "getfile()" may be redundant, because "catfile()" for them also does so. But this patch chooses writing it only once at the beginning of "getfile()", to avoid writing same code twice both for ".hgsub" and ".hgsubstate" separately. diff --git a/hgext/convert/git.py b/hgext/convert/git.py --- a/hgext/convert/git.py +++ b/hgext/convert/git.py @@ -104,6 +104,8 @@ return data def getfile(self, name, rev): + if rev == hex(nullid): + raise IOError if name == '.hgsub': data = '\n'.join([m.hgsub() for m in self.submoditer()]) mode = '' @@ -155,6 +157,7 @@ seen = set() entry = None subexists = False + subdeleted = False for l in fh.read().split('\x00'): if not entry: if not l.startswith(':'): @@ -171,7 +174,11 @@ if f == '.gitmodules': subexists = True - changes.append(('.hgsub', '')) + if entry[4] == 'D': + subdeleted = True + changes.append(('.hgsub', hex(nullid))) + else: + changes.append(('.hgsub', '')) elif entry[1] == '160000' or entry[0] == ':160000': subexists = True else: @@ -182,8 +189,11 @@ raise util.Abort(_('cannot read changes in %s') % version) if subexists: - self.retrievegitmodules(version) - changes.append(('.hgsubstate', '')) + if subdeleted: + changes.append(('.hgsubstate', hex(nullid))) + else: + self.retrievegitmodules(version) + changes.append(('.hgsubstate', '')) return (changes, {}) def getcommit(self, version): diff --git a/tests/test-convert-git.t b/tests/test-convert-git.t --- a/tests/test-convert-git.t +++ b/tests/test-convert-git.t @@ -363,6 +363,23 @@ $ cd ../.. +convert the revision removing '.gitmodules' itself (and related +submodules) + + $ cd git-repo6 + $ git rm .gitmodules + rm '.gitmodules' + $ git rm --cached git-repo5 + rm 'git-repo5' + $ commit -a -m 'remove .gitmodules and submodule git-repo5' + $ cd .. + + $ hg convert -q git-repo6 git-repo6-hg + $ hg -R git-repo6-hg tip -T "{desc|firstline}\n" + remove .gitmodules and submodule git-repo5 + $ hg -R git-repo6-hg tip -T "{file_dels}\n" + .hgsub .hgsubstate + damaged git repository tests: In case the hard-coded hashes change, the following commands can be used to list the hashes and their corresponding types in the repository: