1"""Convenience functions for working with git. 2 3This module does not include any tasks, only functions. 4 5At this point, these functions do not use any kind of library. They require 6the git binary on the path.""" 7 8from paver.easy import sh 9import os, re 10 11def _format_path(provided_path): 12 return provided_path or os.getcwd() 13 14def _split_remote_branch_name(provided_name): 15 return provided_name.split("/")[1] 16 17def clone(url, dest_folder): 18 sh("git clone %(url)s %(path)s" % dict(url=url, path=dest_folder) ) 19 20def pull(destination, remote="origin", branch="master"): 21 """Perform a git pull. Destination must be absolute path. 22 """ 23 sh("cd %(destination)s; git pull %(remote)s %(branch)s" % dict( 24 destination=destination, remote=remote, branch=branch) ) 25 26def latest_tag(): 27 """Get the most recent git tag. Useful for using in package version.""" 28 return str(sh("git describe --tags --always HEAD", capture=True).strip()) 29 30def branch_list(path="", remote_branches_only=False, __override__=None): 31 """ 32 Lists git branches for the repository specified (or CWD). 33 If remote_branches_only is specified will list branches that exist 34 on the remote. These branches may, or may not, have corresponding remote 35 tracking branches. 36 37 Returns a Python tuple. The first item in the tuple will be the current 38 branch, and the other item will be a list of branches for the repository. 39 40 Optional parameter path: the path to the git repo. Else uses os.getcwd() 41 """ 42 43 remote_branches = "" 44 if remote_branches_only: 45 remote_branches = "-r" 46 47 if __override__ == None: 48 git_output = sh( "cd %(repo_path)s; git branch %(remote)s" % dict( 49 repo_path = _format_path(path), remote = remote_branches ), capture=True ) 50 else: 51 git_output = __override__ 52 53 if git_output == None: 54 return None, [] # should only hit this condition in testing... 55 56 current_branch = "" 57 branches = [] 58 found_a_match = False 59 regex = re.compile(r"(\*?)\W*(.+)") 60 61 for line in git_output.split("\n"): 62 match_obj = regex.match(line) 63 if match_obj: 64 found_a_match = True 65 if match_obj.group(1): 66 current_branch = match_obj.group(2).strip() 67 if match_obj.group(2).strip(): 68 branches.append( match_obj.group(2).strip() ) 69 70 if found_a_match is False: 71 raise "git branch did not return output expected. Returned %s" % git_output 72 73 return current_branch, branches 74 75def branch_checkout(branch_name, path=""): 76 """Checkout a git branch. 77 78 Take the branch name to checkout, and optional path parameter 79 (the path to the git repo. Else uses os.getcwd()) 80 """ 81 82 sh( "cd %(repo_path)s; git checkout %(branch_name)s" % dict( 83 repo_path = _format_path(path), 84 branch_name=branch_name) ) 85 86def branch_track_remote(remote_branch_name, local_branch_name=None, path=""): 87 local_branch_name = ( local_branch_name or _split_remote_branch_name(remote_branch_name) ) 88 89 sh( "cd %(repo_path)s; git checkout -b %(branch_name)s --track %(remote_branch_name)s" % dict( 90 repo_path = _format_path(path), 91 branch_name=local_branch_name, 92 remote_branch_name=remote_branch_name) ) 93 94