Skip to main content

git-project - The extensible stupid project manager

VersionImageLink

PythonVersionImageLink


Installation

pip install git-project
pip install git-project-core-plugins

git-project needs Python 3.10 or later.

Overview

git-project is a git extension for managing development work in a git repository. By itself it does almost nothing. It provides -h, --version and --menu, and plugins provide the commands.

git-project-core-plugins provides the basic commands, among them clone, init, worktree, branch, run and config. Install it alongside git-project.

git-project aims to make switching between tasks in a repository fast, without losing the state of the tasks you set aside. For example, the core plugins can give each worktree its own build directory, so moving to another worktree does not rebuild everything.

Projects

git-project runs under the name of a link to it, and that name selects the active project. If git-fizzbin is a symlink to git-project, then git fizzbin <command> runs git-project with fizzbin as the active project. Run as git-project itself, the active project is project. These docs write git <project> for whichever name you use.

Create the link yourself, in a directory on your PATH:

ln -s "$(command -v git-project)" ~/.local/bin/git-fizzbin

Each project keeps its settings apart from the others, so one repository can hold several projects, each run through its own link.

Configuration

git-project stores its settings in the repository’s git config. A project’s settings live in a section named after the project. git-project changes . and _ in the name to -, so the project fizz_bin uses the section fizz-bin.

Whenever they are missing, git-project sets two values in the project section: branch, the repository’s main branch, and remote, which is origin.

Plugins keep their own settings in subsections of the project section. For example, a project with one worktree might hold:

[fizzbin]
    branch = main
    remote = origin
    srcdir = /src
[fizzbin "worktree.main"]
    builddir = {srcdir}/build

A key can hold more than one value. On every run, git-project also checks the config file and stops if one section holds the same key = value line twice.

Scopes

A scope is a subsection that a plugin makes active for the current run. While a scope is active, a value set in the scope overrides the same key in the project section. For example, when you run inside a worktree, the core plugins’ worktree plugin makes that worktree’s subsection a scope. A value set for one worktree then applies only there.

The name of an active scope is also a substitution variable, and its value is the scope’s identifier. In the example above, {worktree} is main inside the main worktree.

Substitution

Some values are substituted before they are used, for example the commands that the run plugin runs. Substitution replaces {name} with the value of name. A name can be:

  • a key in the project section

  • a key in the object being substituted, or in an active scope

  • the name of an active scope, as above

  • one of these built-in names

project

The active project’s section name

branch

The checked-out branch, or during a rebase the branch being rebased

gitdir

The repository’s git directory

git_common_dir

The git directory that all worktrees share

git_workdir

The root of the current worktree

Substitution repeats until the value stops changing, so a value can name another value that itself contains {name}. A value may not name itself. To write a literal brace, write {{} for { and {}} for }. A name is ASCII letters, digits and underscores, and does not start with a digit. Other text in single braces, such as {x.upper()} or {}, stays as written, but a doubled {{ or }} becomes one brace. A name that is not defined is an error.

Substitution inserts each value as written, and the run plugin runs its commands through a shell. Treat the git config as code, and do not include config from a source you do not trust.

Getting help

git <project> -h lists the commands that the installed plugins provide. Use -h there, because git turns git <project> --help into a request for a man page. After a command name --help works as usual, and with the core plugins installed git <project> help <command> shows a command’s full manual.

--menu lists a command’s subcommands, arguments and options in a form meant for tools. --menu=json prints them as one JSON object and adds each subcommand’s aliases and each argument’s nargs and choices. An option’s name is its long flag when it has one. --menu=json-tree prints the same object with each subcommand’s own object nested under its menu key, so one call returns every level. The version field changes only when a key is removed or changes meaning, so a reader should ignore keys it does not know.

nargs is null when the argument takes argparse’s default, one value or none for a switch. Otherwise it is a count such as "2", or "?", "*", "+" or "...", which takes every remaining word as written. Three keys help a tool offer values. complete names the kind of value: branch, committish, directory, file, remote or worktree, a git-project worktree name. A null or unknown complete means free text. candidates lists values to suggest, which unlike choices the command does not enforce. repeatable is true when each use of an option adds to its value rather than replacing it.

License

git-project is distributed under the terms of the GNU Affero General Public License v3.0 or later.

Authors

git-project is written and maintained by David Greene.

0.1.2 - 2026-10-22

Fixed

  • Git.refname_is_merged now resolves a target given as a short branch name to that branch, and Project.branch_is_merged and Project.branch_is_pushed look up each project branch as a branch. A tag with the same name, such as a tag master, was taken in its place. A branch could then be reported merged when only the tag contained it, or unmerged or unpushed when the project branch contained it.

  • Git.clone and Git.fetch_remote run the git CLI for an ssh url without a password, so they use the ssh agent, ~/.ssh/config and known_hosts as plain git does, and a Host alias now resolves. An ssh clone has the same branches, upstream config and remote HEAD as a libgit2 clone. A failure is a one-line GitProjectError that carries git’s error. ssh sends keepalives, so a link that stops answering fails in about a minute. GIT_SSH_COMMAND turns that off, and so do GIT_SSH and core.sshCommand when ssh.id is unset. An ssh clone or fetch through git gives up after six hours. A libgit2 clone or fetch that reached an ssh server with no key to offer died with TypeError: credential does not implement interface, and now fails with a one-line error.

Full Changelog

Metadata

Release files for git-project 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for git-project 0.1.2
File Size Uploaded Provenance Actions
git_project-0.1.2.tar.gz 98.7 kB Without provenance Details for git_project-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for git-project 0.1.2
File Interpreter ABI Platform Actions
git_project-0.1.2-py3-none-any.whl Python 3 none any Details for git_project-0.1.2-py3-none-any.whl

Total release size: 170.2 kB

Release files / git_project-0.1.2.tar.gz

Download URL git_project-0.1.2.tar.gz
Size 98.7 kB
Tags Source
SHA-256 checksum
How to use checksums
29ecdd76f7786fd89438508695d37394478725880c03c93472f18c33212131db
BLAKE2b-256 checksum
How to use checksums
5e1ed2f85254c548d117874c486993b1452e0b68131495b8c8474f2b351c9bc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / git_project-0.1.2-py3-none-any.whl

Download URL git_project-0.1.2-py3-none-any.whl
Size 71.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0f446674c8ebbc7d284b96c1a4a31ea02c74786f8310d13786c4b5ba02908d05
BLAKE2b-256 checksum
How to use checksums
0f39552d07d918376a8c6959767602f9e6b8e9d934e72114ca102e369b6eddab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for git-project 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page