def main(): process_options() try: git.check_repository() if config["dependents"]: git_dependent_branches() elif config["limb"]: git_pending_limb() else: if config["left"]: git_pending_commits() else: git_pending_branch(git.current_branch()) except git.GitError, e: sys.stderr.write("\nError: %s\n" % e.msg) sys.stderr.write("Exiting.\n") if config["debug"]: sys.stdout.write("\n") raise sys.exit(1)
def git_list_branches(): branch_name = git.current_branch().name limb_name = git.current_limb().name if limb_name: sys.stdout.write("%s/\n" % limb_name) for name in git.branchnames(limb_name): if name == branch_name: sys.stdout.write("* %s\n" % name) else: sys.stdout.write(" %s\n" % name)
def git_dependent_branches(): provider = config["dependents"].strip('/') if provider: provider = git.Branch(provider) else: provider = git.current_branch() limbs = config["limbs"] if limbs: limbs = [git.Limb.get(x.strip('/')) for x in limbs] else: limbs = [git.current_limb()] for limb in limbs: for branch in provider.all_dependents(limb): sys.stdout.write('%s\n' % branch.name)
def git_pending_commits(): left = config["left"] right = config["right"] with_rejects = config["with_rejects"] if right: right = git.Branch(right) else: right = git.current_branch() if left: left = git.Branch(left) if not left.id: sys.stderr.write("Invalid branch: %s\n" % left.name) sys.exit(1) if not right.id: sys.stderr.write("Invalid branch: %s\n" % right.name) sys.exit(1) left_base = left.upstream_version if not left_base: sys.stderr.write("Invalid upstream_version for %s\n" % left.name) sys.exit(1) commits = git.changeid_diff(left, right, with_rejects=with_rejects) if (not left.has_branch_merge_base() and commits and not commits[0].contains(left_base)): sys.stderr.write("Error: upstream version: %s\n" " is not a first-parent ancestor of:\n" " %s\n" % (left_base, left.name)) sys.exit(1) if config["verbose"]: cmd = ["git", "--no-pager", "log", "-1", "--pretty=format:%h %s\n"] for commit in commits: git.call(cmd + [commit.id], stdout=sys.stdout) else: for commit in commits: sys.stdout.write("%s\n" % commit.id)
def git_delete_limb(): limbname = config["limb1"] recursive = config["recursive"] limb = git.Limb.get(limbname) if not limb.exists(): if not limbname: limbname = '""' sys.stderr.write("%s: not found\n" % limbname) sys.exit(1) limb_branches = git.branchnames(limbname, recursive=recursive) try: current_name = git.current_branch().name if current_name and current_name in limb_branches: sys.stderr.write("Cannot delete current branch: %s.\n" % current_name) sys.exit(1) except git.GitError: pass cmd = ['git', 'branch', '-D'] + limb_branches git.call(cmd, stdout=sys.stdout, verbose=True)
def git_create_limb(): limb1name = config["limb1"] limb2name = config["limb2"] force = config["force"] recursive = config["recursive"] checkout = config["checkout"] checkout_name = None if checkout: check_clean_state() branch = git.Branch.get(limb1name) if branch.exists(): sys.stdout.write("%s is an existing branch, need a limb name\n" % limb1name) sys.exit(1) remote = git.remote_alias() if limb1name.startswith(remote + '/'): sys.stdout.write('%s: Cannot create a limb beginning with "%s"\n' % (limb1name, remote)) sys.exit(1) if limb2name: branch = git.Branch.get(limb2name) if branch.exists(): sys.stdout.write("%s is an existing branch, need a limb\n" % limb2name) sys.exit(1) limb2 = git.Limb.get(limb2name) else: limb2 = git.current_limb() limb2name = limb2.name if not limb2.exists(): if not limb2name: limb2name = '""' sys.stdout.write("%s: not found\n" % limb2name) sys.exit(1) if limb1name == limb2name: sys.stdout.write("%s and %s are identical.\n" % (limb1name, limb2name)) return limb1_branchnames = git.branchnames(limb1name, recursive=recursive) if limb1_branchnames and not force: sys.stderr.write("%s exists. Use -f to force overwrite.\n" % limb1name) sys.exit(1) limb2_subnames = git.subnames(limb2name, recursive=recursive) try: current = git.current_branch() current_name = current.name except: current_name = None if current_name and current_name in limb1_branchnames: if not checkout: check_clean_state() git.call(['git', 'checkout', current.id], stdout=None, stderr=None) checkout = True if current.subname in limb2_subnames: checkout_name = current_name limb1_subnames = git.subnames(limb1name, limb1_branchnames) for subname in limb2_subnames: destname = "%s/%s" % (limb1name, subname) sourcename = "%s/%s" % (limb2name, subname) dest = git.Branch.get(destname) source = git.Branch.get(sourcename) if dest.id != source.id: cmd = ['git', 'branch', '-f', destname, sourcename] git.call(cmd, stdout=sys.stdout, verbose=True) if not checkout_name: checkout_name = destname for subname in limb1_subnames: if subname in limb2_subnames: continue del_name = "%s/%s" % (limb1name, subname) cmd = ['git', 'branch', '-D', del_name] git.call(cmd, stdout=sys.stdout, verbose=True) if checkout: if not checkout_name: sys.stderr.write("No branch in %s to checkout.\n" % limb2name) sys.exit(1) cmd = ['git', 'checkout', checkout_name] if current_name and checkout_name == current.name: git.call(cmd, stdout=None, stderr=None) else: git.call(cmd, stdout=sys.stdout, verbose=True)
def rebase_limb(): options = config["options"] upstreamname = config["upstream"] limbname = config["limb"] if limbname: common_branch = "%s/common" % limbname.rstrip("/") cmd = ['git', 'checkout', common_branch] git.call(cmd, stdout=sys.stdout, verbose=True) original_branch = git.current_branch() limb = git.current_limb() limbname = limb.name upstreamname = upstreamname.rstrip("/") upstream = git.Limb.get(upstreamname) if not limb.exists(): sys.stdout.write("%s: not found\n" % limbname) sys.exit(1) if not upstream.exists(): sys.stdout.write("%s: not found\n" % upstreamname) sys.exit(1) upstream_subnames = git.subnames(upstreamname) limb_subnames = git.subnames(limbname) not_rebased = [] for subname in limb_subnames: limb_branchname = "%s/%s" % (limbname, subname) upstream_branchname = "%s/%s" % (upstreamname, subname) if subname not in upstream_subnames: not_rebased.append((limb_branchname, upstream_branchname)) continue limb_branch = git.Branch.get(limb_branchname) upstream_branch = git.Branch.get(upstream_branchname) if limb_branch.contains(upstream_branch): continue cmd = ['git', 'checkout', limb_branchname] git.call(cmd, stdout=sys.stdout, verbose=True) cmd = ['git', 'rebase'] + options + [upstream_branchname] git.call(cmd, stdout=sys.stdout, verbose=True) for subname in upstream_subnames: if subname in limb_subnames: continue limb_branchname = "%s/%s" % (limbname, subname) upstream_branchname = "%s/%s" % (upstreamname, subname) cmd = ['git', 'branch', limb_branchname, upstream_branchname] git.call(cmd, stdout=sys.stdout, verbose=True) # restore original branch if git.current_branch() != original_branch: cmd = ['git', 'checkout', original_branch.name] git.call(cmd, stdout=sys.stdout, verbose=True) if not_rebased: sys.stderr.write("\n") for limb_branchname, upstream_branchname in not_rebased: sys.stderr.write("NOT rebasing %s, no %s\n" % (limb_branchname, upstream_branchname))
def provenance(): branchname = config["branchname"] limitIDs = config["limitIDs"] abbrev = config["abbrev"] terse = config["terse"] extraterse = config["extraterse"] verbose = config["verbose"] includes = config["includes"] excludes = config["excludes"] upstream_branchnames = config["upstream_branchnames"] if branchname and branchname != 'HEAD': branch = git.Branch(branchname) else: branch = git.current_branch() if not branch.id or not branch.exists(): if branchname: sys.stderr.write('Branch "%s" not found\n' % branchname) else: sys.stderr.write('No current branch\n') sys.exit(1) if upstream_branchnames: if not branch.limb: sys.stderr.write('Branch "%s" is not part of a limb.\n' % branch.name) sys.exit(1) upstream_branches = [] for ub_name in upstream_branchnames: ub = git.Branch.get(ub_name) if not ub.exists(): rub = ub.remote_branch if not rub.exists(): sys.stderr.write("upstream-branch '%s' not found\n" % ub_name) sys.exit(1) ub = rub upstream_branches.append(ub) branch.limb.upstream_branches = upstream_branches ids = [] for id in limitIDs: cmd = ['git', 'rev-parse', id] nid = git.call(cmd, error=None, stderr=None).rstrip() or id ids.append(nid) limitIDs = ids for commit, change in branch.provenance(): commitid = commit.id changeid = commit.changeid if limitIDs: for id in limitIDs: if commitid.startswith(id) or changeid.startswith(id): break else: continue if change == 'cherry-picked' and (includes or excludes): from_branchnames = [x.name for x in commit.from_branches] if includes: for s in includes: for name in from_branchnames: if s in name: break else: continue break else: continue if excludes: skip = False for s in excludes: for name in from_branchnames: if s in name: skip = True break else: continue break if skip: continue elif includes: continue if abbrev: commitid = commit.abbrev_id() sys.stdout.write(commitid) if verbose: sys.stdout.write(" %s" % ' '.join(commit.subject)) if change == 'cherry-picked': if extraterse: sys.stdout.write("\n") continue elif terse: fmt = " %s %s" else: if abbrev: fmt = "\n %9s %s" else: fmt = "\n %s %s" for i in reversed(range(len(commit.from_commits))): if abbrev: commitid = commit.from_commits[i].abbrev_id() else: commitid = commit.from_commits[i].id branchname = commit.from_branches[i].name sys.stdout.write(fmt % (commitid, branchname)) if terse: sys.stdout.write("\n") else: sys.stdout.write("\n\n")