1306
return LargeFileSystem.processContent(self, git_mode, relPath, contents)
1307
1308
class Command:
1309
+ delete_actions = ( "delete", "move/delete", "purge" )
1310
+ add_actions = ( "add", "move/add" )
1311
+
1312
def __init__(self):
1313
self.usage = "usage: %prog [options]"
1314
self.needsGit = True
2527
return ""
2528
2529
class P4Sync(Command, P4UserMap):
2527
- delete_actions = ( "delete", "move/delete", "purge" )
2530
2531
def __init__(self):
2532
Command.__init__(self)
2614
if self.verbose:
2615
print("checkpoint finished: " + out)
2616
2615
- def cmp_shelved(self, path, filerev, revision):
2616
- """ Determine if a path at revision #filerev is the same as the file
2617
- at revision @revision for a shelved changelist. If they don't match,
2618
- unshelving won't be safe (we will get other changes mixed in).
2619
-
2620
- This is comparing the revision that the shelved changelist is *based* on, not
2621
- the shelved changelist itself.
2622
- """
2623
- ret = p4Cmd(["diff2", "{0}#{1}".format(path, filerev), "{0}@{1}".format(path, revision)])
2624
- if verbose:
2625
- print("p4 diff2 path %s filerev %s revision %s => %s" % (path, filerev, revision, ret))
2626
- return ret["status"] == "identical"
2627
-
2628
- def extractFilesFromCommit(self, commit, shelved=False, shelved_cl = 0, origin_revision = 0):
2617
+ def extractFilesFromCommit(self, commit, shelved=False, shelved_cl = 0):
2618
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
2619
for path in self.cloneExclude]
2620
files = []
2639
file["type"] = commit["type%s" % fnum]
2640
if shelved:
2641
file["shelved_cl"] = int(shelved_cl)
2653
-
2654
- # For shelved changelists, check that the revision of each file that the
2655
- # shelve was based on matches the revision that we are using for the
2656
- # starting point for git-fast-import (self.initialParent). Otherwise
2657
- # the resulting diff will contain deltas from multiple commits.
2658
-
2659
- if file["action"] != "add" and \
2660
- not self.cmp_shelved(path, file["rev"], origin_revision):
2661
- sys.exit("change {0} not based on {1} for {2}, cannot unshelve".format(
2662
- commit["change"], self.initialParent, path))
2663
-
2642
files.append(file)
2643
fnum = fnum + 1
2644
return files
3010
print('Ignoring file outside of prefix: {0}'.format(path))
3011
return hasPrefix
3012
3035
- def commit(self, details, files, branch, parent = ""):
3013
+ def commit(self, details, files, branch, parent = "", allow_empty=False):
3014
epoch = details["time"]
3015
author = details["user"]
3016
jobs = self.extractJobsFromCommit(details)
3024
files = [f for f in files
3025
if self.inClientSpec(f['path']) and self.hasBranchPrefix(f['path'])]
3026
3049
- if not files and not gitConfigBool('git-p4.keepEmptyCommits'):
3027
+ if gitConfigBool('git-p4.keepEmptyCommits'):
3028
+ allow_empty = True
3029
+
3030
+ if not files and not allow_empty:
3031
print('Ignoring revision {0} as it would produce an empty commit.'
3032
.format(details['change']))
3033
return
3368
else:
3369
return None
3370
3390
- def importChanges(self, changes, shelved=False, origin_revision=0):
3371
+ def importChanges(self, changes, origin_revision=0):
3372
cnt = 1
3373
for change in changes:
3393
- description = p4_describe(change, shelved)
3374
+ description = p4_describe(change)
3375
self.updateOptionDict(description)
3376
3377
if not self.silent:
3441
print("Parent of %s not found. Committing into head of %s" % (branch, parent))
3442
self.commit(description, filesForCommit, branch, parent)
3443
else:
3463
- files = self.extractFilesFromCommit(description, shelved, change, origin_revision)
3444
+ files = self.extractFilesFromCommit(description)
3445
self.commit(description, files, self.branch,
3446
self.initialParent)
3447
# only needed once, to connect to the previous commit
3938
self.verbose = False
3939
self.noCommit = False
3940
self.destbranch = "refs/remotes/p4-unshelved"
3960
- self.origin = "p4/master"
3941
3942
def renameBranch(self, branch_name):
3943
""" Rename the existing branch to branch_name.N
3969
3970
sys.exit("could not find git-p4 commits in {0}".format(self.origin))
3971
3972
+ def createShelveParent(self, change, branch_name, sync, origin):
3973
+ """ Create a commit matching the parent of the shelved changelist 'change'
3974
+ """
3975
+ parent_description = p4_describe(change, shelved=True)
3976
+ parent_description['desc'] = 'parent for shelved changelist {}\n'.format(change)
3977
+ files = sync.extractFilesFromCommit(parent_description, shelved=False, shelved_cl=change)
3978
+
3979
+ parent_files = []
3980
+ for f in files:
3981
+ # if it was added in the shelved changelist, it won't exist in the parent
3982
+ if f['action'] in self.add_actions:
3983
+ continue
3984
+
3985
+ # if it was deleted in the shelved changelist it must not be deleted
3986
+ # in the parent - we might even need to create it if the origin branch
3987
+ # does not have it
3988
+ if f['action'] in self.delete_actions:
3989
+ f['action'] = 'add'
3990
+
3991
+ parent_files.append(f)
3992
+
3993
+ sync.commit(parent_description, parent_files, branch_name,
3994
+ parent=origin, allow_empty=True)
3995
+ print("created parent commit for {0} based on {1} in {2}".format(
3996
+ change, self.origin, branch_name))
3997
+
3998
def run(self, args):
3999
if len(args) != 1:
4000
return False
4004
4005
sync = P4Sync()
4006
changes = args
4001
- sync.initialParent = self.origin
4007
4003
- # use the first change in the list to construct the branch to unshelve into
4008
+ # only one change at a time
4009
change = changes[0]
4010
4011
# if the target branch already exists, rename it
4018
sync.suppress_meta_comment = True
4019
4020
settings = self.findLastP4Revision(self.origin)
4016
- origin_revision = settings['change']
4021
sync.depotPaths = settings['depot-paths']
4022
sync.branchPrefixes = sync.depotPaths
4023
4024
sync.openStreams()
4025
sync.loadUserMapFromCache()
4026
sync.silent = True
4023
- sync.importChanges(changes, shelved=True, origin_revision=origin_revision)
4027
+
4028
+ # create a commit for the parent of the shelved changelist
4029
+ self.createShelveParent(change, branch_name, sync, self.origin)
4030
+
4031
+ # create the commit for the shelved changelist itself
4032
+ description = p4_describe(change, True)
4033
+ files = sync.extractFilesFromCommit(description, True, change)
4034
+
4035
+ sync.commit(description, files, branch_name, "")
4036
sync.closeStreams()
4037
4038
print("unshelved changelist {0} into {1}".format(change, branch_name))