Skip to content

vcs.py

Utilities related to VCS.

checkout_latest_tag(local_repo, use_prereleases=False)

Checkout latest git tag and check it out, sorted by PEP 440.

Parameters:

Name Type Description Default
local_repo Union[str, pathlib.Path]

A git repository in the local filesystem.

required
use_prereleases Optional[bool]

If False, skip prerelease git tags.

False
Source code in copier/vcs.py
def checkout_latest_tag(local_repo: StrOrPath, use_prereleases: OptBool = False) -> str:
    """Checkout latest git tag and check it out, sorted by PEP 440.

    Parameters:
        local_repo:
            A git repository in the local filesystem.
        use_prereleases:
            If `False`, skip prerelease git tags.
    """
    with local.cwd(local_repo):
        all_tags = git("tag").split()
        if not use_prereleases:
            all_tags = filter(
                lambda tag: not version.parse(tag).is_prerelease, all_tags
            )
        sorted_tags = sorted(all_tags, key=version.parse, reverse=True)
        try:
            latest_tag = str(sorted_tags[0])
        except IndexError:
            print(
                colors.warn | "No git tags found in template; using HEAD as ref",
                file=sys.stderr,
            )
            latest_tag = "HEAD"
        git("checkout", "--force", latest_tag)
        git("submodule", "update", "--checkout", "--init", "--recursive", "--force")
        return latest_tag

clone(url, ref=None)

Clone repo into some temporary destination.

Includes dirty changes for local templates by copying into a temp directory and applying a wip commit there.

Parameters:

Name Type Description Default
url str

Git-parseable URL of the repo. As returned by get_repo.

required
ref Optional[str]

Reference to checkout. For Git repos, defaults to HEAD.

None
Source code in copier/vcs.py
def clone(url: str, ref: OptStr = None) -> str:
    """Clone repo into some temporary destination.

    Includes dirty changes for local templates by copying into a temp
    directory and applying a wip commit there.

    Args:
        url:
            Git-parseable URL of the repo. As returned by
            [get_repo][copier.vcs.get_repo].
        ref:
            Reference to checkout. For Git repos, defaults to `HEAD`.
    """

    location = tempfile.mkdtemp(prefix=f"{__name__}.clone.")
    _clone = git["clone", "--no-checkout", url, location]
    # Faster clones if possible
    if GIT_VERSION >= Version("2.27"):
        _clone = _clone["--filter=blob:none"]
    _clone()

    if not ref and os.path.exists(url) and Path(url).is_dir():
        is_dirty = False
        with local.cwd(url):
            is_dirty = bool(git("status", "--porcelain").strip())
        if is_dirty:
            url_abspath = Path(url).absolute()
            with local.cwd(location):
                git("--git-dir=.git", f"--work-tree={url_abspath}", "add", "-A")
                git(
                    "--git-dir=.git",
                    f"--work-tree={url_abspath}",
                    "commit",
                    "-m",
                    "Copier automated commit for draft changes",
                    "--no-verify",
                )
                warn(
                    "Dirty template changes included automatically.",
                    DirtyLocalWarning,
                )

    with local.cwd(location):
        git("checkout", ref or "HEAD")
        git("submodule", "update", "--checkout", "--init", "--recursive", "--force")

    return location

get_repo(url)

Transforms url into a git-parseable origin URL.

Parameters:

Name Type Description Default
url str

Valid examples:

required
Source code in copier/vcs.py
def get_repo(url: str) -> OptStr:
    """Transforms `url` into a git-parseable origin URL.

    Args:
        url:
            Valid examples:

            - gh:copier-org/copier
            - gl:copier-org/copier
            - git@github.com:copier-org/copier.git
            - git+https://mywebsiteisagitrepo.example.com/
            - /local/path/to/git/repo
            - /local/path/to/git/bundle/file.bundle
    """
    for pattern, replacement in REPLACEMENTS:
        url = re.sub(pattern, replacement, url)
    url_path = Path(url)
    if not (
        url.endswith(GIT_POSTFIX)
        or url.startswith(GIT_PREFIX)
        or is_git_repo_root(url_path)
        or is_git_bundle(url_path)
    ):
        return None

    if url.startswith("git+"):
        url = url[4:]
    return url

is_git_bundle(path)

Indicate if a path is a valid git bundle.

Source code in copier/vcs.py
def is_git_bundle(path: Path) -> bool:
    """Indicate if a path is a valid git bundle."""
    with TemporaryDirectory(prefix=f"{__name__}.is_git_bundle.") as dirname:
        with local.cwd(dirname):
            git("init")
            return bool(git["bundle", "verify", path] & TF)

is_git_repo_root(path)

Indicate if a given path is a git repo root directory.

Source code in copier/vcs.py
def is_git_repo_root(path: StrOrPath) -> bool:
    """Indicate if a given path is a git repo root directory."""
    try:
        with local.cwd(Path(path, ".git")):
            return bool(git("rev-parse", "--is-inside-git-dir").strip() == "true")
    except OSError:
        return False

is_in_git_repo(path)

Indicate if a given path is in a git repo directory.

Source code in copier/vcs.py
def is_in_git_repo(path: StrOrPath) -> bool:
    """Indicate if a given path is in a git repo directory."""
    try:
        git("-C", path, "rev-parse", "--show-toplevel")
        return True
    except (OSError, ProcessExecutionError):
        return False
Back to top