Skip to content

Commit e51858f

Browse files
committed
Git.getrefs() finds all references or subset of references associated with a hash if specified. This is used to checkout/associate a branch if the hash matches the branch reference (the tip) and prevent detached mode
1 parent a01e44b commit e51858f

File tree

1 file changed

+41
-10
lines changed

1 file changed

+41
-10
lines changed

mbed/mbed.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class ProcessException(Exception):
133133

134134
def popen(command, stdin=None, **kwargs):
135135
# print for debugging
136-
log('Exec "'+' '.join(command)+'"" in '+os.getcwd())
136+
log('Exec "'+' '.join(command)+'" in '+os.getcwd())
137137
try:
138138
proc = subprocess.Popen(command, **kwargs)
139139
except OSError as e:
@@ -148,7 +148,8 @@ def popen(command, stdin=None, **kwargs):
148148
raise ProcessException(proc.returncode, command[0], ' '.join(command), os.getcwd())
149149

150150
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())
152153
try:
153154
proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
154155
except OSError as e:
@@ -228,7 +229,7 @@ def clone(url, name=None, hash=None, depth=None, protocol=None):
228229
if hash:
229230
with cd(name):
230231
try:
231-
popen([hg_cmd, 'checkout', hash] + (['-v'] if verbose else ['-q']))
232+
Hg.checkout(None, hash)
232233
except ProcessException:
233234
error("Unable to update to revision \"%s\"" % hash, 1)
234235

@@ -260,8 +261,9 @@ def fetch(repo):
260261
log("Pulling remote repository \"%s\" to local \"%s\"" % (repo.url, repo.name))
261262
popen([hg_cmd, 'pull'] + (['-v'] if verbose else ['-q']))
262263

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)))
265267
popen([hg_cmd, 'update'] + (['-r', hash] if hash else []) + (['-C'] if clean else []) + (['-v'] if verbose else ['-q']))
266268

267269
def update(repo, hash=None, clean=False):
@@ -416,7 +418,7 @@ def clone(url, name=None, hash=None, depth=None, protocol=None):
416418
if hash:
417419
with cd(name):
418420
try:
419-
popen([git_cmd, 'checkout', '-q', hash] + ([] if verbose else ['-q']))
421+
Git.checkout(None, hash)
420422
except ProcessException:
421423
error("Unable to update to revision \"%s\"" % hash, 1)
422424

@@ -466,9 +468,16 @@ def discard(repo):
466468
popen([git_cmd, 'checkout', '.'] + ([] if verbose else ['-q'])) # undo modified files
467469
popen([git_cmd, 'clean', '-fdq'] + ([] if verbose else ['-q'])) # cleans up untracked files and folders
468470

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)))
471474
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
472481

473482
def update(repo, hash=None, clean=False):
474483
if clean:
@@ -523,7 +532,7 @@ def outgoing():
523532

524533
# Checks whether current working tree is detached
525534
def isdetached():
526-
return Git.getbranch() == "HEAD"
535+
return True if Git.getbranch() == "" else False
527536

528537
# Finds default remote
529538
def getremote():
@@ -559,11 +568,33 @@ def geturl(repo):
559568
def gethash(repo):
560569
return pquery([git_cmd, 'rev-parse', 'HEAD']).strip()
561570

562-
# Finds current branch or returns empty string if detached
571+
# Gets current branch or returns empty string if detached
563572
def getbranch():
564573
branch = pquery([git_cmd, 'rev-parse', '--symbolic-full-name', '--abbrev-ref', 'HEAD']).strip()
565574
return branch if branch != "HEAD" else ""
566575

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+
567598
def ignores(repo):
568599
with open(os.path.join(repo.path, '.git/info/exclude'), 'w') as f:
569600
f.write('\n'.join(ignores)+'\n')

0 commit comments

Comments
 (0)