Skip to content

Instantly share code, notes, and snippets.

@mintchaos
Created April 16, 2009 06:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mintchaos/96275 to your computer and use it in GitHub Desktop.
Save mintchaos/96275 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
#
# some bits stolen from Travis Cline's http://github.com/traviscline/git-branchdescriptions
#
import os
import re
import sys
from subprocess import Popen, PIPE
HELP_TEXT = """
git-sync is quick hack rsync wrapper that's aware of git branches.
You must set sync.location to be an rsync path where your branches will
sync to such as: `git config sync.location user@servername:path/to/project/`
git sync will look in that path for folders with names that match your current
branch. If there are it'll rsync your working directory into that folder. If it
can't find a branch-named folder it'll sync your working directory to
sync.location/master.
It has two optional options.
`git sync check`
Will tell you where the current working directory will sync to.
`git sync create`
Will create a remote folder for your current branch in the remote directory.
`git sync`
Will run the sync.
WARNING: git-sync is potentially dangerous. it will delete your data if pointed
at the wrong directory. Please run `git sync check` first and be careful while
setting your paths.
It's also not backed by a test suite and I'm parsing arguments dumb. Whee!
----
Requires GitPython
`easy_install/pip GitPython`
"""
try: # conditional import to allow setup.py to grab __version__
import git
from git.errors import GitCommandError
except ImportError:
pass
def _santitize_branch_name(name):
"""
Strips down a git branch name to plain text.
"""
s = name.strip('*').strip().split()[0] # get first part of string sans '*'
s = _strip_ansi_escaped_chars(s) # remove color formatting if it exists
return s
def _strip_ansi_escaped_chars(s):
"""
Strips ANSI escaped characters from a string.
"""
esc = '\x1b.+?m'
return re.sub(esc+'$', '', re.sub('^'+esc, '', s))
class GitSyncError(Exception):
pass
class GitSyncMisconfiguredError(GitSyncError):
pass
class GitSyncInvalidArgumentError(GitSyncError):
pass
class GitSync(object):
def __init__(self, command=None, args=None):
repo_path = os.getcwd()
self.repo = git.Repo(repo_path)
if command in ['check', 'create', None]:
self.command = command
else:
raise GitSyncInvalidArgumentError()
self.branch = _santitize_branch_name(self.repo.active_branch)
self.remote = self.repo.git.execute(('git', 'config', '--get', 'sync.location'), with_exceptions=False).strip('/')
try:
self.host, self.path = self.remote.split(':')
except ValueError:
raise GitSyncMisconfiguredError('\nYou must set sync.location to be an rsync path where your branches will sync to\nExample:\n`git config sync.location user@servername:path/to/project/`')
self.master_dir = self.repo.git.execute(('git', 'config', '--get', 'sync.master'), with_exceptions=False) or "master"
self.master_path = "%s/%s" % (self.path, self.master_dir)
def remote_popen(self, command):
return Popen(["ssh", self.host, command], stdout=PIPE)
def get_remote_dirs(self):
return self.remote_popen('ls %s' % self.path).stdout.read().split()
def get_remote_path(self):
if self.branch in self.get_remote_dirs():
return "%s/%s" % (self.path, self.branch)
else:
return self.master_path
def sync(self):
os.system('rsync -avC --delete --exclude=".git" --include="core" %s/ %s:%s/' % (self.repo.wd, self.host, self.get_remote_path()))
def check(self):
print "Branch: %s will sync to %s:%s/" % (self.branch, self.host, self.get_remote_path())
def create(self):
if self.branch in self.get_remote_dirs():
print "Remote path for %s already exists" % self.branch
elif self.master_dir in self.get_remote_dirs():
cmd = 'cp -r %(path)s/%(master)s %(path)s/%(branch)s' % dict(path=self.path, branch=self.branch, master=self.master_dir)
print cmd
self.remote_popen(cmd)
else:
self.remote_popen('mkdir -p %s/%s' % (self.path, self.branch))
self.sync()
def run(self):
if self.command:
return getattr(self, self.command)()
return self.sync()
def run(args):
try:
command = args[1]
except IndexError:
command = None
try:
GitSync(command).run()
sys.exit(False)
except GitSyncError:
print HELP_TEXT
sys.exit(True)
if __name__ == '__main__':
run(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment