def main(argv): assert len(argv) == 1, "No arguments expected" upfn = upstream cur = current_branch() if cur == "HEAD": upfn = lambda b: git_hash(upstream(b)) cur = git_hash(cur) downstreams = [b for b in branches() if upfn(b) == cur] if not downstreams: return "No downstream branches" elif len(downstreams) == 1: run_git("checkout", downstreams[0]) else: high = len(downstreams) - 1 print while True: print "Please select a downstream branch" for i, b in enumerate(downstreams): print " %d. %s" % (i, b) r = raw_input("Selection (0-%d)[0]: " % high).strip() or "0" if not r.isdigit() or (0 > int(r) > high): print "Invalid choice." else: run_git("checkout", downstreams[int(r)]) break
def rebase(parent, start, branch, abort=False): try: run_git('rebase', '--onto', parent, start, branch) return RebaseRet(True, '') except CalledProcessError as cpe: if abort: run_git('rebase', '--abort') return RebaseRet(False, cpe.output)
def resolve(target): """Return the generation number for target. As a side effect, record any new calculated data to the git repository. """ num = get_num(target) if num is not None: return num if git_tree(REF) is None: empty = git_mktree({}) ref = run_git('commit-tree', '-m', 'Initial commit from git-number', empty) run_git('update-ref', REF, ref) with ScopedPool() as pool: available = pool.apply_async(git_tree, args=(REF,), kwds={'recurse': True}) preload = set() rev_list = [] with StatusPrinter('Loading commits: %d') as inc: for line in run_git('rev-list', '--topo-order', '--parents', '--reverse', hexlify(target), '^'+REF).splitlines(): toks = map(unhexlify, line.split()) rev_list.append((toks[0], toks[1:])) preload.update(t[:PREFIX_LEN] for t in toks) inc() preload.intersection_update( unhexlify(k.replace('/', '')) for k in available.get().iterkeys() ) preload.difference_update((x,) for x in get_num_tree.cache) if preload: preload_iter = pool.imap_unordered(preload_tree, preload) with StatusPrinter('Preloading nurbs: (%%d/%d)' % len(preload)) as inc: for prefix, tree in preload_iter: get_num_tree.cache[prefix,] = tree inc() get_num_tree.default_enabled = True for ref, pars in rev_list: num = set_num(ref, max(map(get_num, pars)) + 1 if pars else 0) finalize(hexlify(target)) return num
def fix_head(target): try: git_dir = run_git('rev-parse', '--git-dir') with open(os.path.join(git_dir, 'HEAD'), 'wb') as f: f.write(target) except CalledProcessError as e: print e, e.out_err
def main(): force = '-f' in sys.argv if force: sys.argv.remove('-f') StatusPrinter.ENABLED = True target = hexlify(parse_one_committish()) print 'Got Target: %s' % target fix_head(target) run_git('reset', '-q', target) if force: force_checkout(git_tree(target, recurse=True)) else: fancy_checkout()
def finalize(target): """After calculating the generation number for |target|, call finalize to save all our work to the git repository. """ if not DIRTY_TREES: return msg = 'git-number Added %s numbers' % sum(DIRTY_TREES.itervalues()) idx = os.path.join(run_git('rev-parse', '--git-dir'), 'number.idx') env = {'GIT_INDEX_FILE': idx} with StatusPrinter('Finalizing: (%%d/%d)' % len(DIRTY_TREES)) as inc: run_git('read-tree', REF, env=env) prefixes_trees = ((p, get_num_tree(p)) for p in sorted(DIRTY_TREES)) updater = subprocess.Popen(['git', 'update-index', '-z', '--index-info'], stdin=subprocess.PIPE, env=env) with ScopedPool() as leaf_pool: for item in leaf_pool.imap(leaf_map_fn, prefixes_trees): updater.stdin.write(item) inc() updater.stdin.close() updater.wait() run_git('update-ref', REF, run_git('commit-tree', '-m', msg, '-p', git_hash(REF), '-p', target, run_git('write-tree', env=env)))
def check_versions(args, packages): error = False # Get relevant commits: compare HEAD against upstream branch or HEAD~1 # (the latter if this CI check is running on upstream branch). Note that # for the common.get_changed_files() code, we don't check against # upstream branch HEAD, but against the latest common ancestor. This is not # desired here, since we already know what packages changed, and really # want to check if the version was increased towards *current* upstream # branch HEAD. commit = f"upstream/{common.get_upstream_branch()}" if common.run_git(["rev-parse", "HEAD"]) == common.run_git(["rev-parse", commit]): print(f"NOTE: {commit} is on same commit as HEAD, comparing" " HEAD against HEAD~1.") commit = "HEAD~1" for package in packages: # Get versions, skip new packages head = get_package_version(args, package, "HEAD") upstream = get_package_version(args, package, commit, False) if not upstream: if head.rpartition('r')[2] != "0": print(f"- {package}: {head} (HEAD) (new package) [ERROR]") error = True else: print(f"- {package}: {head} (HEAD) (new package)") continue # Compare head and upstream versions result = pmb.parse.version.compare(head, upstream) if result != 1: error = True # Print result line ("- hello-world: 1-r2 (HEAD) > 1-r1 (HEAD~1)") formatstr = "- {}: {} (HEAD) {} {} ({})" if result != 1: formatstr += " [ERROR]" operator = version_compare_operator(result) print(formatstr.format(package, head, operator, upstream, commit)) if error: exit_with_error_message()
def main(): if '--clean' in sys.argv: clean_refs() return 0 orig_branch = current_branch() if orig_branch == 'HEAD': orig_branch = git_hash('HEAD') if 'origin' in run_git('remote').splitlines(): run_git('fetch', 'origin', stderr=None) else: run_git('svn', 'fetch', stderr=None) branch_tree = {} for branch in branches(): parent = upstream(branch) if not parent: print 'Skipping %s: No upstream specified' % branch continue branch_tree[branch] = parent starting_refs = {} for branch, parent in branch_tree.iteritems(): starting_refs[branch] = get_or_create_merge_base_tag(branch, parent) if VERBOSE: pprint(branch_tree) pprint(starting_refs) # XXX There is a more efficient way to do this, but for now... while branch_tree: this_pass = [i for i in branch_tree.items() if i[1] not in branch_tree] for branch, parent in this_pass: clean_branch(branch, parent, starting_refs[branch]) del branch_tree[branch] clean_refs() bclean() if orig_branch in branches(): run_git('checkout', orig_branch) else: run_git('checkout', 'origin/master') return 0
def clean_branch(branch, parent, starting_ref): if (git_hash(parent) != git_hash(starting_ref) and git_hash(branch) != git_hash(starting_ref)): print 'Rebasing:', branch # Try a plain rebase first if rebase(parent, starting_ref, branch, abort=True).success: return # Maybe squashing will help? print "Failed! Attempting to squash", branch, "...", squash_branch = branch+"_squash_attempt" run_git('checkout', '-b', squash_branch) squash() squash_ret = rebase(parent, starting_ref, squash_branch, abort=True) run_git('checkout', branch) run_git('branch', '-D', squash_branch) if squash_ret.success: print 'Success!' squash() final_rebase = rebase(parent, starting_ref, branch) assert final_rebase.success == squash_ret.success if not squash_ret.success: print squash_ret.message print 'Failure :(' print 'Your working copy is in mid-rebase. Please completely resolve and' print 'run `git reup` again.' sys.exit(1)
def main(argv): assert 2 <= len(argv) < 3, "Must supply (<newname>) or (<oldname> <newname>)" if len(argv) == 2: old_name = current_branch() new_name = argv[1] else: old_name = argv[1] new_name = argv[2] assert old_name in branches(), "<oldname> must exist" assert new_name not in branches(), "<newname> must not exist" run_git('branch', '-m', old_name, new_name) matcher = re.compile(r'^branch\.(.*)\.merge$') branches_to_fix = [] for line in run_git('config', '-l').splitlines(): key, value = line.split('=', 1) if value == 'refs/heads/' + old_name: m = matcher.match(key) if m: branch = m.group(1) remote = run_git('config', '--get', 'branch.%s.remote' % branch) if remote == '.': branches_to_fix.append(branch) for b in branches_to_fix: run_git('config', 'branch.%s.merge' % b, 'refs/heads/' + new_name)
def bclean(): merged = list(branches('--merged', 'origin/master')) if VERBOSE: print merged upstreams = {} downstreams = collections.defaultdict(list) for branch in branches(): try: parent = upstream(branch) upstreams[branch] = parent downstreams[parent].append(branch) except CalledProcessError: pass if VERBOSE: print upstreams print downstreams if current_branch() in merged: run_git('checkout', 'origin/master') for branch in merged: for down in downstreams[branch]: if down not in merged: run_git('branch', '--set-upstream-to', upstreams[branch], down) print ('Reparented %s to track %s (was tracking %s)' % (down, upstreams[branch], branch)) print run_git('branch', '-d', branch) return 0
def get_package_version(args, package, revision, check=True): # Redirect stderr to /dev/null, so git doesn't complain about files not # existing in master for new packages stderr = None if not check: stderr = subprocess.DEVNULL # Run something like "git show upstream/master:main/hello-world/APKBUILD" pmaports_dir = common.get_pmaports_dir() pattern = pmaports_dir + "/**/" + package + "/APKBUILD" path = glob.glob(pattern, recursive=True)[0][len(pmaports_dir + "/"):] apkbuild_content = common.run_git(["show", revision + ":" + path], check, stderr) if not apkbuild_content: return None # Save APKBUILD to a temporary path and parse it from there. (Not the best # way to do things, but good enough for this CI script.) with tempfile.TemporaryDirectory() as tempdir: with open(tempdir + "/APKBUILD", "w", encoding="utf-8") as handle: handle.write(apkbuild_content) parsed = pmb.parse.apkbuild(args, tempdir + "/APKBUILD", False, False) return parsed["pkgver"] + "-r" + parsed["pkgrel"]
def fancy_checkout(): made_dirs = set() # Curiously, this is faster than REPO.status(), even on *nix. opts = ['--porcelain', '-z', '--ignore-submodules=dirty'] f_diff = run_git('status', *opts).split('\0') total = (len(f_diff) - 1) fmt = FMT % total if not total: return with StatusPrinter(fmt) as inc: ign_inc = lambda *_: inc() with ScopedPool(PROC_COUNT, initializer=init_repo) as pool: for mode, path in (x.split(None, 1) for x in f_diff if x): # technically, path could be 'from\0to', but that only happens for # rename and copy status we don't support. if mode[0] in 'DMA?': handle_dir(made_dirs, path) pool.apply_async(handle_file_lookup, (path,), callback=ign_inc) else: print ("Got unexpected mode: %s %s" % (mode, path)) assert False
def main(argv): assert len(argv) == 2, "Must supply new parent" branch = current_branch() new_parent = argv[1] cur_parent = upstream(branch) assert branch != 'HEAD', 'Must be on the branch you want to reparent' assert cur_parent != new_parent get_or_create_merge_base_tag(branch, cur_parent) print "Reparenting %s to track %s (was %s)" % (branch, new_parent, cur_parent) run_git('branch', '--set-upstream-to', new_parent, branch) try: cmd = ['reup'] + (['--verbose'] if VERBOSE else []) run_git(*cmd, stdout=None, stderr=None) except: print "Resetting parent back to %s" % (cur_parent) run_git('branch', '--set-upstream-to', cur_parent, branch) raise return 0
def init_repo(): global REPO, TREE_ROOT if not REPO: git_dir = run_git('rev-parse', '--git-dir') REPO = pygit2.Repository(git_dir) TREE_ROOT = REPO.revparse_single('HEAD').tree
def squash(): branch = current_branch() parent = upstream(branch) merge_base = get_or_create_merge_base_tag(branch, parent) run_git('reset', '--soft', merge_base) run_git('commit', '-a', '-C', 'HEAD@{1}')