123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- #!/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, deleted, 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[1] == 'D':
- deleted.append(st)
- if st[0] == 'U':
- conflicts.append(st)
- elif st[0] != ' ':
- staged.append(st)
- stashed = get_stash()
- if not changed and not deleted 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),
- str(len(deleted))
- ])
- print(out, end='')
|