Chromium Code Reviews| Index: git_common.py |
| diff --git a/git_common.py b/git_common.py |
| index 4a430c609cbec773edeba785729e30591f857dcc..5923b0b38d20b59e2f86b4f06e8d9f359a14552b 100644 |
| --- a/git_common.py |
| +++ b/git_common.py |
| @@ -91,6 +91,9 @@ GIT_TRANSIENT_ERRORS = ( |
| GIT_TRANSIENT_ERRORS_RE = re.compile('|'.join(GIT_TRANSIENT_ERRORS), |
| re.IGNORECASE) |
| +# First version where the for-each-ref command's format string supported the |
| +# upstream:track token. |
| +MIN_UPSTREAM_TRACK_GIT_VERSION = (1, 9) |
| class BadCommitRefException(Exception): |
| def __init__(self, refs): |
| @@ -436,8 +439,11 @@ def hash_multi(*reflike): |
| return run('rev-parse', *reflike).splitlines() |
| -def hash_one(reflike): |
| - return run('rev-parse', reflike) |
| +def hash_one(reflike, short=False): |
| + args = ['rev-parse', reflike] |
| + if short: |
| + args.insert(1, '--short') |
| + return run(*args) |
| def in_rebase(): |
| @@ -716,3 +722,46 @@ def upstream(branch): |
| branch+'@{upstream}') |
| except subprocess2.CalledProcessError: |
| return None |
| + |
| +def get_git_version(): |
| + """Returns a tuple that contains the numeric components of the current git |
| + version.""" |
| + version_string = run('--version') |
| + version_match = re.search(r'(\d+.)+(\d+)', version_string) |
| + version = version_match.group() if version_match else '' |
| + |
| + return tuple(int(x) for x in version.split('.')) |
| + |
| + |
| +def get_all_tracking_info(): |
| + format_string = ( |
| + '--format=%(refname:short):%(objectname:short):%(upstream:short):') |
| + if get_git_version() >= MIN_UPSTREAM_TRACK_GIT_VERSION: |
| + format_string += '%(upstream:track)' |
| + |
| + info_map = {} |
| + data = run('for-each-ref', format_string, 'refs/heads') |
| + TrackingInfo = collections.namedtuple( |
| + 'TrackingInfo', 'hash upstream ahead behind') |
| + for line in data.splitlines(): |
| + (branch, branch_hash, upstream_branch, tracking_status) = line.split(':') |
| + |
| + ahead_match = re.search(r'ahead (\d+)', tracking_status) |
| + ahead = int(ahead_match.group(1)) if ahead_match else None |
| + |
| + behind_match = re.search(r'behind (\d+)', tracking_status) |
| + behind = int(behind_match.group(1)) if behind_match else None |
| + |
| + info_map[branch] = TrackingInfo( |
| + hash=branch_hash, upstream=upstream_branch, ahead=ahead, behind=behind) |
| + |
| + empty_info = TrackingInfo(hash=None, upstream=None, ahead=None, behind=None) |
| + |
| + # Set an empty info object for upstreams which are not branches (e.g empty |
| + # upstream, remotes and deleted upstream branches). |
| + missing_upstreams = {} |
| + for info in info_map.values(): |
| + if info.upstream not in info_map and info.upstream not in missing_upstreams: |
| + missing_upstreams[info.upstream] = empty_info |
|
iannucci
2014/09/02 22:31:27
Maybe this is more convenient in the user-code (I
calamity
2014/09/03 01:43:21
Done.
|
| + |
| + return dict(info_map.items() + missing_upstreams.items()) |