@@ -553,29 +553,49 @@ def gitConfigList(key):
553
553
_gitConfig [key ] = read_pipe ("git config --get-all %s" % key , ignore_error = True ).strip ().split (os .linesep )
554
554
return _gitConfig [key ]
555
555
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
+
557
563
branches = {}
558
564
559
565
cmdline = "git rev-parse --symbolic "
560
566
if branchesAreInRemotes :
561
- cmdline += " --remotes"
567
+ cmdline += "--remotes"
562
568
else :
563
- cmdline += " --branches"
569
+ cmdline += "--branches"
564
570
565
571
for line in read_pipe_lines (cmdline ):
566
572
line = line .strip ()
567
573
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" :
570
579
continue
571
- branch = line
572
580
573
- # strip off p4
574
- branch = re . sub ( "^ p4/", "" , line )
581
+ # strip off p4/ prefix
582
+ branch = line [ len ( " p4/"):]
575
583
576
584
branches [branch ] = parseRevision (line )
585
+
577
586
return branches
578
587
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
+
579
599
def findUpstreamBranchPoint (head = "HEAD" ):
580
600
branches = p4BranchesInGit ()
581
601
# map from depot-path to branch name
@@ -907,7 +927,8 @@ def __init__(self):
907
927
optparse .make_option ("--dry-run" , "-n" , dest = "dry_run" , action = "store_true" ),
908
928
optparse .make_option ("--prepare-p4-only" , dest = "prepare_p4_only" , action = "store_true" ),
909
929
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" ),
911
932
]
912
933
self .description = "Submit changes from git to the perforce depot."
913
934
self .usage += " [name of git branch to submit into perforce depot]"
@@ -920,6 +941,7 @@ def __init__(self):
920
941
self .isWindows = (platform .system () == "Windows" )
921
942
self .exportLabels = False
922
943
self .p4HasMoveCommand = p4_has_move_command ()
944
+ self .branch = None
923
945
924
946
def check (self ):
925
947
if len (p4CmdList ("opened ..." )) > 0 :
@@ -1656,6 +1678,8 @@ def run(self, args):
1656
1678
print "All commits applied!"
1657
1679
1658
1680
sync = P4Sync ()
1681
+ if self .branch :
1682
+ sync .branch = self .branch
1659
1683
sync .run ([])
1660
1684
1661
1685
rebase = P4Rebase ()
@@ -2509,13 +2533,6 @@ def getBranchMappingFromGitBranches(self):
2509
2533
branch = branch [len (self .projectName ):]
2510
2534
self .knownBranches [branch ] = branch
2511
2535
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
-
2519
2536
def updateOptionDict (self , d ):
2520
2537
option_keys = {}
2521
2538
if self .keepRepoPath :
@@ -2687,6 +2704,7 @@ def importChanges(self, changes):
2687
2704
files = self .extractFilesFromCommit (description )
2688
2705
self .commit (description , files , self .branch ,
2689
2706
self .initialParent )
2707
+ # only needed once, to connect to the previous commit
2690
2708
self .initialParent = ""
2691
2709
except IOError :
2692
2710
print self .gitError .read ()
@@ -2752,34 +2770,31 @@ def importHeadRevision(self, revision):
2752
2770
def run (self , args ):
2753
2771
self .depotPaths = []
2754
2772
self .changeRange = ""
2755
- self .initialParent = ""
2756
2773
self .previousDepotPaths = []
2774
+ self .hasOrigin = False
2757
2775
2758
2776
# map from branch depot path to parent branch
2759
2777
self .knownBranches = {}
2760
2778
self .initialParents = {}
2761
- self .hasOrigin = originP4BranchesExist ()
2762
- if not self .syncWithOrigin :
2763
- self .hasOrigin = False
2764
2779
2765
2780
if self .importIntoRemotes :
2766
2781
self .refPrefix = "refs/remotes/p4/"
2767
2782
else :
2768
2783
self .refPrefix = "refs/heads/p4/"
2769
2784
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" )
2774
2791
2792
+ branch_arg_given = bool (self .branch )
2775
2793
if len (self .branch ) == 0 :
2776
2794
self .branch = self .refPrefix + "master"
2777
2795
if gitBranchExists ("refs/heads/p4" ) and self .importIntoRemotes :
2778
2796
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" )
2783
2798
2784
2799
# accept either the command-line option, or the configuration variable
2785
2800
if self .useClientSpec :
@@ -2796,12 +2811,25 @@ def run(self, args):
2796
2811
if args == []:
2797
2812
if self .hasOrigin :
2798
2813
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 ()
2800
2825
2801
2826
if len (self .p4BranchesInGit ) > 1 :
2802
2827
if not self .silent :
2803
2828
print "Importing from/into multiple branches"
2804
2829
self .detectBranches = True
2830
+ for branch in branches .keys ():
2831
+ self .initialParents [self .refPrefix + branch ] = \
2832
+ branches [branch ]
2805
2833
2806
2834
if self .verbose :
2807
2835
print "branches: %s" % self .p4BranchesInGit
@@ -2838,13 +2866,21 @@ def run(self, args):
2838
2866
if p4Change > 0 :
2839
2867
self .depotPaths = sorted (self .previousDepotPaths )
2840
2868
self .changeRange = "@%s,#head" % p4Change
2841
- if not self .detectBranches :
2842
- self .initialParent = parseRevision (self .branch )
2843
2869
if not self .silent and not self .detectBranches :
2844
2870
print "Performing incremental import into %s git branch" % self .branch
2845
2871
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/
2846
2876
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
2848
2884
2849
2885
if len (args ) == 0 and self .depotPaths :
2850
2886
if not self .silent :
@@ -2955,8 +2991,21 @@ def run(self, args):
2955
2991
else :
2956
2992
# catch "git p4 sync" with no new branches, in a repo that
2957
2993
# 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
+
2960
3009
if self .verbose :
2961
3010
print "Getting p4 changes for %s...%s" % (', ' .join (self .depotPaths ),
2962
3011
self .changeRange )
@@ -2974,6 +3023,14 @@ def run(self, args):
2974
3023
2975
3024
self .updatedBranches = set ()
2976
3025
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
+
2977
3034
self .importChanges (changes )
2978
3035
2979
3036
if not self .silent :
@@ -3006,6 +3063,13 @@ def run(self, args):
3006
3063
read_pipe ("git update-ref -d %s" % branch )
3007
3064
os .rmdir (os .path .join (os .environ .get ("GIT_DIR" , ".git" ), self .tempBranchLocation ))
3008
3065
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
+
3009
3073
return True
3010
3074
3011
3075
class P4Rebase (Command ):
@@ -3113,17 +3177,15 @@ def run(self, args):
3113
3177
3114
3178
if not P4Sync .run (self , depotPaths ):
3115
3179
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>"'
3127
3189
3128
3190
# auto-set this variable if invoked with --use-client-spec
3129
3191
if self .useClientSpec_from_options :
0 commit comments