fangorn/ex_git_objectstore
public
ref:aef8c4de87e2e108e964d90b4969ddac21de63be
feat: write_tree/2, commit_tree/3, merge_branches/4 (#24) (#14)
Closes #24
## Summary
Adds top-level primitives for building trees and commits programmatically and for creating a merge commit from two refs in-process. These unblock fangorn/anvil#45 — Anvil's merge/rebase path currently shells out to \`git\` in a temp filesystem clone because this library offered no way to construct commits without a working directory.
## API
\`\`\`elixir
ExGitObjectstore.write_tree(repo, entries) # {:ok, tree_sha}
ExGitObjectstore.commit_tree(repo, tree_sha, opts) # {:ok, commit_sha}
ExGitObjectstore.merge_branches(repo, ours, theirs, opts) # {:ok, merge_sha}
\`\`\`
- **\`write_tree/2\`** — thin wrapper over \`Tree.new/1 + Object.write/2\`. SHA is stable across input orderings because \`Tree.new\` canonicalizes.
- **\`commit_tree/3\`** — structured \`%{name, email, when: DateTime}\` identity shape, formatted to git's wire format (\`\"Name <email> <unix> <+HHMM>\"\`). Validates tree SHA exists + is a Tree, and each parent SHA exists + is a Commit, before writing. Normalizes missing trailing message newline. Supports optional \`gpgsig\`.
- **\`merge_branches/4\`** — resolves both refs → commit SHAs, calls the existing \`Merge.merge_commits/3\` to three-way-merge against the merge base, then writes a two-parent merge commit via \`commit_tree/3\`. Returns \`{:error, {:conflicts, [...]}}\` on conflict without writing anything.
## Tests
New file \`test/ex_git_objectstore/commit_tree_and_merge_test.exs\` — 16 tests:
- Tree writes, empty tree, deterministic SHA
- Root commit + commit-with-parents round-trip
- Default-committer-equals-author, separate committer preserved
- Trailing-newline normalization idempotence
- Missing tree, non-tree, missing parent, non-commit parent rejection
- Positive AND negative TZ offset formatting
- Divergent non-conflicting merge produces two-parent commit with merged tree
- Conflict returns \`{:conflicts, _}\` and leaves branch refs unchanged
- Custom merge message overrides default
Full suite: **582 tests, 0 failures**.
## Follow-up
Once this merges and the \`mix.lock\` pin in \`fangorn/anvil\` is bumped, fangorn/anvil#45 (replace shell-out merge with in-process tree builder) can proceed.
SHA:
aef8c4de87e2e108e964d90b4969ddac21de63be
Author:
Anvil <noreply@anvil.fangorn.io>
Date:
2026-04-18 13:04
Parents:
0b41726
3 files changed
+1534
-0
| Type | ||
|---|---|---|
|
|
CHANGELOG.md | +36 −0 |
|
||