@@ -133,7 +133,7 @@ class ProcessException(Exception):
133
133
134
134
def popen (command , stdin = None , ** kwargs ):
135
135
# print for debugging
136
- log ('Exec "' + ' ' .join (command )+ '"" in ' + os .getcwd ())
136
+ log ('Exec "' + ' ' .join (command )+ '" in ' + os .getcwd ())
137
137
try :
138
138
proc = subprocess .Popen (command , ** kwargs )
139
139
except OSError as e :
@@ -148,7 +148,8 @@ def popen(command, stdin=None, **kwargs):
148
148
raise ProcessException (proc .returncode , command [0 ], ' ' .join (command ), os .getcwd ())
149
149
150
150
def pquery (command , stdin = None , ** kwargs ):
151
- log ('Query "' + ' ' .join (command )+ '" in ' + os .getcwd ())
151
+ if very_verbose :
152
+ log ('Query "' + ' ' .join (command )+ '" in ' + os .getcwd ())
152
153
try :
153
154
proc = subprocess .Popen (command , stdout = subprocess .PIPE , stderr = subprocess .PIPE , ** kwargs )
154
155
except OSError as e :
@@ -228,7 +229,7 @@ def clone(url, name=None, hash=None, depth=None, protocol=None):
228
229
if hash :
229
230
with cd (name ):
230
231
try :
231
- popen ([ hg_cmd , 'checkout' , hash ] + ([ '-v' ] if verbose else [ '-q' ]) )
232
+ Hg . checkout ( None , hash )
232
233
except ProcessException :
233
234
error ("Unable to update to revision \" %s\" " % hash , 1 )
234
235
@@ -260,8 +261,9 @@ def fetch(repo):
260
261
log ("Pulling remote repository \" %s\" to local \" %s\" " % (repo .url , repo .name ))
261
262
popen ([hg_cmd , 'pull' ] + (['-v' ] if verbose else ['-q' ]))
262
263
263
- def checkout (repo , hash = None , clean = False ):
264
- log ("Checkout \" %s\" to %s" % (repo .name , repo .hashtype (hash , True )))
264
+ def checkout (repo , hash , clean = False ):
265
+ if repo :
266
+ log ("Checkout \" %s\" to %s" % (repo .name , repo .hashtype (hash , True )))
265
267
popen ([hg_cmd , 'update' ] + (['-r' , hash ] if hash else []) + (['-C' ] if clean else []) + (['-v' ] if verbose else ['-q' ]))
266
268
267
269
def update (repo , hash = None , clean = False ):
@@ -416,7 +418,7 @@ def clone(url, name=None, hash=None, depth=None, protocol=None):
416
418
if hash :
417
419
with cd (name ):
418
420
try :
419
- popen ([ git_cmd , 'checkout' , '-q' , hash ] + ([] if verbose else [ '-q' ]) )
421
+ Git . checkout ( None , hash )
420
422
except ProcessException :
421
423
error ("Unable to update to revision \" %s\" " % hash , 1 )
422
424
@@ -466,9 +468,16 @@ def discard(repo):
466
468
popen ([git_cmd , 'checkout' , '.' ] + ([] if verbose else ['-q' ])) # undo modified files
467
469
popen ([git_cmd , 'clean' , '-fdq' ] + ([] if verbose else ['-q' ])) # cleans up untracked files and folders
468
470
469
- def checkout (repo , hash = None , clean = False ):
470
- log ("Checkout \" %s\" to %s" % (repo .name , repo .hashtype (hash , True )))
471
+ def checkout (repo , hash , clean = False ):
472
+ if repo :
473
+ log ("Checkout \" %s\" to %s" % (repo .name , repo .hashtype (hash , True )))
471
474
popen ([git_cmd , 'checkout' , hash ] + ([] if verbose else ['-q' ]))
475
+ if Git .isdetached (): # try to find associated refs to avoid detached state
476
+ refs = Git .getrefs (hash )
477
+ for ref in refs : # re-associate with a local or remote branch (hash is the same)
478
+ log ("Hash \" %s\" match a branch reference. Re-associating with branch (it's the same hash)" % hash )
479
+ popen ([git_cmd , 'checkout' , re .sub (r'^(.*?)\/(.*?)$' , r'\2' , ref )] + ([] if verbose else ['-q' ]))
480
+ break
472
481
473
482
def update (repo , hash = None , clean = False ):
474
483
if clean :
@@ -523,7 +532,7 @@ def outgoing():
523
532
524
533
# Checks whether current working tree is detached
525
534
def isdetached ():
526
- return Git .getbranch () == "HEAD"
535
+ return True if Git .getbranch () == "" else False
527
536
528
537
# Finds default remote
529
538
def getremote ():
@@ -559,11 +568,33 @@ def geturl(repo):
559
568
def gethash (repo ):
560
569
return pquery ([git_cmd , 'rev-parse' , 'HEAD' ]).strip ()
561
570
562
- # Finds current branch or returns empty string if detached
571
+ # Gets current branch or returns empty string if detached
563
572
def getbranch ():
564
573
branch = pquery ([git_cmd , 'rev-parse' , '--symbolic-full-name' , '--abbrev-ref' , 'HEAD' ]).strip ()
565
574
return branch if branch != "HEAD" else ""
566
575
576
+ # Finds refs (local or remote branches). Will match hash if specified
577
+ def getrefs (hash = None , ret_hash = False ):
578
+ result = []
579
+ lines = pquery ([git_cmd , 'show-ref' ]).strip ().splitlines ()
580
+ for line in lines :
581
+ m = re .match (r'^(.+)\s+(.+)$' , line )
582
+ if m and (not hash or m .group (1 ).startswith (hash )):
583
+ if re .match (r'refs\/(heads|remotes)\/' , m .group (2 )): # exclude tags
584
+ result .append (m .group (1 ) if ret_hash else re .sub (r'refs\/(heads|remotes)\/' , '' , m .group (2 )))
585
+ return result
586
+
587
+ # Finds branches a hash belongs to
588
+ def hashbranches (hash ):
589
+ branches = []
590
+ lines = pquery ([git_cmd , 'branch' , '-a' , '--contains' ] + ([hash ] if hash else [])).strip ().splitlines ()
591
+ for line in lines :
592
+ if re .match (r'^\*?\s+\((.+)\)$' , line ):
593
+ continue
594
+ line = re .sub (r'\s+' , '' , line )
595
+ branches .append (line )
596
+ return branches
597
+
567
598
def ignores (repo ):
568
599
with open (os .path .join (repo .path , '.git/info/exclude' ), 'w' ) as f :
569
600
f .write ('\n ' .join (ignores )+ '\n ' )
0 commit comments