@@ -553,29 +553,49 @@ def gitConfigList(key):
553553 _gitConfig [key ] = read_pipe ("git config --get-all %s" % key , ignore_error = True ).strip ().split (os .linesep )
554554 return _gitConfig [key ]
555555
556- def p4BranchesInGit (branchesAreInRemotes = True ):
556+ def p4BranchesInGit (branchesAreInRemotes = True ):
557+ """Find all the branches whose names start with "p4/", looking
558+ in remotes or heads as specified by the argument. Return
559+ a dictionary of { branch: revision } for each one found.
560+ The branch names are the short names, without any
561+ "p4/" prefix."""
562+
557563 branches = {}
558564
559565 cmdline = "git rev-parse --symbolic "
560566 if branchesAreInRemotes :
561- cmdline += " --remotes"
567+ cmdline += "--remotes"
562568 else :
563- cmdline += " --branches"
569+ cmdline += "--branches"
564570
565571 for line in read_pipe_lines (cmdline ):
566572 line = line .strip ()
567573
568- ## only import to p4/
569- if not line .startswith ('p4/' ) or line == "p4/HEAD" :
574+ # only import to p4/
575+ if not line .startswith ('p4/' ):
576+ continue
577+ # special symbolic ref to p4/master
578+ if line == "p4/HEAD" :
570579 continue
571- branch = line
572580
573- # strip off p4
574- branch = re . sub ( "^ p4/", "" , line )
581+ # strip off p4/ prefix
582+ branch = line [ len ( " p4/"):]
575583
576584 branches [branch ] = parseRevision (line )
585+
577586 return branches
578587
588+ def branch_exists (branch ):
589+ """Make sure that the given ref name really exists."""
590+
591+ cmd = [ "git" , "rev-parse" , "--symbolic" , "--verify" , branch ]
592+ p = subprocess .Popen (cmd , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
593+ out , _ = p .communicate ()
594+ if p .returncode :
595+ return False
596+ # expect exactly one line of output: the branch name
597+ return out .rstrip () == branch
598+
579599def findUpstreamBranchPoint (head = "HEAD" ):
580600 branches = p4BranchesInGit ()
581601 # map from depot-path to branch name
@@ -907,7 +927,8 @@ def __init__(self):
907927 optparse .make_option ("--dry-run" , "-n" , dest = "dry_run" , action = "store_true" ),
908928 optparse .make_option ("--prepare-p4-only" , dest = "prepare_p4_only" , action = "store_true" ),
909929 optparse .make_option ("--conflict" , dest = "conflict_behavior" ,
910- choices = self .conflict_behavior_choices )
930+ choices = self .conflict_behavior_choices ),
931+ optparse .make_option ("--branch" , dest = "branch" ),
911932 ]
912933 self .description = "Submit changes from git to the perforce depot."
913934 self .usage += " [name of git branch to submit into perforce depot]"
@@ -920,6 +941,7 @@ def __init__(self):
920941 self .isWindows = (platform .system () == "Windows" )
921942 self .exportLabels = False
922943 self .p4HasMoveCommand = p4_has_move_command ()
944+ self .branch = None
923945
924946 def check (self ):
925947 if len (p4CmdList ("opened ..." )) > 0 :
@@ -1656,6 +1678,8 @@ def run(self, args):
16561678 print "All commits applied!"
16571679
16581680 sync = P4Sync ()
1681+ if self .branch :
1682+ sync .branch = self .branch
16591683 sync .run ([])
16601684
16611685 rebase = P4Rebase ()
@@ -2509,13 +2533,6 @@ def getBranchMappingFromGitBranches(self):
25092533 branch = branch [len (self .projectName ):]
25102534 self .knownBranches [branch ] = branch
25112535
2512- def listExistingP4GitBranches (self ):
2513- # branches holds mapping from name to commit
2514- branches = p4BranchesInGit (self .importIntoRemotes )
2515- self .p4BranchesInGit = branches .keys ()
2516- for branch in branches .keys ():
2517- self .initialParents [self .refPrefix + branch ] = branches [branch ]
2518-
25192536 def updateOptionDict (self , d ):
25202537 option_keys = {}
25212538 if self .keepRepoPath :
@@ -2687,6 +2704,7 @@ def importChanges(self, changes):
26872704 files = self .extractFilesFromCommit (description )
26882705 self .commit (description , files , self .branch ,
26892706 self .initialParent )
2707+ # only needed once, to connect to the previous commit
26902708 self .initialParent = ""
26912709 except IOError :
26922710 print self .gitError .read ()
@@ -2752,34 +2770,31 @@ def importHeadRevision(self, revision):
27522770 def run (self , args ):
27532771 self .depotPaths = []
27542772 self .changeRange = ""
2755- self .initialParent = ""
27562773 self .previousDepotPaths = []
2774+ self .hasOrigin = False
27572775
27582776 # map from branch depot path to parent branch
27592777 self .knownBranches = {}
27602778 self .initialParents = {}
2761- self .hasOrigin = originP4BranchesExist ()
2762- if not self .syncWithOrigin :
2763- self .hasOrigin = False
27642779
27652780 if self .importIntoRemotes :
27662781 self .refPrefix = "refs/remotes/p4/"
27672782 else :
27682783 self .refPrefix = "refs/heads/p4/"
27692784
2770- if self .syncWithOrigin and self .hasOrigin :
2771- if not self .silent :
2772- print "Syncing with origin first by calling git fetch origin"
2773- system ("git fetch origin" )
2785+ if self .syncWithOrigin :
2786+ self .hasOrigin = originP4BranchesExist ()
2787+ if self .hasOrigin :
2788+ if not self .silent :
2789+ print 'Syncing with origin first, using "git fetch origin"'
2790+ system ("git fetch origin" )
27742791
2792+ branch_arg_given = bool (self .branch )
27752793 if len (self .branch ) == 0 :
27762794 self .branch = self .refPrefix + "master"
27772795 if gitBranchExists ("refs/heads/p4" ) and self .importIntoRemotes :
27782796 system ("git update-ref %s refs/heads/p4" % self .branch )
2779- system ("git branch -D p4" );
2780- # create it /after/ importing, when master exists
2781- if not gitBranchExists (self .refPrefix + "HEAD" ) and self .importIntoRemotes and gitBranchExists (self .branch ):
2782- system ("git symbolic-ref %sHEAD %s" % (self .refPrefix , self .branch ))
2797+ system ("git branch -D p4" )
27832798
27842799 # accept either the command-line option, or the configuration variable
27852800 if self .useClientSpec :
@@ -2796,12 +2811,25 @@ def run(self, args):
27962811 if args == []:
27972812 if self .hasOrigin :
27982813 createOrUpdateBranchesFromOrigin (self .refPrefix , self .silent )
2799- self .listExistingP4GitBranches ()
2814+
2815+ # branches holds mapping from branch name to sha1
2816+ branches = p4BranchesInGit (self .importIntoRemotes )
2817+
2818+ # restrict to just this one, disabling detect-branches
2819+ if branch_arg_given :
2820+ short = self .branch .split ("/" )[- 1 ]
2821+ if short in branches :
2822+ self .p4BranchesInGit = [ short ]
2823+ else :
2824+ self .p4BranchesInGit = branches .keys ()
28002825
28012826 if len (self .p4BranchesInGit ) > 1 :
28022827 if not self .silent :
28032828 print "Importing from/into multiple branches"
28042829 self .detectBranches = True
2830+ for branch in branches .keys ():
2831+ self .initialParents [self .refPrefix + branch ] = \
2832+ branches [branch ]
28052833
28062834 if self .verbose :
28072835 print "branches: %s" % self .p4BranchesInGit
@@ -2838,13 +2866,21 @@ def run(self, args):
28382866 if p4Change > 0 :
28392867 self .depotPaths = sorted (self .previousDepotPaths )
28402868 self .changeRange = "@%s,#head" % p4Change
2841- if not self .detectBranches :
2842- self .initialParent = parseRevision (self .branch )
28432869 if not self .silent and not self .detectBranches :
28442870 print "Performing incremental import into %s git branch" % self .branch
28452871
2872+ # accept multiple ref name abbreviations:
2873+ # refs/foo/bar/branch -> use it exactly
2874+ # p4/branch -> prepend refs/remotes/ or refs/heads/
2875+ # branch -> prepend refs/remotes/p4/ or refs/heads/p4/
28462876 if not self .branch .startswith ("refs/" ):
2847- self .branch = "refs/heads/" + self .branch
2877+ if self .importIntoRemotes :
2878+ prepend = "refs/remotes/"
2879+ else :
2880+ prepend = "refs/heads/"
2881+ if not self .branch .startswith ("p4/" ):
2882+ prepend += "p4/"
2883+ self .branch = prepend + self .branch
28482884
28492885 if len (args ) == 0 and self .depotPaths :
28502886 if not self .silent :
@@ -2955,8 +2991,21 @@ def run(self, args):
29552991 else :
29562992 # catch "git p4 sync" with no new branches, in a repo that
29572993 # does not have any existing p4 branches
2958- if len (args ) == 0 and not self .p4BranchesInGit :
2959- die ("No remote p4 branches. Perhaps you never did \" git p4 clone\" in here." );
2994+ if len (args ) == 0 :
2995+ if not self .p4BranchesInGit :
2996+ die ("No remote p4 branches. Perhaps you never did \" git p4 clone\" in here." )
2997+
2998+ # The default branch is master, unless --branch is used to
2999+ # specify something else. Make sure it exists, or complain
3000+ # nicely about how to use --branch.
3001+ if not self .detectBranches :
3002+ if not branch_exists (self .branch ):
3003+ if branch_arg_given :
3004+ die ("Error: branch %s does not exist." % self .branch )
3005+ else :
3006+ die ("Error: no branch %s; perhaps specify one with --branch." %
3007+ self .branch )
3008+
29603009 if self .verbose :
29613010 print "Getting p4 changes for %s...%s" % (', ' .join (self .depotPaths ),
29623011 self .changeRange )
@@ -2974,6 +3023,14 @@ def run(self, args):
29743023
29753024 self .updatedBranches = set ()
29763025
3026+ if not self .detectBranches :
3027+ if args :
3028+ # start a new branch
3029+ self .initialParent = ""
3030+ else :
3031+ # build on a previous revision
3032+ self .initialParent = parseRevision (self .branch )
3033+
29773034 self .importChanges (changes )
29783035
29793036 if not self .silent :
@@ -3006,6 +3063,13 @@ def run(self, args):
30063063 read_pipe ("git update-ref -d %s" % branch )
30073064 os .rmdir (os .path .join (os .environ .get ("GIT_DIR" , ".git" ), self .tempBranchLocation ))
30083065
3066+ # Create a symbolic ref p4/HEAD pointing to p4/<branch> to allow
3067+ # a convenient shortcut refname "p4".
3068+ if self .importIntoRemotes :
3069+ head_ref = self .refPrefix + "HEAD"
3070+ if not gitBranchExists (head_ref ) and gitBranchExists (self .branch ):
3071+ system (["git" , "symbolic-ref" , head_ref , self .branch ])
3072+
30093073 return True
30103074
30113075class P4Rebase (Command ):
@@ -3113,17 +3177,15 @@ def run(self, args):
31133177
31143178 if not P4Sync .run (self , depotPaths ):
31153179 return False
3116- if self .branch != "master" :
3117- if self .importIntoRemotes :
3118- masterbranch = "refs/remotes/p4/master"
3119- else :
3120- masterbranch = "refs/heads/p4/master"
3121- if gitBranchExists (masterbranch ):
3122- system ("git branch master %s" % masterbranch )
3123- if not self .cloneBare :
3124- system ("git checkout -f" )
3125- else :
3126- print "Could not detect main branch. No checkout/master branch created."
3180+
3181+ # create a master branch and check out a work tree
3182+ if gitBranchExists (self .branch ):
3183+ system ([ "git" , "branch" , "master" , self .branch ])
3184+ if not self .cloneBare :
3185+ system ([ "git" , "checkout" , "-f" ])
3186+ else :
3187+ print 'Not checking out any branch, use ' \
3188+ '"git checkout -q -b master <branch>"'
31273189
31283190 # auto-set this variable if invoked with --use-client-spec
31293191 if self .useClientSpec_from_options :
0 commit comments