#!/usr/bin/env python3 from __future__ import print_function import os import sys import re from subprocess import Popen, PIPE, check_output def get_tagname_or_hash(): """return tagname if exists else hash""" # get hash hash_cmd = ['git', 'rev-parse', '--short', 'HEAD'] hash_ = check_output(hash_cmd).decode('utf-8').strip() # get tagname tags_cmd = ['git', 'for-each-ref', '--points-at=HEAD', '--count=2', '--sort=-version:refname', '--format=%(refname:short)', 'refs/tags'] tags = check_output(tags_cmd).decode('utf-8').split() if tags: return tags[0] + ('+' if len(tags) > 1 else '') elif hash_: return hash_ return None # Re-use method from https://github.com/magicmonty/bash-git-prompt to get stashs count def get_stash(): cmd = Popen(['git', 'rev-parse', '--git-dir'], stdout=PIPE, stderr=PIPE) so, se = cmd.communicate() stash_file = '%s%s' % (so.decode('utf-8').rstrip(), '/logs/refs/stash') try: with open(stash_file) as f: return sum(1 for _ in f) except IOError: return 0 # `git status --porcelain --branch` can collect all information # branch, remote_branch, untracked, staged, changed, conflicts, ahead, behind po = Popen(['git', 'status', '--porcelain', '--branch'], env=dict(os.environ, LANG="C"), stdout=PIPE, stderr=PIPE) stdout, sterr = po.communicate() if po.returncode != 0: sys.exit(0) # Not a git repository # collect git status information untracked, staged, changed, conflicts = [], [], [], [] ahead, behind = 0, 0 status = [(line[0], line[1], line[2:]) for line in stdout.decode('utf-8').splitlines()] for st in status: if st[0] == '#' and st[1] == '#': if re.search('Initial commit on', st[2]) or re.search('No commits yet on', st[2]): branch = st[2].split(' ')[-1] elif re.search('no branch', st[2]): # detached status branch = get_tagname_or_hash() elif len(st[2].strip().split('...')) == 1: branch = st[2].strip() else: # current and remote branch info branch, rest = st[2].strip().split('...') if len(rest.split(' ')) == 1: # remote_branch = rest.split(' ')[0] pass else: # ahead or behind divergence = ' '.join(rest.split(' ')[1:]) divergence = divergence.lstrip('[').rstrip(']') for div in divergence.split(', '): if 'ahead' in div: ahead = int(div[len('ahead '):].strip()) elif 'behind' in div: behind = int(div[len('behind '):].strip()) elif st[0] == '?' and st[1] == '?': untracked.append(st) else: if st[1] == 'M': changed.append(st) if st[0] == 'U': conflicts.append(st) elif st[0] != ' ': staged.append(st) stashed = get_stash() if not changed and not staged and not conflicts and not untracked: clean = 1 else: clean = 0 out = ' '.join([ branch, str(ahead), str(behind), str(len(staged)), str(len(conflicts)), str(len(changed)), str(len(untracked)), str(stashed), str(clean) ]) print(out, end='')