Skip to content

Hardening, tests, and new features (diff, .gitignore, sharded storage) - #1

Merged
devang47 merged 7 commits into
mainfrom
feat/hardening-tests-and-features
Oct 6, 2026
Merged

devang47 merged 7 commits into
mainfrom
feat/hardening-tests-and-features

Conversation

@devang47

Copy link
Copy Markdown
Owner

Overview

Hardens MicroGit end-to-end and fills in the missing features, taking it from a
working prototype to a tested, releasable CLI. Started from a /code-review,
then worked through five phases. All changes: build clean, go vet clean,
staticcheck clean, gofmt clean, 58 tests passing, coverage 80.5%
(cmd) / 61.4% (utils).

What changed, by phase

Correctness fixes (from code review)

  • remove matched index lines by prefix — remove foo also dropped foobar. Now matches the exact path.
  • checkout left stale files and a stale index, and silently lost commits. Now deletes files absent from the target, resets the index, and warns/guards against data loss.
  • status never reported committed files modified in the working tree. Fixed.
  • save printed broken Println("...%w") messages and truncated unquoted multi-word messages. Fixed.
  • init/log ignored errors / printed bogus entries. Fixed.

Phase 2 — error handling & exit codes

  • All commands converted to cobra RunE: failures return clean Error: messages and exit non-zero; success exits 0.
  • Ref/index writes are atomic (temp + rename) so a crash can't corrupt the repo.
  • Added Args validation, --version, and dropped the dead --toggle flag.

Phase 3 — features

  • microgit diff — dependency-free LCS line diff (working tree vs any commit).
  • .gitignore support in add . and status.
  • Short-hash resolution for checkout/diff (with ambiguity detection).

Phase 4 — storage depth

  • Sharded (objects/ab/cdef…), zlib-compressed object storage, like git.
  • checkout --force guard against discarding uncommitted work.

Phase 5 — docs & tooling

  • README (install, quick-start, "How it works"), CONTRIBUTING.md, Makefile.

CI / release

  • CI matrix (ubuntu/macos/windows × Go 1.21–1.23) + race job.
  • golangci-lint + gofmt/vet workflow.
  • GoReleaser release pipeline on v* tags (version injected via ldflags).

Testing

  • Unit tests for every command + helpers.
  • New black-box e2e/ suite that builds the binary and drives it as a subprocess (stdout/stderr + exit codes).

Notes

  • Object storage format changed (sharded + compressed); existing .microgit
    repos created by older builds are not readable. Acceptable for a pre-1.0
    educational tool.
  • Commits are grouped by concern (storage → cmd fixes → diff → tests → CI →
    docs) rather than strictly chronological, since files were touched across
    phases; each commit builds on the previous.

- Shard objects by the first two hex chars of their hash (objects/ab/cdef...).
- Compress stored objects with zlib; add ReadObject to decompress.
- Add WriteFileAtomic (temp file + rename) so ref/index writes can't corrupt.
- Add ObjectPath and IsInitialized helpers; simplify HashContent to Sum256.
Correctness fixes:
- remove: match the exact index path so 'remove foo' can't drop 'foobar'.
- checkout: delete stale files, reset the index, add --force and short-hash
  resolution; refuse to discard uncommitted changes without --force.
- status: report committed files modified in the working tree.
- save: fix broken Println("%w") messages; keep multi-word messages; warn on
  non-tip commits.
- init/log: check errors instead of reporting false success; stop cleanly.

Structural changes:
- Convert commands to cobra RunE so failures exit non-zero with clean messages
  (SilenceUsage on the root); add Args validation.
- Route ref/index writes through atomic writes.
- Add shared repo helpers (repo.go): ensureRepo, .gitignore matcher, getLatest,
  writeIndex, resolveHash.
- Drop the dead --toggle flag; add --version wired to an ldflags-injectable var.
Show line-level differences between the working tree and a commit (HEAD by
default, or a hash / 'latest') using a dependency-free LCS line diff. New and
deleted files are shown against /dev/null.
- New unit tests for save, status, checkout, diff, ignore, hash resolution and
  repo helpers, plus utils object/round-trip tests.
- Regression tests covering every review fix (prefix remove, checkout cleanup,
  status modified detection, non-tip warning, repo guards, short hashes, force).
- New e2e/ package that builds the binary and drives it as a subprocess,
  asserting real stdout/stderr and exit codes.
- Shared test helpers (runCmd/runCmdErr, captureOutput, setupTestRepo).
- CI: build/vet/test across ubuntu/macos/windows x Go 1.21-1.23, plus a race job.
- Lint: gofmt, go vet and golangci-lint (config relaxes errcheck in tests).
- Release: GoReleaser builds cross-platform archives + checksums on v* tags,
  injecting the version via ldflags.
- README: install/quick-start, diff & checkout --force docs, short-hash notes,
  a 'How it works' storage section, and reality-matched feature list.
- Add CONTRIBUTING.md and a Makefile (build/test/race/cover/lint/install).
- .gitignore: ignore .DS_Store, the built binary and the dist/ release dir.
- ignore matcher: normalize paths to forward slashes and use slash-based glob
  matching (path.Match) so .gitignore/built-in ignores work on Windows.
- init test: skip the 0755 permission assertion on Windows (no Unix perm bits).
- CI matrix: exclude macos-latest with Go 1.21/1.22, whose linker output the
  macOS 26 runner rejects (dyld: missing LC_UUID); macOS is covered on 1.23.
@devang47
devang47 merged commit 20f0293 into main Oct 6, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant