Fast, flexible and type-safe Git command execution in Python using subprocess.
- π§ Typed: All commands and options are statically type-checked.
- β‘ Fast: Minimal abstractions over subprocess, runs directly on your system Git.
- π§© Composable: Git commands and options can be passed around as objects.
- π Overridable: Easily override environment variables and options in a chainable, readable manner.
- π¦ Lightweight: No dependencies on heavy Git libraries or C extensions.
- π§° Extensible: Future support for output transformers and other plugins.
- π¨ Exception Handling: Raises any error as a Python-recognisable exception.
- π€ Debuggable: Exceptions capture
stdout,stderr, and the return code of the run command. - π€ Lazy Execution: Inherently lazily processed.
- π Transparent Output: Returns a Git command's
stdoutas-is. - π§ͺ Terminal Functions: Git subcommands are terminal functions.
- π§Ό Idiomatic Python: Write commands in idiomatic Python at compile-time and be confident theyβll execute smoothly at runtime.
- π Add-ons: Special features provided to ease programming with git. These can be added if required.
pip install gitboltRunning system commands in Python can be tricky for the following reasons:
- Arguments sent to
subprocessmay not be typed correctly and result in runtime errors. - Argument groups may be mutually exclusive or required conditionally β again causing runtime issues.
- Errors from subprocess are often unhelpful and difficult to debug.
Also, using subprocess effectively means you must:
- Understand and manage process setup, piping, and teardown.
- Know your CLI command intricacies in depth.
This project exists to fix all that β with ergonomics, speed, and type-safety.
Type-checking ensures runtime safety.
Make git command interfaces as ergonomic to the user as possible.
git hash-object supports taking multiple files and outputs a hash per file. But in practice, it's most often used to write a single file to the Git object database and return its hash. To match this real-world usage, Gitbolt offers a more ergonomic method that accepts one file and returns one hash β while still giving you the flexibility to access the full range of git hash-object capabilities when needed.
Gitbolt lets you pass subcommands around as typed objects. This enables highly focused, minimal APIs β you can write functions that accept only the subcommands they truly need. This leads to cleaner logic, better separation of concerns, and compile-time guarantees that help prevent misuse.
import gitbolt
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
version_subcmd = git.version_subcmd
add_subcmd = git.add_subcmd
def method_which_only_adds_a_file(add_subcmd: gitbolt.base.Add):
"""
This method only requires the `add` subcommand.
"""
...
method_which_only_adds_a_file(add_subcmd)git subcommands are modeled as terminal functions that return stdout.
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
status_out = git.status_subcmd.status()
print(status_out)Commands are designed to be passed around as objects. This makes them modular and thus users can opt to use only particular commands.
from gitbolt import get_git
git = get_git() # get git object for the current working directory
add_subcmd = git.add_subcmd
ls_tree_subcmd = git.ls_tree_subcmd
# now, functions can be written to accept only the required subcommands and nothing more than that.Only required commands and hence their implementations can be installed as per user requirement.
e.g.
- To install only the
git addcommand related logic:-
pip install gitbolt[add]
-
- To install command logic related to
git addandgit rmcommands:-
pip install gitbolt[add,rm]
-
- Install all porcelain related commands:
-
pip install gitbolt[porcelain]
-
- Install high performance
pygit2implementations:-
pip install gitbolt[pygit2]
-
pip install gitbolt[add,pygit2,rm]
-
- At last, install every command's implementation:
-
pip install gitbolt[all]
-
Extensive use of type-hints ensures that invalid usages fail early β at compile-time. Write at compile-time and be sure that commands run error-free at runtime.
Allow users to set/unset/reset Git environment variables and main command options using typed, chainable, Pythonic methods β just before a subcommand is executed.
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
git = git.git_envs_override(GIT_TRACE=True)from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
git = git.git_envs_override(GIT_TRACE=1, GIT_DIR=Path('/tmp/git-dir/'), GIT_EDITOR='vim')from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
overridden_git = git.git_envs_override(GIT_SSH=Path('/tmp/SSH')).git_envs_override(
GIT_TERMINAL_PROMPT=1,
GIT_NO_REPLACE_OBJECTS=True
)
re_overridden_git = overridden_git.git_envs_override(GIT_TRACE=True)from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
from vt.utils.commons.commons.core_py import UNSET
git = SimpleGitCommand()
overridden_git = git.git_envs_override(GIT_ADVICE=True, GIT_TRACE=True)
no_advice_unset_git = overridden_git.git_envs_override(GIT_TRACE=UNSET)from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
overridden_git = git.git_envs_override(GIT_TRACE=True)
git_trace_reset_git = overridden_git.git_envs_override(GIT_TRACE=False)Allow users to set/unset/reset git main command options in typed and pythonic manner just before subcommand run to provide maximal flexibility.
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
git = git.git_opts_override(no_replace_objects=True)from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
git = git.git_opts_override(no_replace_objects=True, git_dir=Path(), paginate=True)from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
overridden_git = git.git_opts_override(exec_path=Path('tmp')).git_opts_override(
noglob_pathspecs=True,
no_advice=True
).git_opts_override(
config_env={'auth': 'suhas', 'comm': 'suyog'}
)
re_overridden_git = overridden_git.git_opts_override(glob_pathspecs=True)from pathlib import Path
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
from vt.utils.commons.commons.core_py import UNSET
git = SimpleGitCommand()
overridden_git = git.git_opts_override(exec_path=Path('tmp'), no_advice=True)
no_advice_unset_git = overridden_git.git_opts_override(no_advice=UNSET)from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
overridden_git = git.git_opts_override(no_advice=True)
no_advice_reset_git = overridden_git.git_opts_override(no_advice=False)At last, run unchecked commands in git.
Introduced in 0.0.0dev4 to
- experiment.
- have consistent interfaced commands run until all subcommands are provided by the library.
from gitbolt.git_subprocess.impl.simple import SimpleGitCommand
git = SimpleGitCommand()
git = git.git_opts_override(no_advice=True)
git.subcmd_unchecked.run(['--version']) # run the version option for git.
git.subcmd_unchecked.run(['version']) # run the version subcommand.Output of git commands is returned as-is. No transformations unless explicitly requested. Transformers for formatting/parsing can be added later.
- π Composable Git commands.
- π€ Returns raw stdout.
- π¨ Exceptions with full context.
- π€ Lazy execution.
- π§ Strong typing and compile-time guarantees.
- π§Ό Idiomatic Python.
- π§ͺ Terminal subcommands.
- π£ Fail-fast on invalid usage.
- π License (Apache-2.0)
- π€ Contributing Guide
- Support
pygit2for direct, fast Git access. - Enable
porcelainsupport usingpygit2where required.pygit2usage will automatically make all commands return in porcelain mode.