Give git map-branches extra information behind -v and -vv flags.
This CL adds information to the git map-branches command. Invoking
it map-branches with -v, will show tracking status of branches and
invoking with -vv will additionally show the Rietveld URL and the
branch hash.
BUG=None
Review URL: https://codereview.chromium.org/509843002
git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@291776 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/git_common.py b/git_common.py
index 64a385b..31a62b8 100644
--- a/git_common.py
+++ b/git_common.py
@@ -91,6 +91,9 @@
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 @@
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 @@
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):')
+
+ # This is not covered by the depot_tools CQ which only has git version 1.8.
+ if get_git_version() >= MIN_UPSTREAM_TRACK_GIT_VERSION: # pragma: no cover
+ 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)
+
+ # Set None 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] = None
+
+ return dict(info_map.items() + missing_upstreams.items())