Documentation
# gitprofiles

`gitprofiles` is CLI for managing multiple Git identities with local enforcement.

The intended workflow is:

- first, define profiles once
- then, set one profile per repository

Commits/pushes are blocked when profile state is missing or mismatched, although, there are some limitations. Please read below.

## Compatability

The only supported platforms are:

- Linux/POSIX shell environments

The program may or may not work on other platforms. Support for them is not planned either.

## Install and Run

Build locally:

```bash
cargo build --release
```

Run the binary:

```bash
./target/release/gitprofiles --help
```

## Quickstart

1. Initialize global integration:

```bash
gitprofiles init
```

2. Create a profile (interactive):

```bash
gitprofiles create
```

3. In each repository, select a profile:

```bash
gitprofiles set-profile work
```

4. Validate repository state:

```bash
gitprofiles check
```

## Commands

- `gitprofiles init`
- `gitprofiles create`
- `gitprofiles set-profile <name>`
- `gitprofiles check`
- `gitprofiles list`
- `gitprofiles remove <name>`

## How Enforcement Works

The way gitprofiles was designed is straightforward. It does not try to wrap Git or replace its behavior, but instead, it adds a guardrail at the two moments where identity mistakes usually matter most. They're during, 1: creating commits, and, 2: pushing changes.

When you run `gitprofiles init`, the tool creates two hooks under `~/.config/gitprofiles/hooks`: `prepare-commit-msg` and `pre-push`. Both hooks call `gitprofiles check`.

`gitprofiles check` is the policy gate. It reads your repo's local `gitprofiles.profile`, `user.name`, and `user.email`, then compares that state against the profile definition in `~/.config/gitprofiles/profiles.toml`. If the profile marker is missing, if the profile name is not found in the TOML file, or if local name/email drift from that profile, the operation is rejected.

So practically, once you run `gitprofiles set-profile <name>` in a repo, the checks keep that repo locked to the specified profile, unless you intentionally change something.

## Nuance

There is one behavior that can look confusing if it happens to you... During `init`, gitprofiles sets `user.useConfigOnly=true` globally. This is so that Git doesn't aut-guesses identity from the system username/hostname. That means in a repository where you have not set a local profile yet, and if global `user.name`/`user.email` are unset, a commit may fail with Git's own message:

```
fatal: no email was given and auto-detection is disabled
```

This is expected, and it is still policy enforcement doing its job.

The "fix" is to run `gitprofiles set-profile <name>` in that repository, then `gitprofiles check`, and try again. After local profile setup is valid, commits/pushes will work. And you do not need global `user.name`/`user.email`, it's optional.

## Limitations

1. There is no client-side hook for local `git tag` creation. So tag creation itself is not blocked. The main identity risk is with annotated tags, because they embed tagger identity metadata, and that can be published when tags are pushed.

2. gitprofiles is just a client-side enforcement, which is great enough. However, local hooks can be bypassed if things were invoked in ways that skip Git.

3. `gitprofiles init` will refuse when `core.hooksPath` is already set globally, and it will also refuse if managed hook targets already exist. This is so the program does not overwrite an existing hook setup. A hook integration mode that can coexist with pre-existing hooks (chaining instead of refusing by default) is planned.

## Troubleshooting

```
refusing to initialize: global core.hooksPath is already set
```

The program detected an existing hook setup and intentionally refused to overwrite it. That is currently a hard stop by design. You need to clear or migrate that existing hooks path manually before running `gitprofiles init`.

```
missing local key 'gitprofiles.profile'
```

That repository has not been assigned a profile marker yet. Run `gitprofiles set-profile <name>` in that repo.

```
profile '<name>' does not exist
```

The profile name is not in `~/.config/gitprofiles/profiles.toml`. Run `gitprofiles list` to see existing names, or create the profile first via `gitprofiles create`.

```
local user.name/user.email mismatch
```

Repository identity has drifted from the selected profile. Re-apply with `gitprofiles set-profile <name>`, then confirm with `gitprofiles check`.

```
fatal: no email was given and auto-detection is disabled
```

Git is telling you there is still no valid local identity in that repository while `user.useConfigOnly=true` is active. Set the repo profile and retry.