def fetch_branch(repo_path, branch, shallow=True): """ Call "git fetch -p origin <branch>" :param repo_path: The full path to the repository on-disk :param branch: The branch. :param shallow: Whether to perform a shallow fetch (--depth 1) :raises: BranchNotFoundError if the branch is not found; GitError for other errors """ validate_branch(branch) log.info("Fetching %s from origin", branch) args = ['git', 'fetch'] if shallow: args.extend(['--depth', '1']) args.extend(['-p', 'origin', fetch_refspec(branch)]) proc = subprocess.Popen(args, cwd=repo_path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if proc.wait() != 0: not_found_str = "fatal: couldn't find remote ref %s" % branch out = proc.stdout.read().decode() log.error(out) if not_found_str in out.lower(): raise BranchNotFoundError(branch) else: raise GitError("git fetch failed!")
def local_branch_from_ref(ref): if ref.startswith('refs/pull/'): s = lsstrip(ref, 'refs/pull/') s = rsstrip(s, '/merge') s = rsstrip(s, '/head') return "PR#%s" % s elif ref.startswith('refs/heads/'): return lsstrip(ref, 'refs/heads/') raise GitError("Unsupported ref '%s', try 'refs/heads/' or 'refs/pull/'" % ref)
def fetch(repo_path): """ Call "git fetch -p origin" :param repo_path: The full path to the repository :raises: GitError if the operation fails """ log.info("Fetching from upstream into %s", repo_path) proc = subprocess.Popen(('git', 'fetch', '-p', 'origin'), cwd=repo_path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if proc.wait() != 0: out = proc.stdout.read().decode() log.error(out) raise GitError("git fetch failed!")
def set_remote(repo_path, repo_url): """ Call "git remote set-url origin <repo_url>" :param repo_url: The full URL to the repo (not including the branch) :param repo_path: The full path to the repository :raises: GitError if the operation fails """ log.debug("Setting repo remote to %s", repo_url) proc = subprocess.Popen(('git', 'remote', 'set-url', 'origin', repo_url), cwd=repo_path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if proc.wait() != 0: out = proc.stdout.read() log.error(out) raise GitError("git remote set-url failed!")
def clone_repo(repo_url, dest_path, branch, shallow=True): """ Clone a repo into a path :param repo_url: The full URL to the repo (not including the branch) :param dest_path: The full path to the destination directory :param branch: The branch. :param shallow: Whether to perform a shallow clone (--depth 1) :raises: BranchNotFoundError if the branch is not found; GitError for other errors """ validate_branch(branch) log.info("Cloning %s %s from upstream", repo_url, branch) if branch.startswith('refs/'): clone_repo_ref(repo_url, dest_path, branch) return args = ['git', 'clone'] if shallow: args.extend(['--depth', '1']) args.extend(['--branch', branch, repo_url, dest_path]) proc = subprocess.Popen( args, cwd=os.path.dirname(dest_path), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) not_found_str = "Remote branch %s not found" % branch out = proc.stdout.read() result = proc.wait() # Newer git versions will bail if the branch is not found, but older ones # will not. Fortunately they both output similar text. if not_found_str in out: log.error(out) if result == 0: # Old git left a repo with the wrong branch. Remove it. shutil.rmtree(dest_path, ignore_errors=True) raise BranchNotFoundError(branch, repo_url) elif result != 0: # Unknown error raise GitError("git clone failed!")
def remote_ref_from_ref(ref, remote='origin'): if ref.startswith('refs/pull/'): return 'refs/remotes/' + remote + lsstrip(ref, 'refs') elif ref.startswith('refs/heads/'): return 'refs/remotes/' + remote + lsstrip(ref, 'refs/heads') raise GitError("Unsupported ref '%s'" % ref)