Skip to content

Instantly share code, notes, and snippets.

@henryiii henryiii/git-all.py
Last active Jul 26, 2017

Embed
What would you like to do?
Fast repository status for repos in git folder, Python Rewrite.
#!/usr/bin/env python3
from plumbum import local, cli, FG, BG, TF, ProcessExecutionError, colors
from plumbum.cmd import tput, git
from contextlib import contextmanager
from functools import partial
# This can be hard coded to a repo location, or cwd, etc.
# REPOLOC = local.path(__file__) / '..'
REPOLOC = local.env.home / 'git'
valid_repos = [d / '../..' for d in REPOLOC // '*/.git/config']
printf = partial(print, end='', flush=True)
def git_on_all():
'Loop over all the repos, inside the loop you are in the directory of the repo.'
for n,repo in enumerate(valid_repos):
with local.cwd(repo):
with (colors[1:7][n%6] & colors.bold):
yield repo.basename
def fetch():
'Fetch on all repos, with message printed for failures.'
bg = []
for repo in git_on_all():
bg.append((repo, git['fetch','-q'] & BG))
printf('Waiting for the repos to report: ')
for repo, fut in bg:
try:
fut.wait()
except ProcessExecutionError:
print(repo, 'Failed to fetch, not valid?')
print('done.')
# Git commands, collected and named for clarity
def unstaged_changes():
'True if there are unstaged changes in working tree.'
return not git['diff-index', '--cached', '--quiet', 'HEAD', '--ignore-submodules', '--'] & TF
def print_unstaged_changes():
printf(~colors.bold & git('diff-files', '--name-status', '-r', '--ignore-submodules', '--'))
def uncommited_changes_in_index():
return not git['diff-index', '--cached', '--quiet', 'HEAD', '--ignore-submodules', '--'] & TF
def print_uncommited_changes_in_index():
printf(~colors.bold & git('diff-index', '--cached', '--name-status', '-r', '--ignore-submodules', 'HEAD', '--'))
def unpushed_changes():
'Note that this is a list of unpushed changes compared to empty, not as programatic as above solutions'
return git('rev-list', '@{u}..') != ''
def print_unpushed_changes():
printf(~colors.bold & git('log', '@{u}..', '--oneline'))
def unmerged_changes():
return git('rev-list', '..@{u}') != ''
def print_unmerged_changes():
printf(~colors.bold & git('log', '..@{u}', '--oneline'))
# Actual Application and commands
class GitAll(cli.Application):
"""Multiple repository checker"""
VERSION = "1.0"
@GitAll.subcommand("status")
class Status(cli.Application):
'Checks all the git repos in git folder'
quick = cli.Flag("-q", help = "Quick status (no fetch)")
def main(self):
if not self.quick:
fetch()
for repo in git_on_all():
printf("Checking {}: ".format(repo))
changed = False
if unstaged_changes():
print("There are unstaged changes:")
print_unstaged_changes()
changed = True
if uncommited_changes_in_index():
print("There are uncommented changes in the index:")
print_uncommited_changes_in_index()
changed = True
if unpushed_changes():
print("There are unpushed changes:")
print_unpushed_changes()
changed = True
if unmerged_changes():
print("There are unmerged changes:")
print_unmerged_changes()
changed = True
if not changed:
print("No changes")
@GitAll.subcommand("pull")
class Pull(cli.Application):
'Pulls all repos in the folder, not threaded.'
def main(self):
for repo in git_on_all():
git['pull'] & FG
@GitAll.subcommand("fetch")
class Fetch(cli.Application):
'Fetches all repos in the folder'
quiet = cli.Flag("-q", help = "Quiet fetch")
def main(self):
fetch()
if not self.quiet:
for repo in git_on_all():
printf("Fetched {}: ".format(repo))
if unmerged_changes():
print("There are unmerged changes:")
print_unmerged_changes()
else:
print("Up to date.")
@GitAll.subcommand("merge")
class Merge(cli.Application):
'Merges all repos in the folder (origin/master)'
def main(self):
for repo in git_on_all():
printf("Merging {}: ".format(repo))
if unmerged_changes():
git['merge','origin/master'] & FG
else:
print("Merge not needed.")
if __name__ == "__main__":
GitAll.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.