{"id":29345578,"url":"https://github.com/vaastav-technologies/py-gitbolt","last_synced_at":"2026-05-01T00:31:47.683Z","repository":{"id":293677149,"uuid":"984798113","full_name":"Vaastav-Technologies/py-gitbolt","owner":"Vaastav-Technologies","description":"git command interfaces with default implementation using subprocess calls.","archived":false,"fork":false,"pushed_at":"2025-07-02T19:42:56.000Z","size":187,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-02T19:48:29.586Z","etag":null,"topics":["git","python","python-3","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Vaastav-Technologies.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-16T14:22:34.000Z","updated_at":"2025-07-02T19:45:06.000Z","dependencies_parsed_at":"2025-07-02T19:41:44.603Z","dependency_job_id":null,"html_url":"https://github.com/Vaastav-Technologies/py-gitbolt","commit_stats":null,"previous_names":["vaastav-technologies/py-git"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Vaastav-Technologies/py-gitbolt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vaastav-Technologies%2Fpy-gitbolt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vaastav-Technologies%2Fpy-gitbolt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vaastav-Technologies%2Fpy-gitbolt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vaastav-Technologies%2Fpy-gitbolt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vaastav-Technologies","download_url":"https://codeload.github.com/Vaastav-Technologies/py-gitbolt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vaastav-Technologies%2Fpy-gitbolt/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264295472,"owners_count":23586523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["git","python","python-3","python3"],"created_at":"2025-07-08T15:28:45.939Z","updated_at":"2026-05-01T00:31:47.612Z","avatar_url":"https://github.com/Vaastav-Technologies.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🚀 Gitbolt\n\n![PyPI - Types](https://img.shields.io/pypi/types/gitbolt)\n![GitHub License](https://img.shields.io/github/license/Vaastav-Technologies/py-gitbolt)\n[![🔧 test](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/test.yml/badge.svg)](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/test.yml)\n[![💡 typecheck](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/typecheck.yml/badge.svg)](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/typecheck.yml)\n[![🛠️ lint](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/lint.yml/badge.svg)](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/lint.yml)\n[![📊 coverage](https://codecov.io/gh/Vaastav-Technologies/py-gitbolt/branch/main/graph/badge.svg)](https://codecov.io/gh/Vaastav-Technologies/py-gitbolt)\n[![📤 Upload Python Package](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/python-publish.yml/badge.svg)](https://github.com/Vaastav-Technologies/py-gitbolt/actions/workflows/python-publish.yml)\n![PyPI - Version](https://img.shields.io/pypi/v/gitbolt)\n\n**Fast, flexible and type-safe Git command execution in Python using subprocess.**\n\n---\n\n## ✨ Features\n\n* 🧠 **Typed:** All commands and options are statically type-checked.\n* ⚡ **Fast:** Minimal abstractions over subprocess, runs directly on your system Git.\n* 🧩 **Composable:** Git commands and options can be passed around as objects.\n* 🔁 **Overridable:** Easily override environment variables and options in a chainable, readable manner.\n* 📦 **Lightweight:** No dependencies on heavy Git libraries or C extensions.\n* 🧰 **Extensible:** Future support for output transformers and other plugins.\n* 🚨 **Exception Handling:** Raises any error as a Python-recognisable exception.\n* 📤 **Debuggable:** Exceptions capture `stdout`, `stderr`, and the return code of the run command.\n* 💤 **Lazy Execution:** Inherently lazily processed.\n* 📄 **Transparent Output:** Returns a Git command's `stdout` as-is.\n* 🧪 **Terminal Functions:** Git subcommands are terminal functions.\n* 🧼 **Idiomatic Python:** Write commands in idiomatic Python at compile-time and be confident they’ll execute smoothly at runtime.\n* 🎀 **Add-ons:** Special features provided to ease programming with git. These can be added if required.\n* 💻 **CLI-cmd:** Take commands from cli and run in `gitbolt`.\n\n---\n\n## 📦 Installation\n\n```bash\npip install gitbolt\n```\n\n---\n\n## 💡 Motivation\n\nRunning system commands in Python can be tricky for the following reasons:\n\n1. Arguments sent to `subprocess` may not be typed correctly and result in runtime errors.\n2. Argument groups may be mutually exclusive or required conditionally — again causing runtime issues.\n3. Errors from subprocess are often unhelpful and difficult to debug.\n\nAlso, using subprocess effectively means you must:\n\n* Understand and manage process setup, piping, and teardown.\n* Know your CLI command intricacies in depth.\n\n\u003e This project exists to fix all that — with ergonomics, speed, and type-safety.\n\n---\n\n## 🎯 Project Goals\n\n### ✅ Predictable Compile-Time Behavior\n\nType-checking ensures runtime safety.\n\n### ✅ Ergonomic APIs\n\n\u003cdetails\u003e\n\u003csummary\u003eMake git command interfaces as ergonomic to the user as possible.\u003c/summary\u003e\n\n#### Provide versions of most used command combinations\n\n`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.\n\n#### Let subcommands be passed around as objects\n\nGitbolt 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.\n\n```python\nimport gitbolt\n\ngit = gitbolt.get_git()\nversion_subcmd = git.version_subcmd\nadd_subcmd = git.add_subcmd\n\ndef method_which_only_adds_a_file(add_subcmd: gitbolt.base.Add):\n    \"\"\"\n    This method only requires the `add` subcommand.\n    \"\"\"\n    ...\n\nmethod_which_only_adds_a_file(add_subcmd)\n```\n\n\u003c/details\u003e\n\n### ✅ Subcommands as Objects\n\ngit subcommands are modeled as terminal functions that return stdout.\n\n```python\nimport gitbolt\n\ngit = gitbolt.get_git()\nversion_stdout = git.version_subcmd.version().version()\nprint(version_stdout)\n```\n\n### 🪼 Modular Architecture\n\n#### 🧑‍💻 Modular at the programmatic level\n\nCommands are designed to be passed around as objects. This makes them modular and thus users can opt to use only \nparticular commands.\n\n```python\nfrom gitbolt import get_git\n\ngit = get_git() # get git object for the current working directory\nadd_subcmd = git.add_subcmd\nls_tree_subcmd = git.ls_tree_subcmd\n\n# now, functions can be written to accept only the required subcommands and nothing more than that.\n```\n\n#### 📽️ Modular at project level\n\nOnly required commands and hence their implementations can be installed as per user requirement.\n\ne.g.\n\n- To install only the `git add` command related logic:\n  - ```shell\n    pip install gitbolt[add]\n    ```\n- To install command logic related to `git add` and `git rm` commands:\n  - ```shell\n    pip install gitbolt[add,rm]\n    ```\n- Install all porcelain related commands:\n  - ```shell\n    pip install gitbolt[porcelain]\n    ```\n- Install high performance `pygit2` implementations:\n  - ```shell\n    pip install gitbolt[pygit2]\n    ```\n  - ```shell\n    pip install gitbolt[add,pygit2,rm]\n    ```\n- At last, install every command's implementation:\n  - ```shell\n    pip install gitbolt[all]\n    ```\n\n---\n\n## 🧠 Strong Typing Everywhere\n\nExtensive 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.\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003eAllow users to set/unset/reset Git environment variables and main command options using typed, chainable, Pythonic methods — just before a subcommand is executed.\u003c/summary\u003e\n\n### 🧬 Git Environment Variables\n\n#### 🔁 Override a single Git env (e.g., `GIT_TRACE`)\n\n```python\nimport gitbolt\n\ngit = gitbolt.get_git()\ngit = git.git_envs_override(GIT_TRACE=True)\n```\n\n#### 🌐 Override multiple Git envs (e.g., `GIT_TRACE`, `GIT_DIR`, `GIT_EDITOR`)\n\n```python\nfrom pathlib import Path\nimport gitbolt\n\ngit = gitbolt.get_git()\ngit = git.git_envs_override(GIT_TRACE=1, GIT_DIR=Path('/tmp/git-dir/'), GIT_EDITOR='vim')\n```\n\n#### 🪢 Chain multiple overrides fluently\n\n```python\nfrom pathlib import Path\nimport gitbolt\n\ngit = gitbolt.get_git()\noverridden_git = git.git_envs_override(GIT_SSH=Path('/tmp/SSH')).git_envs_override(\n    GIT_TERMINAL_PROMPT=1,\n    GIT_NO_REPLACE_OBJECTS=True\n)\nre_overridden_git = overridden_git.git_envs_override(GIT_TRACE=True)\n```\n\n#### ❌ Unset Git envs using a special `UNSET` marker\n\n```python\nimport gitbolt\nfrom vt.utils.commons.commons.core_py import UNSET\n\ngit = gitbolt.get_git()\noverridden_git = git.git_envs_override(GIT_ADVICE=True, GIT_TRACE=True)\nno_advice_unset_git = overridden_git.git_envs_override(GIT_TRACE=UNSET)\n```\n\n#### 🔄 Reset Git envs by setting new values\n\n```python\nimport gitbolt\n\ngit = gitbolt.get_git()\noverridden_git = git.git_envs_override(GIT_TRACE=True)\ngit_trace_reset_git = overridden_git.git_envs_override(GIT_TRACE=False)\n```\n\u003c/details\u003e\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003eAllow users to set/unset/reset git main command options in typed and pythonic manner just before subcommand run to provide maximal flexibility.\u003c/summary\u003e\n\n### ⚙️ Git Main Command Options\n\n#### 🔁 Override a single Git opt (e.g., `--no-replace-objects`)\n\n```python\nimport gitbolt\n\ngit = gitbolt.get_git()\ngit = git.git_opts_override(no_replace_objects=True)\n```\n\n#### 🌐 Override multiple options (e.g., `--git-dir`, `--paginate`)\n\n```python\nfrom pathlib import Path\nfrom gitbolt.subprocess.impl.simple import SimpleGitCommand\n\ngit = SimpleGitCommand()\ngit = git.git_opts_override(no_replace_objects=True, git_dir=Path(), paginate=True)\n```\n\n#### 🪢 Chain multiple option overrides fluently\n\n```python\nimport gitbolt\nfrom pathlib import Path\n\ngit = gitbolt.get_git()\noverridden_git = git.git_opts_override(exec_path=Path('tmp')).git_opts_override(\n    noglob_pathspecs=True,\n    no_advice=True\n).git_opts_override(\n    config_env={'auth': 'suhas', 'comm': 'suyog'}\n)\nre_overridden_git = overridden_git.git_opts_override(glob_pathspecs=True)\n```\n\n#### ❌ Unset Git opts using a special `UNSET` marker\n\n```python\nimport gitbolt\nfrom pathlib import Path\nfrom vt.utils.commons.commons.core_py import UNSET\n\ngit = gitbolt.get_git()\noverridden_git = git.git_opts_override(exec_path=Path('tmp'), no_advice=True)\nno_advice_unset_git = overridden_git.git_opts_override(no_advice=UNSET)\n```\n\n#### 🔄 Reset Git opts by setting new values\n\n```python\nimport gitbolt\n\ngit = gitbolt.get_git()\noverridden_git = git.git_opts_override(no_advice=True)\nno_advice_reset_git = overridden_git.git_opts_override(no_advice=False)\n```\n\n\u003c/details\u003e\n\n### 🔄 Run unchecked commands\n\nAt last, run unchecked commands in git.\n\nIntroduced in `0.0.0dev4` to \n- experiment.\n- have consistent interfaced commands run until all subcommands are provided by the library.\n\n```python\nimport gitbolt\n\ngit = gitbolt.get_git_command()\ngit = git.git_opts_override(no_advice=True)\ngit.subcmd_unchecked.run(['--version']) # run the version option for git.\ngit.subcmd_unchecked.run(['version']) # run the version subcommand.\n```\n\n#### 💻 Run commands received from CLI\n\nIntroduced in `0.0.0dev11` is the ability to take commands from CLI and run it inside `gitbolt`.\n\nWhile making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example \nwould be to make a system that receives CLI commands and does certain modifications/additions inside `gitbolt` before\nactually running them. An example:\n\n```python\nimport gitbolt\n\nopts = [\"--no-pager\", \"--namespace\", \"n1\"]  # options received from outside your program.\nenvs = dict(GIT_AUTHOR_NAME=\"ss\")  # env-vars received form outside your program.\ngit = gitbolt.get_git_command(opts=opts, envs=envs)\n\n# these can later be overridden\ngit = git.git_opts_override(namespace=\"n2\")\n```\n\n---\n\n## 🔍 Transparent by Default\n\nOutput of git commands is returned as-is. No transformations unless explicitly requested.\nTransformers for formatting/parsing can be added later.\n\n---\n\n## ✅ Benefits Out-of-the-Box\n\n* 🔄 Composable Git commands.\n* 📤 Returns raw stdout.\n* 🚨 Exceptions with full context.\n* 💤 Lazy execution.\n* 🧠 Strong typing and compile-time guarantees.\n* 🧼 Idiomatic Python.\n* 🧪 Terminal subcommands.\n* 💣 Fail-fast on invalid usage.\n\n---\n\n## 📄 More Information\n\n- 📜 [License (Apache-2.0)](./LICENSE)\n- 🤝 [Contributing Guide](./CONTRIBUTING.md)\n\n---\n\n## 🚧 Future Goals\n\n* Support `pygit2` for direct, fast Git access.\n* Enable `porcelain` support using `pygit2` where required.\n  \u003e `pygit2` usage will automatically make all commands return in porcelain mode.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaastav-technologies%2Fpy-gitbolt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvaastav-technologies%2Fpy-gitbolt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaastav-technologies%2Fpy-gitbolt/lists"}