git-p4: Search for parent commit on branch creation
To find out which is its parent the commit of the new branch is compared sequentially to each blob of the parent branch from the newest to the oldest. The first blob which results in a zero diff is considered the parent commit. If none is found, then the commit is applied to the top of the parent branch. A fast-import "checkpoint" call is required because diff-tree is only able to work with blobs on disk. But most of these commits will not be part of the final imported tree, making fast-import fail. To avoid this, the temporary branches are tracked and then removed at the end of the import process. Signed-off-by: Vitor Antunes <vitor.hda@gmail.com> Acked-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Vitor Antunes committed
Jan 25, 2012 at 23:48 UTC
fed23693ba1a1ea7beb851cd385d458136e91664
1 file changed
+45
-1
contrib/fast-import/git-p4
+45
-1
@@ -1429,6 +1429,8 @@ class P4Sync(Command, P4UserMap):
1429
self.cloneExclude = []
1430
self.useClientSpec = False
1431
self.clientSpecDirs = None
1432
+ self.tempBranches = []
1433
+ self.tempBranchLocation = "git-p4-tmp"
1434
1435
if gitConfig("git-p4.syncFromOrigin") == "false":
1436
self.syncWithOrigin = False
@@ -1450,6 +1452,14 @@ class P4Sync(Command, P4UserMap):
1452
.replace("%25", "%")
1453
return path
1454
1455
+ # Force a checkpoint in fast-import and wait for it to finish
1456
+ def checkpoint(self):
1457
+ self.gitStream.write("checkpoint\n\n")
1458
+ self.gitStream.write("progress checkpoint\n\n")
1459
+ out = self.gitOutput.readline()
1460
+ if self.verbose:
1461
+ print "checkpoint finished: " + out
1462
+
1463
def extractFilesFromCommit(self, commit):
1464
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
1465
for path in self.cloneExclude]
@@ -1957,6 +1967,20 @@ class P4Sync(Command, P4UserMap):
1967
self.importChanges(changes)
1968
return True
1969
1970
+ def searchParent(self, parent, branch, target):
1971
+ parentFound = False
1972
+ for blob in read_pipe_lines(["git", "rev-list", "--reverse", "--no-merges", parent]):
1973
+ blob = blob.strip()
1974
+ if len(read_pipe(["git", "diff-tree", blob, target])) == 0:
1975
+ parentFound = True
1976
+ if self.verbose:
1977
+ print "Found parent of %s in commit %s" % (branch, blob)
1978
+ break
1979
+ if parentFound:
1980
+ return blob
1981
+ else:
1982
+ return None
1983
+
1984
def importChanges(self, changes):
1985
cnt = 1
1986
for change in changes:
@@ -2013,7 +2037,21 @@ class P4Sync(Command, P4UserMap):
2037
parent = self.initialParents[branch]
2038
del self.initialParents[branch]
2039
2016
- self.commit(description, filesForCommit, branch, [branchPrefix], parent)
2040
+ blob = None
2041
+ if len(parent) > 0:
2042
+ tempBranch = os.path.join(self.tempBranchLocation, "%d" % (change))
2043
+ if self.verbose:
2044
+ print "Creating temporary branch: " + tempBranch
2045
+ self.commit(description, filesForCommit, tempBranch, [branchPrefix])
2046
+ self.tempBranches.append(tempBranch)
2047
+ self.checkpoint()
2048
+ blob = self.searchParent(parent, branch, tempBranch)
2049
+ if blob:
2050
+ self.commit(description, filesForCommit, branch, [branchPrefix], blob)
2051
+ else:
2052
+ if self.verbose:
2053
+ print "Parent of %s not found. Committing into head of %s" % (branch, parent)
2054
+ self.commit(description, filesForCommit, branch, [branchPrefix], parent)
2055
else:
2056
files = self.extractFilesFromCommit(description)
2057
self.commit(description, files, self.branch, self.depotPaths,
@@ -2348,6 +2386,12 @@ class P4Sync(Command, P4UserMap):
2386
self.gitOutput.close()
2387
self.gitError.close()
2388
2389
+ # Cleanup temporary branches created during import
2390
+ if self.tempBranches != []:
2391
+ for branch in self.tempBranches:
2392
+ read_pipe("git update-ref -d %s" % branch)
2393
+ os.rmdir(os.path.join(os.environ.get("GIT_DIR", ".git"), self.tempBranchLocation))
2394
+
2395
return True
2396
2397
class P4Rebase(Command):