From 31f9ec129ef37e50b5cacf26a2ebcb5420fcdc5e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 21 Aug 2007 11:53:02 +0200 Subject: git-p4: Always call 'p4 sync ...' before submitting to Perforce. Acked-by: Marius Storm-Olsen Acked-by: Thiago Macieira --- contrib/fast-import/git-p4 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 55778c5775..3728cbf9aa 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -664,9 +664,8 @@ class P4Submit(Command): f.close(); os.chdir(self.clientPath) - response = raw_input("Do you want to sync %s with p4 sync? [y]es/[n]o " % self.clientPath) - if response == "y" or response == "yes": - system("p4 sync ...") + print "Syncronizing p4 checkout..." + system("p4 sync ...") if self.reset: self.firstTime = True -- cgit v1.2.3 From 14594f4b5747e51b051f647f6430089e6664e77d Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 22 Aug 2007 09:07:15 +0200 Subject: git-p4: After submission to p4 always synchronize from p4 again (into refs/remotes). Whether to rebase HEAD or not is still left as question to the end-user. Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 3728cbf9aa..16e0a7bc81 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -704,10 +704,14 @@ class P4Submit(Command): else: print "All changes applied!" os.chdir(self.oldWorkingDirectory) - response = raw_input("Do you want to sync from Perforce now using git-p4 rebase? [y]es/[n]o ") + + sync = P4Sync() + sync.run([]) + + response = raw_input("Do you want to rebase current HEAD from Perforce now using git-p4 rebase? [y]es/[n]o ") if response == "y" or response == "yes": rebase = P4Rebase() - rebase.run([]) + rebase.rebase() os.remove(self.configFile) return True @@ -1439,6 +1443,9 @@ class P4Rebase(Command): sync = P4Sync() sync.run([]) + return self.rebase() + + def rebase(self): [upstream, settings] = findUpstreamBranchPoint() if len(upstream) == 0: die("Cannot find upstream branchpoint for rebase") -- cgit v1.2.3 From 4f6432d8cc6ebdcdc366cf67ab39e8125c449d80 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sun, 26 Aug 2007 15:56:36 +0200 Subject: git-p4: Cleanup; moved the code for getting a sorted list of p4 changes for a list of given depot paths into a standalone method. Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 16e0a7bc81..e9feb7498c 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -281,6 +281,19 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent def originP4BranchesExist(): return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master") +def p4ChangesForPaths(depotPaths, changeRange): + assert depotPaths + output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, changeRange) + for p in depotPaths])) + + changes = [] + for line in output: + changeNum = line.split(" ")[1] + changes.append(int(changeNum)) + + changes.sort() + return changes + class Command: def __init__(self): self.usage = "usage: %prog [options]" @@ -1322,15 +1335,7 @@ class P4Sync(Command): if self.verbose: print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), self.changeRange) - assert self.depotPaths - output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, self.changeRange) - for p in self.depotPaths])) - - for line in output: - changeNum = line.split(" ")[1] - changes.append(int(changeNum)) - - changes.sort() + changes = p4ChangesForPaths(self.depotPaths, self.changeRange) if len(self.maxChanges) > 0: changes = changes[:min(int(self.maxChanges), len(changes))] -- cgit v1.2.3 From e87f37ae42dad89b39620c234fc29c94529a4d07 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sun, 26 Aug 2007 16:00:52 +0200 Subject: git-p4: Cleanup; moved the code to import a list of p4 changes using fast-import into a separate member function of P4Sync. Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 140 +++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 69 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index e9feb7498c..c00702c895 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1118,6 +1118,76 @@ class P4Sync(Command): self.keepRepoPath = (d.has_key('options') and ('keepRepoPath' in d['options'])) + def importChanges(self, changes): + cnt = 1 + for change in changes: + description = p4Cmd("describe %s" % change) + self.updateOptionDict(description) + + if not self.silent: + sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes))) + sys.stdout.flush() + cnt = cnt + 1 + + try: + if self.detectBranches: + branches = self.splitFilesIntoBranches(description) + for branch in branches.keys(): + ## HACK --hwn + branchPrefix = self.depotPaths[0] + branch + "/" + + parent = "" + + filesForCommit = branches[branch] + + if self.verbose: + print "branch is %s" % branch + + self.updatedBranches.add(branch) + + if branch not in self.createdBranches: + self.createdBranches.add(branch) + parent = self.knownBranches[branch] + if parent == branch: + parent = "" + elif self.verbose: + print "parent determined through known branches: %s" % parent + + # main branch? use master + if branch == "main": + branch = "master" + else: + + ## FIXME + branch = self.projectName + branch + + if parent == "main": + parent = "master" + elif len(parent) > 0: + ## FIXME + parent = self.projectName + parent + + branch = self.refPrefix + branch + if len(parent) > 0: + parent = self.refPrefix + parent + + if self.verbose: + print "looking for initial parent for %s; current parent is %s" % (branch, parent) + + if len(parent) == 0 and branch in self.initialParents: + parent = self.initialParents[branch] + del self.initialParents[branch] + + self.commit(description, filesForCommit, branch, [branchPrefix], parent) + else: + files = self.extractFilesFromCommit(description) + self.commit(description, files, self.branch, self.depotPaths, + self.initialParent) + self.initialParent = "" + except IOError: + print self.gitError.read() + sys.exit(1) + def run(self, args): self.depotPaths = [] self.changeRange = "" @@ -1350,74 +1420,7 @@ class P4Sync(Command): self.updatedBranches = set() - cnt = 1 - for change in changes: - description = p4Cmd("describe %s" % change) - self.updateOptionDict(description) - - if not self.silent: - sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes))) - sys.stdout.flush() - cnt = cnt + 1 - - try: - if self.detectBranches: - branches = self.splitFilesIntoBranches(description) - for branch in branches.keys(): - ## HACK --hwn - branchPrefix = self.depotPaths[0] + branch + "/" - - parent = "" - - filesForCommit = branches[branch] - - if self.verbose: - print "branch is %s" % branch - - self.updatedBranches.add(branch) - - if branch not in self.createdBranches: - self.createdBranches.add(branch) - parent = self.knownBranches[branch] - if parent == branch: - parent = "" - elif self.verbose: - print "parent determined through known branches: %s" % parent - - # main branch? use master - if branch == "main": - branch = "master" - else: - - ## FIXME - branch = self.projectName + branch - - if parent == "main": - parent = "master" - elif len(parent) > 0: - ## FIXME - parent = self.projectName + parent - - branch = self.refPrefix + branch - if len(parent) > 0: - parent = self.refPrefix + parent - - if self.verbose: - print "looking for initial parent for %s; current parent is %s" % (branch, parent) - - if len(parent) == 0 and branch in self.initialParents: - parent = self.initialParents[branch] - del self.initialParents[branch] - - self.commit(description, filesForCommit, branch, [branchPrefix], parent) - else: - files = self.extractFilesFromCommit(description) - self.commit(description, files, self.branch, self.depotPaths, - self.initialParent) - self.initialParent = "" - except IOError: - print self.gitError.read() - sys.exit(1) + self.importChanges(changes) if not self.silent: print "" @@ -1427,7 +1430,6 @@ class P4Sync(Command): sys.stdout.write("%s " % b) sys.stdout.write("\n") - self.gitStream.close() if importProcess.wait() != 0: die("fast-import failed: %s" % self.gitError.read()) -- cgit v1.2.3 From 1c49fc197bd05a4c2ed602efcdbe277ef798813a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sun, 26 Aug 2007 16:04:34 +0200 Subject: git-p4: Cleanup; Turn self.revision into a function local variable (it's not used anywhere outside the function). Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index c00702c895..d7c5becc0e 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1285,7 +1285,7 @@ class P4Sync(Command): self.depotPaths = sorted(args) - self.revision = "" + revision = "" self.users = {} newPaths = [] @@ -1296,15 +1296,15 @@ class P4Sync(Command): if self.changeRange == "@all": self.changeRange = "" elif ',' not in self.changeRange: - self.revision = self.changeRange + revision = self.changeRange self.changeRange = "" p = p[:atIdx] elif p.find("#") != -1: hashIdx = p.index("#") - self.revision = p[hashIdx:] + revision = p[hashIdx:] p = p[:hashIdx] elif self.previousDepotPaths == []: - self.revision = "#head" + revision = "#head" p = re.sub ("\.\.\.$", "", p) if not p.endswith("/"): @@ -1345,19 +1345,19 @@ class P4Sync(Command): self.gitStream = importProcess.stdin self.gitError = importProcess.stderr - if self.revision: - print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), self.revision, self.branch) + if revision: + print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch) details = { "user" : "git perforce import user", "time" : int(time.time()) } details["desc"] = ("Initial import of %s from the state at revision %s" - % (' '.join(self.depotPaths), self.revision)) - details["change"] = self.revision + % (' '.join(self.depotPaths), revision)) + details["change"] = revision newestRevision = 0 fileCnt = 0 for info in p4CmdList("files " + ' '.join(["%s...%s" - % (p, self.revision) + % (p, revision) for p in self.depotPaths])): if info['code'] == 'error': -- cgit v1.2.3 From c208a24310582d9cf337b66f41a0d7a9fe106bb4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sun, 26 Aug 2007 16:07:18 +0200 Subject: git-p4: Cleanup; moved the code for the initial #head or revision import into a separate function, out of P4Sync.run. Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 87 ++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 42 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index d7c5becc0e..2c67190ffc 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1188,6 +1188,50 @@ class P4Sync(Command): print self.gitError.read() sys.exit(1) + def importHeadRevision(self, revision): + print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch) + + details = { "user" : "git perforce import user", "time" : int(time.time()) } + details["desc"] = ("Initial import of %s from the state at revision %s" + % (' '.join(self.depotPaths), revision)) + details["change"] = revision + newestRevision = 0 + + fileCnt = 0 + for info in p4CmdList("files " + + ' '.join(["%s...%s" + % (p, revision) + for p in self.depotPaths])): + + if info['code'] == 'error': + sys.stderr.write("p4 returned an error: %s\n" + % info['data']) + sys.exit(1) + + + change = int(info["change"]) + if change > newestRevision: + newestRevision = change + + if info["action"] == "delete": + # don't increase the file cnt, otherwise details["depotFile123"] will have gaps! + #fileCnt = fileCnt + 1 + continue + + for prop in ["depotFile", "rev", "action", "type" ]: + details["%s%s" % (prop, fileCnt)] = info[prop] + + fileCnt = fileCnt + 1 + + details["change"] = newestRevision + self.updateOptionDict(details) + try: + self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths) + except IOError: + print "IO error with git fast-import. Is your git version recent enough?" + print self.gitError.read() + + def run(self, args): self.depotPaths = [] self.changeRange = "" @@ -1346,48 +1390,7 @@ class P4Sync(Command): self.gitError = importProcess.stderr if revision: - print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch) - - details = { "user" : "git perforce import user", "time" : int(time.time()) } - details["desc"] = ("Initial import of %s from the state at revision %s" - % (' '.join(self.depotPaths), revision)) - details["change"] = revision - newestRevision = 0 - - fileCnt = 0 - for info in p4CmdList("files " - + ' '.join(["%s...%s" - % (p, revision) - for p in self.depotPaths])): - - if info['code'] == 'error': - sys.stderr.write("p4 returned an error: %s\n" - % info['data']) - sys.exit(1) - - - change = int(info["change"]) - if change > newestRevision: - newestRevision = change - - if info["action"] == "delete": - # don't increase the file cnt, otherwise details["depotFile123"] will have gaps! - #fileCnt = fileCnt + 1 - continue - - for prop in ["depotFile", "rev", "action", "type" ]: - details["%s%s" % (prop, fileCnt)] = info[prop] - - fileCnt = fileCnt + 1 - - details["change"] = newestRevision - self.updateOptionDict(details) - try: - self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths) - except IOError: - print "IO error with git fast-import. Is your git version recent enough?" - print self.gitError.read() - + self.importHeadRevision(revision) else: changes = [] -- cgit v1.2.3 From 8134f69c21ff47283d8b3ea3cc5b306727cde256 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sun, 26 Aug 2007 16:44:55 +0200 Subject: git-p4: Cleanup; moved the (duplicated) code for turning a branch into a git ref (for example foo -> refs/remotes/p4//foo) into a separate method. Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 2c67190ffc..406bec1a29 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1118,6 +1118,15 @@ class P4Sync(Command): self.keepRepoPath = (d.has_key('options') and ('keepRepoPath' in d['options'])) + def gitRefForBranch(self, branch): + if branch == "main": + return self.refPrefix + "master" + + if len(branch) <= 0: + return branch + + return self.refPrefix + self.projectName + branch + def importChanges(self, changes): cnt = 1 for change in changes: @@ -1153,23 +1162,8 @@ class P4Sync(Command): elif self.verbose: print "parent determined through known branches: %s" % parent - # main branch? use master - if branch == "main": - branch = "master" - else: - - ## FIXME - branch = self.projectName + branch - - if parent == "main": - parent = "master" - elif len(parent) > 0: - ## FIXME - parent = self.projectName + parent - - branch = self.refPrefix + branch - if len(parent) > 0: - parent = self.refPrefix + parent + branch = self.gitRefForBranch(branch) + parent = self.gitRefForBranch(parent) if self.verbose: print "looking for initial parent for %s; current parent is %s" % (branch, parent) -- cgit v1.2.3 From 1ca3d71069620f1438d9f89165a3e69e8d47d302 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sun, 26 Aug 2007 17:36:55 +0200 Subject: git-p4: Added support for automatically importing newly appearing perforce branches. If a change in a p4 "branch" appears that hasn't seen any previous commit and that has a known branch mapping we now try to import it properly. First we find the p4 change of the source branch that the new p4 branch is based on. Then we using git rev-list --bisect to locate the corresponding git commit to that change. Finally we import all changes in the new p4 branch up to the current change and resume with the regular import. Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 76 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) (limited to 'contrib') diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 406bec1a29..adaaae6633 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1127,6 +1127,67 @@ class P4Sync(Command): return self.refPrefix + self.projectName + branch + def gitCommitByP4Change(self, ref, change): + if self.verbose: + print "looking in ref " + ref + " for change %s using bisect..." % change + + earliestCommit = "" + latestCommit = parseRevision(ref) + + while True: + if self.verbose: + print "trying: earliest %s latest %s" % (earliestCommit, latestCommit) + next = read_pipe("git rev-list --bisect %s %s" % (latestCommit, earliestCommit)).strip() + if len(next) == 0: + if self.verbose: + print "argh" + return "" + log = extractLogMessageFromGitCommit(next) + settings = extractSettingsGitLog(log) + currentChange = int(settings['change']) + if self.verbose: + print "current change %s" % currentChange + + if currentChange == change: + if self.verbose: + print "found %s" % next + return next + + if currentChange < change: + earliestCommit = "^%s" % next + else: + latestCommit = "%s" % next + + return "" + + def importNewBranch(self, branch, maxChange): + # make fast-import flush all changes to disk and update the refs using the checkpoint + # command so that we can try to find the branch parent in the git history + self.gitStream.write("checkpoint\n\n"); + self.gitStream.flush(); + branchPrefix = self.depotPaths[0] + branch + "/" + range = "@1,%s" % maxChange + #print "prefix" + branchPrefix + changes = p4ChangesForPaths([branchPrefix], range) + if len(changes) <= 0: + return False + firstChange = changes[0] + #print "first change in branch: %s" % firstChange + sourceBranch = self.knownBranches[branch] + sourceDepotPath = self.depotPaths[0] + sourceBranch + sourceRef = self.gitRefForBranch(sourceBranch) + #print "source " + sourceBranch + + branchParentChange = int(p4Cmd("changes -m 1 %s...@1,%s" % (sourceDepotPath, firstChange))["change"]) + #print "branch parent: %s" % branchParentChange + gitParent = self.gitCommitByP4Change(sourceRef, branchParentChange) + if len(gitParent) > 0: + self.initialParents[self.gitRefForBranch(branch)] = gitParent + #print "parent git commit: %s" % gitParent + + self.importChanges(changes) + return True + def importChanges(self, changes): cnt = 1 for change in changes: @@ -1159,8 +1220,19 @@ class P4Sync(Command): parent = self.knownBranches[branch] if parent == branch: parent = "" - elif self.verbose: - print "parent determined through known branches: %s" % parent + else: + fullBranch = self.projectName + branch + if fullBranch not in self.p4BranchesInGit: + if not self.silent: + print("\n Importing new branch %s" % fullBranch); + if self.importNewBranch(branch, change - 1): + parent = "" + self.p4BranchesInGit.append(fullBranch) + if not self.silent: + print("\n Resuming with change %s" % change); + + if self.verbose: + print "parent determined through known branches: %s" % parent branch = self.gitRefForBranch(branch) parent = self.gitRefForBranch(parent) -- cgit v1.2.3