@@ -32,93 +32,109 @@ def Print(*args, **kwd): # 2.4, 2.5, define our own Print function
32
32
w (str (a ))
33
33
w (kwd .get ("end" , "\n " ))
34
34
35
-
36
35
# change those symbols to whatever you prefer
37
36
symbols = {'ahead of' : '↑·' , 'behind' : '↓·' , 'prehash' :':' }
38
37
39
- from subprocess import Popen , PIPE
40
-
41
38
import sys
42
- gitsym = Popen (['git' , 'symbolic-ref' , 'HEAD' ], stdout = PIPE , stderr = PIPE )
43
- branch , error = gitsym .communicate ()
44
-
45
- error_string = error .decode ('utf-8' )
46
-
47
- if 'fatal: Not a git repository' in error_string :
48
- sys .exit (0 )
49
-
50
- branch = branch .decode ('utf-8' ).strip ()[11 :]
51
-
52
- res , err = Popen (['git' ,'diff' ,'--name-status' ], stdout = PIPE , stderr = PIPE ).communicate ()
53
- err_string = err .decode ('utf-8' )
54
-
55
- if 'fatal' in err_string :
56
- sys .exit (0 )
57
-
58
- changed_files = [namestat [0 ] for namestat in res .splitlines ()]
59
- staged_files = [namestat [0 ] for namestat in Popen (['git' ,'diff' , '--staged' ,'--name-status' ], stdout = PIPE ).communicate ()[0 ].splitlines ()]
60
- nb_changed = len (changed_files ) - changed_files .count ('U' )
61
- nb_U = staged_files .count ('U' )
62
- nb_staged = len (staged_files ) - nb_U
63
- staged = str (nb_staged )
64
- conflicts = str (nb_U )
65
- changed = str (nb_changed )
66
- status_lines = Popen (['git' ,'status' ,'-s' ,'-uall' ],stdout = PIPE ).communicate ()[0 ].splitlines ()
67
- untracked_lines = [a for a in map (lambda s : s .decode ('utf-8' ), status_lines ) if a .startswith ("??" )]
68
- nb_untracked = len (untracked_lines )
69
- untracked = str (nb_untracked )
70
- stashes = Popen (['git' ,'stash' ,'list' ],stdout = PIPE ).communicate ()[0 ].splitlines ()
71
- nb_stashed = len (stashes )
72
- stashed = str (nb_stashed )
73
-
74
- if not nb_changed and not nb_staged and not nb_U and not nb_untracked and not nb_stashed :
75
- clean = '1'
76
- else :
77
- clean = '0'
78
-
39
+ import re
40
+ import shlex
41
+ from subprocess import Popen , PIPE , check_output
42
+
43
+
44
+ def get_tagname_or_hash ():
45
+ """return tagname if exists else hash"""
46
+ cmd = 'git log -1 --format="%h%d"'
47
+ output = check_output (shlex .split (cmd )).decode ('utf-8' ).strip ()
48
+ hash_ , tagname = None , None
49
+ # get hash
50
+ m = re .search ('\(.*\)$' , output )
51
+ if m :
52
+ hash_ = output [:m .start ()- 1 ]
53
+ # get tagname
54
+ m = re .search ('tag: .*[,\)]' , output )
55
+ if m :
56
+ tagname = 'tags/' + output [m .start ()+ len ('tag: ' ): m .end ()- 1 ]
57
+
58
+ if tagname :
59
+ return tagname
60
+ elif hash_ :
61
+ return hash_
62
+ return None
63
+
64
+ def get_stash ():
65
+ cmd = Popen (['git' , 'rev-parse' , '--git-dir' ], stdout = PIPE , stderr = PIPE )
66
+ so , se = cmd .communicate ()
67
+ stashFile = '%s%s' % (so .decode ('utf-8' ).rstrip (),'/logs/refs/stash' )
68
+
69
+ try :
70
+ with open (stashFile ) as f :
71
+ return sum (1 for _ in f )
72
+ except IOError :
73
+ return 0
74
+
75
+ # `git status --porcelain --branch` can collect all information
76
+ # branch, remote_branch, untracked, staged, changed, conflicts, ahead, behind
77
+ po = Popen (['git' , 'status' , '--porcelain' , '--branch' ], stdout = PIPE , stderr = PIPE )
78
+ stdout , sterr = po .communicate ()
79
+ if po .returncode != 0 :
80
+ sys .exit (0 ) # Not a git repository
81
+
82
+ # collect git status information
83
+ untracked , staged , changed , conflicts = [], [], [], []
84
+ ahead , behind = 0 , 0
79
85
remote = ''
80
-
81
- tag , tag_error = Popen (['git' , 'describe' , '--exact-match' ], stdout = PIPE , stderr = PIPE ).communicate ()
82
-
83
- if not branch : # not on any branch
84
- if tag : # if we are on a tag, print the tag's name
85
- branch = tag
86
- else :
87
- branch = symbols ['prehash' ]+ Popen (['git' ,'rev-parse' ,'--short' ,'HEAD' ], stdout = PIPE ).communicate ()[0 ].decode ('utf-8' )[:- 1 ]
86
+ status = [(line [0 ], line [1 ], line [2 :]) for line in stdout .decode ('utf-8' ).splitlines ()]
87
+ for st in status :
88
+ if st [0 ] == '#' and st [1 ] == '#' :
89
+ if re .search ('Initial commit on' , st [2 ]):
90
+ branch = st [2 ].split (' ' )[- 1 ]
91
+ elif re .search ('no branch' , st [2 ]): # detached status
92
+ branch = get_tagname_or_hash ()
93
+ elif len (st [2 ].strip ().split ('...' )) == 1 :
94
+ branch = st [2 ].strip ()
95
+ else :
96
+ # current and remote branch info
97
+ branch , rest = st [2 ].strip ().split ('...' )
98
+ if len (rest .split (' ' )) == 1 :
99
+ # remote_branch = rest.split(' ')[0]
100
+ pass
101
+ else :
102
+ # ahead or behind
103
+ divergence = ' ' .join (rest .split (' ' )[1 :])
104
+ divergence = divergence .lstrip ('[' ).rstrip (']' )
105
+ for div in divergence .split (', ' ):
106
+ if 'ahead' in div :
107
+ ahead = int (div [len ('ahead ' ):].strip ())
108
+ remote += '%s%s' % (symbols ['ahead of' ], ahead )
109
+ elif 'behind' in div :
110
+ behind = int (div [len ('behind ' ):].strip ())
111
+ remote += '%s%s' % (symbols ['behind' ], behind )
112
+ elif st [0 ] == '?' and st [1 ] == '?' :
113
+ untracked .append (st )
114
+ else :
115
+ if st [1 ] == 'M' :
116
+ changed .append (st )
117
+ if st [0 ] == 'U' :
118
+ conflicts .append (st )
119
+ elif st [0 ] != ' ' :
120
+ staged .append (st )
121
+
122
+ if not changed and not staged and not conflicts and not untracked :
123
+ clean = 1
88
124
else :
89
- remote_name = Popen (['git' ,'config' ,'branch.%s.remote' % branch ], stdout = PIPE ).communicate ()[0 ].strip ()
90
- if remote_name :
91
- merge_name = Popen (['git' ,'config' ,'branch.%s.merge' % branch ], stdout = PIPE ).communicate ()[0 ].strip ()
92
- else :
93
- remote_name = "origin"
94
- merge_name = "refs/heads/%s" % branch
95
-
96
- if remote_name == '.' : # local
97
- remote_ref = merge_name
98
- else :
99
- remote_ref = 'refs/remotes/%s/%s' % (remote_name , merge_name [11 :])
100
- revgit = Popen (['git' , 'rev-list' , '--left-right' , '%s...HEAD' % remote_ref ],stdout = PIPE , stderr = PIPE )
101
- revlist = revgit .communicate ()[0 ]
102
- if revgit .poll (): # fallback to local
103
- revlist = Popen (['git' , 'rev-list' , '--left-right' , '%s...HEAD' % merge_name ],stdout = PIPE , stderr = PIPE ).communicate ()[0 ]
104
- behead = revlist .splitlines ()
105
- ahead = len ([x for x in behead if x [0 ]== '>' ])
106
- behind = len (behead ) - ahead
107
- if behind :
108
- remote += '%s%s' % (symbols ['behind' ], behind )
109
- if ahead :
110
- remote += '%s%s' % (symbols ['ahead of' ], ahead )
125
+ clean = 0
111
126
112
127
if remote == "" :
113
- remote = '.'
128
+ remote = '.'
114
129
115
130
out = '\n ' .join ([
116
- str (branch ),
117
- str (remote ),
118
- staged ,
119
- conflicts ,
120
- changed ,
121
- untracked ,
122
- stashed ,
123
- clean ])
131
+ branch ,
132
+ remote .decode ('utf-8' ),
133
+ str (len (staged )),
134
+ str (len (conflicts )),
135
+ str (len (changed )),
136
+ str (len (untracked )),
137
+ str (get_stash ()),
138
+ str (clean )
139
+ ])
124
140
Print (out )
0 commit comments