✨ A Rust flake to automatically log al Git commits into Obsidian. ✨
Rusty Commit Saver captures each commit’s:
- Timestamp
- Commit message
- Repository URL
- Branch name
- Commit hash
and appends it to a dated diary entry in your Wiki directory.
Table of Contents:
- Automatic diary entry creation with YAML frontmatter and table header
- Timestamped commit rows formatted for Obsidian
- Customizable storage path under
📅 Diaries/0. Commits/YYYY/MM-MMMM/ - Preconfigured hooks (via Nix + pre-commit) to ensure code quality
-
Clone the repository
git clone https://github.com/chess-seventh/rusty-commit-saver.git cd rusty-commit-saver -
Enter the Nix development shell
devenv shell
-
Build the project
cargo build --release
-
(Optional) Install the binary to your PATH
cargo install --path .
Simply commit as usual. The hooks will:
- Run linters (
clippy,rustfmt, etc.) inside the Nix shell — pre-commit - Invoke Rusty Commit Saver to log the commit — post-commit, once the commit exists, which is why nothing this tool does can cost you a commit
If you prefer manual invocation:
rusty-commit-saverYour commit will be appended to, where Obsidian should be:
~/Documents/Wiki/📅 Diaries/0. Commits/YYYY/MM-MMMM/YYYY-MM-DD.md
rust-toolchain.tomlpins Rust 1.89.0devenv.nixprovisions Rust, Clippy, rustfmt, and Git hooks.pre-commit-config.yamldefines all pre-commit checkstreefmt.tomlconfigurestreefmtand formatters
Runtime settings live in an INI file at
~/.config/rusty-commit-saver/rusty-commit-saver.ini:
[obsidian]
root_path_dir = ~/Documents/Obsidian
commit_path = Diaries/Commits
[templates]
commit_date_path = %Y/%m-%B/%F.md
commit_datetime = %H:%M:%S
# Optional: repositories to skip, by canonical repo name (comma-separated).
# A commit made in one of these repos writes nothing to the diary.
[exclude]
repos = claude-srcThe [exclude] section is optional. Each entry is matched, case-sensitively,
against the committing repository's canonical name — taken from its origin
remote URL (…/claude-src.git → claude-src), falling back to the
working-directory name for a repo with no usable origin. Because the origin is
the same from every checkout, one entry covers the main clone and every git
worktree of that repo, from any subdirectory.
[obsidian] and [templates] are required; a config missing either one is
fatal. Any other section is ignored, with a line on stderr naming it, never
fatal. One INI file is shared by every checkout on the machine, so a section
written for a newer release must not break a binary that predates it — which is
exactly what adding [exclude] did to every checkout older than 4.17.0.
The stderr line matters: a misspelt section ([excludes]) is ignored too, so
without it your exclusions would silently stop applying.
Keys work the same way, for the same reason:
-
A key this binary does not understand is ignored and named on stderr (
ignoring unrecognised config keys [templates] commit_datetimes). It used to be ignored in complete silence, so a typo applied nothing and said nothing. -
The four keys in
[obsidian]and[templates]are required, and so is a non-empty value for each —commit_path =counts as missing. Without them there is no destination to write to, and a hook that quietly journals nothing looks exactly like a quiet day, so this one stays fatal. ([exclude] reposis optional, like its section.) -
The two
[templates]values must be formatschronocan actually render, and that is checked when the config is read. A bad specifier used to surface from inside the writer asa formatting trait implementation returned an error, naming nothing, after an empty diary file had already been created. -
The fatal message names the config file, the key and its section, plus any unrecognised key in that same section, since a misspelt
commit_pathsis the usual reasoncommit_pathis missing:rusty-commit-saver: /home/you/.config/rusty-commit-saver/rusty-commit-saver.ini: missing required key 'commit_path' in section [obsidian]; unrecognised in [obsidian]: commit_paths
None of this can cost you a commit: the tool runs as a post-commit hook, and git ignores that hook's exit status. A config fault costs you the diary entry and prints on stderr; the commit itself always stands.
tests/hook-gate.sh drives a real commit through a real post-commit hook, in a
throwaway repo and vault, and prints what a human would see:
cargo build
./tests/hook-gate.sh good # journals, says nothing
./tests/hook-gate.sh unknown-key # journals, names the key on stderr
./tests/hook-gate.sh missing-key # journals nothing, names file + key
./tests/hook-gate.sh blank-key # same, for a key with an empty value
./tests/hook-gate.sh bad-format # same, for a format chrono cannot render
./tests/hook-gate.sh unknown-section # journals, names the sectionThere are many enhancements planned:
- Configurable Obsidian path
- Configurable year/day/month on where to save the commit
- Interactive CLI flags and richer metadata (author, files changed)
- Improved error handling and user feedback
- Unit tests and CI pipeline for automated releases
Contributions welcome! Feel free to open issues or submit PRs.
- Fork the repo
- Create a feature branch
- Write tests and update
README.md - Submit a pull request
MIT © 2026 Chess7th