Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

graft

A standalone CLI for managing cross-OS development workspaces: per-account git identity routing plus per-platform build-output redirection over a shared source tree.

Formerly git-identity. Binary still installs under both names this release — git-identity prints a deprecation notice and will be removed next release.

The Problem

Two related friction points if you work across multiple GitHub accounts AND across OSes (e.g. dual-boot Linux + Windows on a shared partition):

Identity side

  1. Wrong commit identity — pushing personal commits with your work email
  2. SSH key juggling — manually managing which key authenticates where
  3. Clone URL friction — forgetting to modify clone URLs for the correct SSH alias

Workspace side

  1. Build output collisionstarget/, node_modules/, .venv/ written into a source tree shared between Windows and Linux: slow I/O on Linux over NTFS, broken exec bits, file-lock collisions, double rebuilds
  2. Setup drift — each teammate (or each OS, on a dual-boot machine) wires things slightly differently

Git's includeIf gitdir: + SSH host aliases solve the identity side. Symlinks (with directory-junction fallback on Windows) solve the workspace side. The setup for either is manual and easy to break.

graft does it all in one config: one YAML, one command, generated correctly.

How It Works

You define your accounts in a single YAML config. graft apply generates:

File What it writes
~/.gitconfig Default [user] identity + [includeIf "gitdir:..."] blocks (uses gitdir/i: on Windows for case-insensitive matching)
~/.gitconfig-{alias} Per-account [user] override (name + email)
~/.ssh/config Host github.com-{alias} blocks with IdentityFile + IdentitiesOnly
<repo>/<link> Per-project symlink to the platform-native build location (Rust → target/, Node → node_modules/, Python → .venv/, etc.)
<repo>/.git/info/exclude Local-only ignore entry so the link never accidentally gets committed

Existing content in these files is preserved — graft only manages a clearly marked block:

# --- BEGIN graft managed block ---
# Do not edit this section manually. Managed by graft.
[user]
    name = Jane Developer
    email = jane@personal.dev

[includeIf "gitdir:D:/dev/workco/"]
    path = ~/.gitconfig-workco
# --- END graft managed block ---

# ... your other git config is untouched ...

Quick Start

1. Install

cargo install --path .

Or build from source:

cargo build --release
# Binary at target/release/graft (and target/release/git-identity during the deprecation window)

2. Set up your first identity

graft

On first run, a setup wizard walks you through creating your config — base directory, account name, email, GitHub username, and whether to enable workspace links. Done in 30 seconds.

For CLI-only setup: graft init

3. Workspace

If you said yes to workspace links during init:

graft workspace status   # show what would change
graft workspace apply    # create/repair links across all detected projects

graft detects Rust / Node / Python projects by marker file at the repo root and creates a symlink (or directory junction on Windows when symlinks need elevation) named exactly what the toolchain expects. cargo build just works — its target/ lives on your platform's native filesystem instead of the shared NTFS partition.

4. Clone repos with the right identity

# Work repos — use the aliased host
git clone git@github.com-workco:org/repo.git D:/dev/workco/repo

# Personal repos — default host, no alias needed
graft clone git@github.com:janedev/dotfiles.git    # graft picks the right host automatically

Concepts

Alias vs Directory Name

Each account has two short names:

  • alias — drives SSH hosts and config file names: github.com-{alias}, ~/.gitconfig-{alias}
  • dir_name — the actual folder under base_directory: D:/dev/{dir_name}/

These can differ.

Default Account

Exactly one account must have is_default: true. This account uses github.com as its SSH host (no -alias suffix), has its [user] block in the main ~/.gitconfig, and is the fallback identity for repos outside any account directory.

Managed Block

graft wraps generated content in sentinel comments (BEGIN/END). On apply, only the managed block is replaced — everything outside it is preserved.

Workspace Links

Source lives on the shared filesystem; build output gets redirected:

Platform Default target template
Linux / macOS ~/build/{account}/{repo}
Windows C:/build/{account}/{repo}

Detectors that fire by default:

Marker file Link name Project type
Cargo.toml target/ Rust
package.json node_modules/ Node
pyproject.toml .venv/ Python
requirements.txt .venv/ Python (legacy)

A repo can match multiple detectors and gets a link for each. Each generated link name is added to that repo's .git/info/exclude so it never accidentally gets committed.

On Windows, graft creates a real symlink if Developer Mode / admin is available; otherwise falls back to a directory junction (no elevation required, works on local volumes only — which is the supported case).

Permissions

Every file write and link creation prompts for confirmation by default. Use --yes to auto-approve, or set always_allow per category in your config to stop being asked.

Cross-OS Setup

graft runs separately on each OS. Each side gets its own ~/.gitconfig, SSH keys, and platform-specific build target. The shared bit is the source tree itself.

Linux / macOS Windows
Config path ~/.config/graft/config.yaml %USERPROFILE%\.config\graft\config.yaml
gitdir keyword gitdir: gitdir/i: (case-insensitive — NTFS is)
Symlinks std::os::unix::fs::symlink Symlink → junction fallback

Same path layout on both OSes — handy for dotfiles repos. Configs from the pre-rename location auto-migrate on first load.

For a single shared config across both partitions of a dual-boot machine (e.g. via a dotfiles symlink), use the per-OS form of base_directory so D:\dev resolves on Windows and /mnt/d/dev resolves on Linux. See sample-config.yaml.

Development

cargo build                              # debug build
cargo test                               # run tests
cargo run --bin graft -- list            # test the list command
cargo run --bin graft -- apply --dry-run # preview changes
cargo clippy                             # lint

License

MIT

About

A standalone CLI for managing multiple git identities with directory-based switching and SSH aliases.

Topics

Resources

Stars

Watchers

Forks

Packages

Contributors

Languages