def do_cherry_pick(commit): cherry_options = config["cherry_options"] merge_commits = config["merge_commits"] if commit in merge_commits: cherry_options = cherry_options + ["-m", "1"] sys.stdout.write("Pick ") cmd = ['git', '--no-pager', 'log', '-1', '--pretty=format:%h %s\n', commit] git.call(cmd, stdout=sys.stdout) cmd = ["git", "cherry-pick", "-n"] + cherry_options + [commit] p = subprocess.Popen(cmd, stdout=sys.stdout, stderr=subprocess.PIPE) errmsg = p.stderr.read() rc = p.wait() if errmsg == 'Finished one cherry-pick.\n': return elif errmsg: resolved_file_lines = [] for line in errmsg.splitlines(1): if line.startswith("Resolved ") or line.startswith("Staged "): resolved_file_lines.append(line) unmerged = unmerged_files() if unmerged or resolved_file_lines: if (resolved_file_lines): sys.stderr.writelines(resolved_file_lines) else: sys.stderr.write(unmerged) sys.stderr.write("Automatic cherry-pick failed. ") output_resolve_msg_and_exit() sys.stderr.write(errmsg) if rc != 0: sys.exit(rc)
def check_mv_headers(ids): no_mv_header_ids = [] u = git.usage() for id in ids: commit = git.read_commit(id) h = commit.mv_header_dict if 'source' in h and 'mr' in h and 'type' in h and 'disposition' in h: continue no_mv_header_ids.append(id) if no_mv_header_ids: sys.stderr.write("The following commits have no MV header:\n") for id in no_mv_header_ids: cmd = ['git', '--no-pager', 'log', '-1', '--pretty=oneline', id] git.call(cmd, stdout=sys.stdout) sys.stderr.write("To cherry-pick commits without an MV header, " "it is necessary to specify either\n" "--edit or all of these options: \n" "--source %s\n" "--bugz, " "--type %s\n" "--disposition %s\n" % (u.Source, u.Type, u.Disposition)) sys.exit(1)
def do_continue_or_skip(): restore_state() merge_msg_filename = config["gitdir"] + "/MERGE_MSG" if os.path.isfile(merge_msg_filename): os.remove(merge_msg_filename) commits = config["commits"] commits_done = config["commits_done"] commit = commits[commits_done] cmd = ['git', '--no-pager', 'log', '-1', '--pretty=format:%h %s\n', commit] oneline = git.call(cmd).strip() if config["continue"]: sys.stdout.write("Continuing %s\n" % oneline) unmerged = unmerged_files() if unmerged: sys.stderr.write(unmerged) sys.stderr.write("Unmerged files. ") output_resolve_msg_and_exit() do_commit(commit) else: cmd = ['git', 'reset', '--hard', 'HEAD^0'] git.call(cmd, stdout=None) sys.stdout.write("Skipping %s\n" % oneline) config["skipped_commits"].append(commit) commits_done += 1 config["commits_done"] = commits_done save_state()
def signoff_limb(): options = config["options"] limb1name = config["limb1"].rstrip("/") limb2name = config["limb2"].rstrip("/") if not limb2name: limb2name = git.current_limb().name limb1 = git.Limb.get(limb1name) if not limb1.exists(): sys.stdout.write("%s: not found\n" % limb1name) sys.exit(1) limb2 = git.Limb.get(limb2name) if not limb2.exists(): sys.stdout.write("%s: not found\n" % limb2name) sys.exit(1) limb1_subnames = git.subnames(limb1name) limb2_subnames = git.subnames(limb2name) signed_off_count = 0 skipped_branchnames = [] for subname in limb2_subnames: limb1_branchname = "%s/%s" % (limb1name, subname) limb2_branchname = "%s/%s" % (limb2name, subname) if subname.startswith("external."): continue if subname not in limb1_subnames: skipped_branchnames.append((limb1_branchname, limb2_branchname)) continue limb1_branch = git.Branch.get(limb1_branchname) limb2_branch = git.Branch.get(limb2_branchname) if limb1_branch.id == limb2_branch.id: continue cmd = ['git', 'checkout', limb2_branchname] git.call(cmd, stdout=sys.stdout, verbose=True) cmd = ['git', 'signoff-mv'] + options + ['%s..' % limb1_branchname] # ignore the error return from git signoff-mv, until it's fixed git.call(cmd, error=None, stdout=sys.stdout, stderr=sys.stderr, verbose=True) signed_off_count += 1 for limb1_branchname, limb2_branchname in skipped_branchnames: sys.stdout.write("%s not found, \n" % limb1_branchname) sys.stdout.write(" NOT signing off on commits in %s\n" % limb2_branchname) else: if not signed_off_count: sys.stdout.write("No new commits to signoff.\n")
def diff_limb(): options = config["options"] limb1name = config["limb1"].rstrip("/") limb2name = config["limb2"].rstrip("/") paths = config["paths"] if not limb1name: limb1name = git.current_limb().name if not limb2name: limb2name = git.current_limb().name limb1 = git.Limb.get(limb1name) if not limb1.exists(): sys.stdout.write("%s: not found\n" % limb1name) sys.exit(1) limb2 = git.Limb.get(limb2name) if not limb2.exists(): sys.stdout.write("%s: not found\n" % limb2name) sys.exit(1) limb1_subnames = git.subnames(limb1name) limb2_subnames = git.subnames(limb2name) not_found = False diff_branches = [] for subname in sorted(set(limb1_subnames + limb2_subnames)): branch1name = "%s/%s" % (limb1name, subname) branch2name = "%s/%s" % (limb2name, subname) if subname not in limb1_subnames: sys.stdout.write("WARNING, non-existent branch: %s\n" % branch1name) not_found = True continue if subname not in limb2_subnames: sys.stdout.write("WARNING, non-existent branch: %s\n" % branch2name) not_found = True continue branch1 = git.Branch.get(branch1name) branch2 = git.Branch.get(branch2name) if branch1.id == branch2.id: continue diff_branches.append([branch1name, branch2name]) if not_found and diff_branches: sys.stdout.write("\n") for branch1name, branch2name in diff_branches: cmd = ['git', '--no-pager', 'diff'] + options cmd.append('%s..%s' % (branch1name, branch2name)) cmd += paths git.call(cmd, stdout=sys.stdout, verbose=True)
def move_commits_to_original_branch(): branch = config["orig_branchname"] if branch != 'detached HEAD': cmd = ['git', 'rev-parse', 'HEAD^0'] head = git.call(cmd).strip() message = "Cherry-pick finished" orig_head = config["orig_head"] cmd = ['git', 'update-ref', '-m', message, branch, head, orig_head] git.call(cmd)
def git_list_dependencies(): limbname = config["limb1"] if not limbname: limbname = git.current_limb().name branch_dep_ref = "%s/limb-info:MONTAVISTA/branch_dependencies" % limbname try: git.call(['git', 'show', branch_dep_ref], stdout=sys.stdout) except: sys.stderr.write("%s not found\n", branch_dep_ref) sys.exit(1)
def do_abort(): restore_state() merge_msg_filename = config["gitdir"] + "/MERGE_MSG" if os.path.isfile(merge_msg_filename): os.remove(merge_msg_filename) cleanup_state() checkout_original_branch() cmd = ['git', 'reset', '--hard'] git.call(cmd, stdout=sys.stdout) sys.exit(0)
def check_clean_state(): cmd = ['git', 'update-index', '--refresh'] try: git.call(cmd, stdout=sys.stdout) except: sys.exit(1) cmd = [ 'git', 'diff-index', '--cached', '--name-status', '-r', 'HEAD^0', '--' ] msg = git.call(cmd) if msg: sys.stdout.write("Your index is not up-to-date\n") sys.stdout.write(msg) sys.exit(1)
def checkout_original_branch(): if config["orig_branchname"] != 'detached HEAD': if not config["nocommit"]: cmd = ["git", "reset", "--hard"] git.call(cmd) prefix_len = len('refs/heads/') cmd = ["git", "checkout", config["orig_branchname"][prefix_len:]] p = subprocess.Popen(cmd, stderr=subprocess.PIPE) errmsg = p.stderr.read() rc = p.wait() if 'Switched to branch ' not in errmsg: sys.stderr.write(errmsg) if rc != 0: sys.stdout.write('"git checkout %s" failed\n' % config["orig_branchname"]) sys.exit(1)
def commit_mv(): no_edit = opt["no-edit"] message_commit = opt["message-commit"] reset_author = opt["reset_author"] commit_options = opt["commit_options"] if message_commit and not reset_author: cmd = [ 'git', 'log', '-1', '--pretty=format:%an\n%ae\n%ai', message_commit.id ] a_name, a_email, a_date = git.call(cmd).splitlines() os.environ["GIT_AUTHOR_NAME"] = a_name os.environ["GIT_AUTHOR_EMAIL"] = a_email os.environ["GIT_AUTHOR_DATE"] = a_date if not no_edit: commit_options.append("-e") msg = commit_message() msgfile = tempfile.NamedTemporaryFile() msgfile.write(msg) msgfile.flush() commit_options += ["--file", msgfile.name] cmd = ['git', 'commit'] + commit_options commit = subprocess.Popen(cmd) rc = commit.wait() msgfile.close() if rc != 0: sys.exit(rc) validate_commit('HEAD^0')
def move_to_detached_head(): cmd = ['git', 'rev-parse', 'HEAD^0'] orig_head = git.call(cmd).strip() config['orig_head'] = orig_head cmd = ['git', 'symbolic-ref', 'HEAD'] orig_branchname = git.call(cmd, stderr=None, error=None).strip() if not orig_branchname: orig_branchname = 'detached HEAD' else: cmd = ['git', 'checkout', orig_head] try: git.call(cmd, stdout=None, stderr=None) except: sys.stderr.write("could not detach HEAD\n") sys.exit(1) config['orig_branchname'] = orig_branchname
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_move_limb(): force = config["force"] recursive = config["recursive"] if config["limb2"]: oldlimbname = config["limb1"] newlimbname = config["limb2"] else: oldlimbname = git.current_limb().name newlimbname = config["limb1"] oldlimb = git.Limb.get(oldlimbname) if not oldlimb.exists(): if not oldlimbname: oldlimbname = '""' sys.stderr.write("%s: not found\n" % oldlimbname) sys.exit(1) newlimb = git.Limb.get(newlimbname) if newlimb.exists(): if force: cmd = ['git', 'branch', '-D'] cmd += git.branchnames(newlimbname, recursive=recursive) git.call(cmd, stdout=sys.stdout) else: sys.stderr.write("%s: already exists. Use -M to overwrite.\n" % newlimbname) sys.exit(1) if force: m_opt = "M" else: m_opt = "m" branchnames = git.branchnames(oldlimbname, recursive=recursive) subnames = [x[(len(oldlimbname) + 1):] for x in branchnames] for subname in subnames: old_name = "%s/%s" % (oldlimbname, subname) new_name = "%s/%s" % (newlimbname, subname) cmd = ['git', 'branch', '-%s' % m_opt, old_name, new_name] git.call(cmd, stdout=sys.stdout, verbose=True)
def select_merge_commits(commits): merge_commits = {} cmd = ["git", "rev-list", "--no-walk", "--parents"] + commits parentlines = git.call(cmd, stderr=None).splitlines() for parentline in parentlines: ids = parentline.split() if len(ids) > 2: merge_commits[ids[0]] = True return merge_commits
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 get_config(var, array=False, required=False): ''' Return the value of the given git config variable ''' try: val = git.call(['git', 'config', var]).strip() if array: val = [x.strip() for x in val.split(',')] except: if required: error('"Server missing config variable %s"\n' % var) if array: val = [] else: val = '' return val
def set_global_constants(): ''' Initialize several global contants used by this program ''' global git_dir global progname progname, ext = os.path.splitext(os.path.basename(sys.argv[0])) if 'GIT_DIR' in os.environ: git_dir = os.path.abspath(os.environ['GIT_DIR']) else: cmd = ['git', 'rev-parse', '--git-dir'] git_dir = git.call(cmd, error=None, stderr=None) if not git_dir: error('No git repository found\n')
def cherry_pick_mv(): set_gitdir() if config["abort"]: do_abort() if config["continue"] or config["skip"]: do_continue_or_skip() else: initialize_commits() commits = config["commits"] commits_done = config["commits_done"] for commit in commits[commits_done:]: do_cherry_pick(commit) do_commit(commit) commits_done += 1 config["commits_done"] = commits_done save_state() if len(commits) > 1: if config["skipped_commits"]: count = len(config["skipped_commits"]) if count == 1: str = "commit was" else: str = "%d commits were" % count sys.stderr.write("The following %s skipped:\n" % str) for commit in config["skipped_commits"]: cmd = [ 'git', '--no-pager', 'log', '-1', '--pretty=format:%h %s\n', commit ] oneline = git.call(cmd).rstrip() sys.stderr.write(" %s\n" % oneline) move_commits_to_original_branch() checkout_original_branch() cleanup_state()
def set_global_constants(): ''' Initialize several global contants used by this program ''' def get_config(var, array=False, required=False): ''' Return the value of the given git config variable ''' try: val = git.call(['git', 'config', var]).strip() if array: val = [x.strip() for x in val.split(',')] except: if required: error('"Server missing config variable %s"\n' % var) if array: val = [] else: val = '' return val global git_dir global progname global debug_flag global gatekeeper_groups global gatekeepers global gitadmin_groups global gitadmins global email_recipients global user global project_desc global project_url global commit_url_fmt global bugz_url_fmt progname, ext = os.path.splitext(os.path.basename(sys.argv[0])) if 'GIT_DIR' in os.environ: git_dir = os.path.abspath(os.environ['GIT_DIR']) if git_dir.startswith(git_base_dir): rel_dir = git_dir[(len(git_base_dir) + 1):] else: rel_dir = git_dir else: usage() notice('\n') debug_flag = get_config('mvista.debug') if debug_flag != '0' and debug_flag != 'False' and debug_flag != 'off': debug_flag = True notice('%s\n' % progname) else: debug_flag = False gatekeeper_groups = get_config('mvista.gatekeeper-groups', array=True) gatekeepers = get_config('mvista.gatekeepers', array=True) gitadmin_groups = get_config('mvista.gitadmin-groups', array=True) gitadmins = get_config('mvista.gitadmins', array=True) email_recipients = get_config('mvista.dev.push-recipients', array=True, required=True) cmd = ['head', '-1', os.path.join(git_dir, "description")] project_desc = git.call(cmd, error=False).strip() if not project_desc or project_desc.startswith('Unnamed repository; edit'): notice('Warning: project description file not set on server\n') project_url = 'http://%s/?p=%s;a=summary' % (git_server, rel_dir) commit_url_fmt = 'http://%s/?p=%s;a=commitdiff;h=%%s' % \ (git_server, rel_dir) bugz_url_fmt = 'http://%s/show_bug.cgi?id=%%s' % bugz_server user = git.User() check_errors()
def push_limb(): re_parent = re.compile(r'(.*)/bugfixes/\d+[^/]*') options = config["options"] repo = config["repo"] localname = config["local"].rstrip("/") remotename = config["remote"].rstrip("/") nofetch = config["nofetch"] if not remotename: if not localname: localname = git.current_limb().name remotename = localname if not localname or not nofetch: git.call(['git', 'fetch', repo], stdout=sys.stdout, verbose=True) git.call(['git', 'remote', 'prune', repo], stdout=sys.stdout, verbose=True) if not localname: remote_branchnames = git.branchnames("%s/%s" % (repo, remotename)) if not remote_branchnames: sys.stdout.write("remote limb %s not found\n" % remotename) sys.exit(1) del_prefix_len = len(repo) + 1 cmd = ['git', 'push'] + options + [repo] cmd += [":%s" % x[del_prefix_len:] for x in remote_branchnames] git.call(cmd, stdout=sys.stdout, verbose=True) return local = git.Limb.get(localname) if not local.exists(): sys.stdout.write("local limb %s not found\n" % localname) sys.exit(1) if not nofetch: # call "git analyze-changes" before pushing cmd = ['git', 'analyze-changes', '-r', repo] if local != git.current_limb(): cmd.append(localname) try: git.call(cmd, stdout=sys.stdout, verbose=True) except: sys.stderr.write( "git analyze-changes failed. No branches pushed.\n") sys.exit(1) time.sleep(5) local_subnames = git.subnames(localname) nff_names = [] rebased_names = [] branchnames = [] for subname in local_subnames: branchname = "%s/%s" % (localname, subname) repo_branchname = "%s/%s/%s" % (repo, remotename, subname) repo_branch = git.Branch.get(repo_branchname) branch = git.Branch.get(branchname) if repo_branch.id and repo_branch.id == branch.id: continue rebased = False match = re_parent.match(remotename) if match: parentname = match.group(1) parent_branchname = "%s/%s/%s" % (repo, parentname, subname) parent_branch = git.Branch.get(parent_branchname) rebased = parent_branch.id and not branch.contains(parent_branch) if rebased: rebased_names.append(branchname) elif repo_branch.id and not branch.contains(repo_branch): nff_names.append(branchname) if localname != remotename: branchname = "%s:%s" % (branchname, "%s/%s" % (remotename, subname)) branchnames.append(branchname) force = "-f" in options or "--force" in options if rebased_names and not force: parentname = "%s/%s" % (repo, parentname) sys.stdout.write("\nNon-fast-forward when compared to %s:\n" % parentname) for branchname in rebased_names: sys.stdout.write(" %s\n" % branchname) sys.stdout.write('\nPlease do "git rebase-limb %s".\n' % parentname) sys.stdout.write("Or if this is what you want, " "re-push the limb using --force.\n") sys.stdout.write("\nNo branches pushed.\n") return if nff_names and not force: sys.stdout.write("\nNon-fast-forward:\n") for branchname in nff_names: sys.stdout.write(" %s\n" % branchname) sys.stdout.write("\nIf this is what you want, " "re-push the limb using --force.\n") sys.stdout.write("\nNo branches pushed.\n") return if not branchnames: sys.stdout.write("No updated or new branches to push.\n") return cmd = ['git', 'push'] + options + [repo] + branchnames git.call(cmd, stdout=sys.stdout, verbose=True)
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")
def git_call_with_err(cmd, errstart): try: strout = git.call(cmd) except git.GitError, e: sys.stderr.write(errstart + ": " + e.msg + "\n") sys.exit(1)
config['addsignoff'] = False elif option in ('-f', '--force'): config["force"] = True if len(args) == 0: usage() config["revlist"] = args if name and email: if email[0] != '<': email = "<%s>" % email committer = "%s %s" % (name, email) else: cmd = ['git', 'var', 'GIT_COMMITTER_IDENT'] ident = git.call(cmd) committer = ident[0:(ident.rindex('>') + 1)] if name: email = committer[committer.index('<'):] if email[0] != '<': email = "<%s>" % email committer = "%s %s" % (name, email) elif email: name = committer[0:(committer.index('<') - 1)] committer = "%s %s" % (name, email) config['committer'] = committer def signoff_mv():
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 file_lines(branch, path): ref = '%s:%s' % (branch.name, path) cmd = ['git', 'show', ref] return git.call(cmd, stderr=None).splitlines()
def log_limbs(): options = config["options"] separator = config["separator"] limb1name = config["limb1"].rstrip("/") limb2name = config["limb2"].rstrip("/") paths = config["paths"] if not limb1name: limb1name = git.current_limb().name if not separator: for option in options: if option.startswith("--max-count"): break else: options.append("--max-count=1") been_here = False limb1 = git.branchnames(limb1name) for branchname in git.branchnames(limb1name): cmd = ['git', '--no-pager', 'log'] + options cmd.append(branchname) cmd += paths if been_here: sys.stdout.write("\n") else: been_here = True git.call(cmd, stdout=sys.stdout, verbose=True) sys.exit(0) if not limb2name: limb2name = git.current_limb().name limb1 = git.Limb.get(limb1name) if not limb1.exists(): sys.stdout.write("%s: not found\n" % limb1name) sys.exit(1) limb2 = git.Limb.get(limb2name) if not limb2.exists(): sys.stdout.write("%s: not found\n" % limb2name) sys.exit(1) limb1_subnames = git.subnames(limb1name) limb2_subnames = git.subnames(limb2name) not_found = False log_branches = [] for subname in sorted(set(limb1_subnames + limb2_subnames)): branch1name = "%s/%s" % (limb1name, subname) branch2name = "%s/%s" % (limb2name, subname) if subname not in limb1_subnames: sys.stdout.write("WARNING, non-existent branch: %s\n" % branch1name) not_found = True continue if subname not in limb2_subnames: sys.stdout.write("WARNING, non-existent branch %s\n" % branch2name) not_found = True continue branch1 = git.Branch.get(branch1name) branch2 = git.Branch.get(branch2name) if branch1.id == branch2.id: continue log_branches.append([branch1name, branch2name]) if not_found and log_branches: sys.stdout.write("\n") been_here = False for branch1name, branch2name in log_branches: range = "%s%s%s" % (branch1name, separator, branch2name) cmd = ['git', 'rev-list'] + [range] + paths if not bool(git.call(cmd)): continue if been_here: sys.stdout.write("\n") else: been_here = True cmd = ['git', '--no-pager', 'log'] + options + [range] + paths 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 merge_limb(): options = config["options"] remotename = config["remote"] limbname = config["limb"] if limbname: limbname = limbname.rstrip('/') limb = git.Limb.get(limbname) branch = limb.repository_branches()[0] git.call(['git', 'checkout', branch], stdout=sys.stdout, verbose=True) else: limb = git.current_limb() limbname = limb.name remote = git.Limb.get(remotename) remotename = remote.name.rstrip("/") if not limb.exists(): sys.stdout.write("%s: not found\n" % limbname) sys.exit(1) if not remote.exists(): sys.stdout.write("%s: not found\n" % remotename) sys.exit(1) limb_subnames = git.subnames(limbname) remote_subnames = git.subnames(remotename) for subname in remote_subnames: if subname not in limb_subnames: limb_branchname = "%s/%s" % (limbname, subname) remote_branchname = "%s/%s" % (remotename, subname) cmd = ['git', 'branch', limb_branchname, remote_branchname] git.call(cmd, stdout=sys.stdout, verbose=True) for subname in limb_subnames: if subname not in remote_subnames: continue limb_branchname = "%s/%s" % (limbname, subname) remote_branchname = "%s/%s" % (remotename, subname) limb_branch = git.Branch.get(limb_branchname) remote_branch = git.Branch.get(remote_branchname) if limb_branch.contains(remote_branch): sys.stdout.write("%s is up-to-date.\n" % limb_branchname) continue try: cmd = ['git', 'checkout', limb_branchname] git.call(cmd, stdout=sys.stdout, verbose=True) cmd = ['git', 'merge', remote_branchname] git.call(cmd, stdout=sys.stdout, verbose=True) except git.GitError: cmdline = ' '.join([re.sub(".*/", "", sys.argv[0])] + sys.argv[1:]) sys.stdout.write("\n") sys.stdout.write("After resolving this issue, you may continue\n") sys.stdout.write("the merge by re-running the command:\n") sys.stdout.write(" %s\n" % cmdline) if config["debug"]: sys.stdout.write("\n") raise sys.exit(1)
def commit_message(): message_commit = opt["message-commit"] addsignoff = opt["addsignoff"] subject = ("Oneline summary of change, less then 60 characters\n" "# *** Leave above line blank for clean log formatting ***") source = "MontaVista Software, LLC | Cavium Networks, Inc | URL | Some Guy <email@addr>" bugz = "Bugzilla bug number" type = "Defect Fix | Security Fix | Enhancement | Integration" disposition = ("Submitted to | Needs submitting to | Merged from |" " Accepted by | Rejected by | Backport from | Local") changeid = None body = [] if message_commit: subject = '\n'.join(message_commit.subject) body = message_commit.body mv_header_lines = message_commit.mv_header_lines mv_header_dict = message_commit.mv_header_dict body = body[len(mv_header_lines):] if opt['add-picked-message']: body.append("(cherry picked from commit %s)" % message_commit.id) # override defaults with what is in mv style header if 'mr' in mv_header_dict: bugz = mv_header_dict['mr'] if 'source' in mv_header_dict: source = mv_header_dict['source'] if 'type' in mv_header_dict: type = mv_header_dict['type'] if 'disposition' in mv_header_dict: disposition = mv_header_dict['disposition'] if 'changeid' in mv_header_dict: changeid = mv_header_dict['changeid'] # Use NCD source and dispostion. # Save NCD bugz # if opt.get('ncd', ""): if 'changeid' in mv_header_dict: body.append("(cherry picked from ncd %s)" % message_commit.id) if bugz.startswith('Bugzilla'): bugz = opt["bugz"] else: body.append("NCD Bug#: %s" % bugz) bugz = opt["bugz"] if not opt.get('ncd', ""): if opt["source"]: source = opt["source"] if opt["disposition"]: disposition = opt["disposition"] else: if 'source' not in mv_header_dict: source = opt["source"] if 'disposition' not in mv_header_dict: disposition = opt["disposition"] if opt["bugz"]: if bugz.startswith('Bugzilla'): bugz = opt["bugz"] else: if opt.get('reset_bugz'): bugz = opt["bugz"] if not opt.get('ncd', '') or not opt.get('reset_bugz'): bugz = bugz.split(',', 2)[0].strip() if bugz != opt["bugz"]: bugz += ", " + opt["bugz"] if opt["type"]: type = opt["type"] if addsignoff: cmd = ['git', 'var', 'GIT_COMMITTER_IDENT'] ident = git.call(cmd) ident = ident[0:(ident.rindex('>') + 1)] signoff_line = "Signed-off-by: " + ident if signoff_line not in body: if not body or ("-by: " not in body[-1] and not body[-1].lower().startswith('cc:')): body.append("") body.append(signoff_line) header = """%s Source: %s MR: %s Type: %s Disposition: %s """ % (subject, source, bugz, type, disposition) body = '\n'.join(body) + '\n' if opt["delete_changeid"]: changeid = None else: if opt["changeid"]: changeid = opt["changeid"] elif not changeid: changeid = generate_changeid(header, body) if changeid: header += "ChangeID: %s\n" % changeid if not body.startswith("Description:\n"): header += "Description:\n\n" return header + body