SwiftGit is a Swift Package that wraps and orchestrates Git command-line functionality
so you can drive Git operations programmatically from Swift. It includes a small
shell abstraction, typed models for common git results, command builders for many
git subcommands, and an embedded portable git distribution for environments that
don't provide git on PATH.
This README gives a focused code-oriented overview of the implementation in
Sources/ and practical instructions for building, testing, and contributing.
Key features
- Thin, testable wrappers around
gitcommands (clone, commit, push, tag, stash, etc.) - Centralized process execution utilities in
Shellsupporting Combine and async/await - Typed models for common git outputs (
GitStatus,Commit,ShowCommitResult) - Embedded portable git at
Sources/SwiftGit/Resource/git-instance.bundlefor hermetic runs - Extensive unit and integration tests that exercise parsing and real git workflows
Table of contents
- Project layout
- Build & test
- Important modules (quick code map)
- Embedded git bundle
- Tests and integration tests
- Contribution notes
- Contribution notes
- See
CONTRIBUTING.mdfor contribution workflow, pre-commit hook instructions, and lint/format guidance.
Project layout (sources)
Sources/SwiftGit/— main package sourcesCustom/— hand-written implementationcommands/— high-level command helpers, e.g.git-commands-clone.swift,git-commands-tag.swiftmodels/— typed models likeGitStatus.swift,Commit.swift,Reference.swiftresults/— parsing results and helpers (e.g.ShowCommitResult.swift)Shell.swift— centralized Process wrapper with Combine + async/await supportGitEnvironment.swift— locate and configure embedded or system gitGit.swift— top-levelGitclass, wiring environment, shell, and triggersRepository.swift(+ extensions) — repository-level helpers
Resource/git-instance.bundle/— portable git binaries and extras included in the packageoptions/— typed option values used to compose command arguments
Build & test
- Build the package (debug):
swift build- Build for release:
swift build -c release- Run the full test suite:
swift test- Run a single test by name (recommended):
# filter matches test case and/or function name
swift test --filter ParseTests.testChangedEntryIndex_valid
swift test --filter test_format_date- Run tests in parallel (CI friendly):
swift test --parallelImportant modules (quick code map)
-
Shell(Sources/SwiftGit/Custom/Shell.swift)- Centralizes process creation, captures stdout/stderr, provides publishers and async helpers.
- Use
Git.data(...)orGit.run(...)which delegate toShell.Instance.
-
GitEnvironment(Sources/SwiftGit/Custom/GitEnvironment.swift)- Selects between embedded git (
.embed(...)), system git (.system), or custom folder. - Exposes environment variables used to run git (e.g.
GIT_EXEC_PATH).
- Selects between embedded git (
-
Git(Sources/SwiftGit/Custom/Git.swift)- High-level entrypoint. Use
Git(environment:)ortry Git.shared(throws if environment fails). - Configure shared fallback environments with
Git.configureShared(environments:). - Methods:
run,runPublisher,datawith variants for arrays of args and string commands.
- High-level entrypoint. Use
-
Repository(Sources/SwiftGit/Custom/Repository.swift+Repository+*.swift)- Convenience methods that operate in a repository directory (run, clone, status, tag, etc.).
-
GitStatusand parsing models (Sources/SwiftGit/Custom/models/GitStatus.swift)- Strongly-typed representations of
git statusoutput. Parsing code is defensive to avoid crashes on malformed input.
- Strongly-typed representations of
Embedded git bundle
- Embedded bundles are now split into dedicated resource targets so consumers can opt in by architecture.
- Products:
SwiftGitArm64→Sources/SwiftGitResourcesArm64/Resource/git-instance.bundleSwiftGitX86_64→Sources/SwiftGitResourcesX86_64/Resource/git-instance.bundleSwiftGitUniversal→Sources/SwiftGitResourcesUniversal/Resource/git-instance.bundle
SwiftGit(base product) no longer embeds a bundle;.embed(.arm64/.x86_64/.universal)works only when the corresponding resource product is linked.GitEnvironment.Style.autonow maps to system git only; use.embed(...)explicitly when you add a resource product.
Example usage (arm64, prefer embedded then system fallback):
import SwiftGit
import SwiftGitArm64
let git = Git(environments: [.embed(.arm64), .system])Shared configuration (arm64):
import SwiftGit
import SwiftGitArm64
Git.configureShared(environments: [.embed(.arm64), .system])
let git = try Git.shared- Agents and tests should not modify files under the bundles. Use
GitEnvironment.Style.custom(URL)to point to an alternate git distribution. - To generate updated bundles, run
tools/update-git-bundle.shwith the desired--archsand copy the result into the correspondingSources/SwiftGitResources*/Resource/directory. - If a bundle looks unusually large, run
tools/fix-git-bundle-links.shto relink duplicategit-*binaries and shrink the footprint. - The default build trims optional GUI/web/perl tooling and shell completions. Use
--include-extrasto keep them. - The update script defaults to the host arch (
uname -m). Use--archs arm64,x86_64for a universal bundle, ortools/thin-git-bundle.shto slim an existing one.
Tests and integration tests
- Tests live under
Tests/SwiftGitTests/.- Unit tests: parsing and helpers (safe parsing of
gitoutput, command splitting). - Integration tests: initialize temporary repos and run real git workflows (init, add, commit, tag, branch, stash, rebase, plumbing commands like
write-tree).
- Unit tests: parsing and helpers (safe parsing of
- Integration tests use system git; if git is unavailable they skip.
- Helper examples:
Tests/SwiftGitTests/IntegrationTests.swift,PlumbingTests.swift,ShowCommitResultTests.swift.
Design & safety notes
- Parsing: code attempts to be defensive;
GitStatususes failable/parsing helpers and falls back to safe defaults for malformed input. - Process execution:
Shellcaptures stdout/stderr and surfaces a typed error when a process exits non‑zero (includes exit code and working directory where possible). - Command string handling: the library provides a
splitCommandLinehelper to handle quoted/escaped arguments for string-based overloads. Prefer array-based overloads when possible to avoid shell-escaping issues.
CI
- A GitHub Actions workflow is included at
.github/workflows/ci.ymland runs the build + tests onmacos-latest.
Contributing and agents
- There is an
AGENTS.mdfile with rules and commands for automated agents and contributors. Agents should follow its guidelines when editing, testing, and committing. - Skill guidance for agent-enabled environments is also noted in
AGENTS.md.
Example usage
- Simple programmatic example (conceptual):
import SwiftGit
// create environment and git
let env = try GitEnvironment(type: .auto)
let git = try Git(environment: env)
// run git --version
let version = try git.run(["--version"])
print("git version: \(version)")Where to look next
- If you want to understand parsing code, start with
Sources/SwiftGit/Custom/results/ShowCommitResult.swiftandSources/SwiftGit/Custom/models/GitStatus.swift. - To add a new command helper, follow existing patterns under
Sources/SwiftGit/Custom/commands/.
Questions or issues
- Open an issue describing what you tried, including commands and repository state. If you want me to extend tests to cover more commands from the official Git docs, say which areas to prioritize (plumbing, submodule flows, network edge cases, etc.).