Skip to content

Instantly share code, notes, and snippets.

@basilfx
Created July 8, 2015 09:24
Show Gist options
  • Save basilfx/2308605ef28cde40d482 to your computer and use it in GitHub Desktop.
Save basilfx/2308605ef28cde40d482 to your computer and use it in GitHub Desktop.
Git Multi-Branch Status
#!/usr/bin/env python
import os
import sys
import subprocess
import multiprocessing
# List of folders to check status on
FOLDERS = [
# Put your project folders here -- absolute paths please.
]
def execute(command):
"""
Run a command and return the command output.
"""
process = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
output = ""
while True:
line = process.stdout.readline()
if not line:
break
output += line
return output.strip()
def execute_count(command):
"""
Run a command and return the number of lines.
"""
output = execute(command).strip()
return len(output.split("\n")) if output else 0
def process_repository(folder):
"""
Process one repository and return a row for the result table.
"""
os.chdir(folder)
execute("git fetch --prune --quiet")
folder = os.path.basename(folder)
branch = execute("git symbolic-ref --short HEAD")
is_clean = "working directory clean" in execute("git status")
is_clean = "yes" if is_clean else "no"
# Update if requested
if "--update" in sys.argv:
if is_clean:
execute("git pull --rebase")
local = execute("git rev-parse @{0}")
remote = execute("git rev-parse @{u}")
base = execute("git merge-base @{0} @{u}")
if execute_count("git ls-remote origin '%s'" % branch):
commits_branch = execute_count(
"git rev-list 'origin/%s...%s'" % (branch, branch))
if local == base:
commits_branch = -1 * commits_branch
else:
commits_branch = "?"
if execute_count("git ls-remote origin master"):
commits_master = execute_count(
"git rev-list 'origin/master...%s'" % branch)
if local == base:
commits_master = -1 * commits_master
else:
commits_master = "?"
if local == remote:
status = "up-to-date"
elif local == base:
status = "need to pull"
elif remote == base:
if commits_branch > 0:
status = "need to push"
else:
status = "up-to-date"
else:
status = "diverged"
# Done
return [folder, branch, str(commits_branch), str(commits_master), is_clean,
status]
def main():
"""
Main entry point.
"""
table = [
["REPOSITORY", "CURRENT BRANCH", "BRANCH", "MASTER", "CLEAN", "STATUS"]
]
# Check repositories
pool = multiprocessing.Pool()
table += sorted(pool.map(process_repository, FOLDERS), key=lambda x: x[0])
# Determine width of each
widths = [0] * len(table[0])
for row in table:
for index, column in enumerate(row):
widths[index] = max(widths[index], len(column))
# Print table
for row in table:
for index, column in enumerate(row):
sys.stdout.write(("%-" + str(widths[index]) + "s ") % column)
sys.stdout.write("\n")
# E.g. `python status.py`
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment