Source code for git_well.git_track_upstream

#!/usr/bin/env python
"""
Requirements:
    pip install GitPython
"""

from __future__ import annotations

from typing import Any
import ubelt as ub
import scriptconfig as scfg


[docs] class TrackUpstreamCLI(scfg.DataConfig): """ Set the branch upstream with sensible defaults if possible. This script can auto-choose sensible default if there is only one remote that also has the working branch. When there is an ambiguity the user will be asked to choose from a list of available remotes with this branch. Once the remote is found the script executes: ..code:: bash git branch --set-upstream-to=<remote>/<branch> <branch> """ __command__: str = 'track_upstream' repo_dpath: scfg.Value = scfg.Value( '.', position=1, help='location of the repo' ) force: scfg.Value = scfg.Value( False, isflag=True, short_alias=['-f'], help='if True, then choose a new tracking branch even if one is set', )
[docs] @classmethod def main( cls, argv: list[str] | str | bool | None = True, **kwargs: Any ) -> None: """ Example: >>> from git_well.git_track_upstream import TrackUpstreamCLI >>> from git_well.repo import Repo >>> repo = Repo.demo() >>> repo.cmd('git remote add origin https://github.com/Erotemic/git_well.git') >>> # TODO: make this test work without the network >>> repo.cmd('git fetch origin') >>> repo.cmd('git reset --hard origin/main') >>> argv = False >>> cls = TrackUpstreamCLI >>> kwargs = cls() >>> kwargs['repo_dpath'] = repo >>> cls.main(argv=argv, **kwargs) """ config = cls.cli(argv=argv, data=kwargs) from git_well._utils import rich_print rich_print('config = {}'.format(ub.urepr(config, nl=1))) from git_well.repo import Repo repo = Repo.coerce(config['repo_dpath']) assert not repo.active_branch.is_remote() assert repo.active_branch.is_valid() tracking_branch = repo.head.reference.tracking_branch() print('tracking_branch = {}'.format(ub.urepr(tracking_branch, nl=1))) if tracking_branch is not None: print(f'tracking_branch is already set to {tracking_branch}.') else: print('tracking branch is not set.') find_new = config.force or (tracking_branch is None) if find_new: print('Finding new tracking branch') branch = repo.active_branch unique_infos = unique_remotes_with_branch(repo, branch) if len(unique_infos) != 1: from git_well._utils import choice_prompt print('unique_infos = {}'.format(ub.urepr(unique_infos, nl=2))) name_to_info = {d['name']: d for d in unique_infos} choices = list(name_to_info.keys()) ans = choice_prompt( 'Sensible defaults are ambiguous. Choose one.', choices=choices, ) chosen = name_to_info[ans] else: chosen = unique_infos[0] print('Chose sensible default: {!r}'.format(chosen)) valid_refs = chosen['valid_refs'] assert len(valid_refs) == 1 ref = valid_refs[0] print('Setting tracking branch to: {!r}'.format(ref)) repo.active_branch.set_tracking_branch(ref) else: print('Doing nothing.')
[docs] def unique_remotes_with_branch(repo: Any, branch: Any) -> list[dict[str, Any]]: available_remotes = repo.remotes remote_infos = {} for remote in available_remotes: valid_refs = [] for ref in remote.refs: if ref.name[len(ref.remote_name) :].lstrip('/') == branch.name: valid_refs.append(ref) if not valid_refs: continue info = {'remote': remote, 'name': remote.name, 'valid_refs': valid_refs} remote_infos[remote.name] = info ref_urls = tuple( sorted(set(ub.flatten(list(remote.urls) for ref in remote.refs))) ) info['ref_urls'] = ref_urls groups = ub.group_items(remote_infos.values(), key=lambda x: x['ref_urls']) unique_infos = [] for key, group in groups.items(): chosen = sorted( group, key=lambda x: ((0 if x['name'] == 'origin' else 1), x['name']), )[0] unique_infos.append(chosen) return unique_infos
__cli__ = TrackUpstreamCLI main = __cli__.main if __name__ == '__main__': TrackUpstreamCLI.main()