Skip to content

feat: add --init and --commit flags for git initialization after clone#63

Merged
nrjdalal merged 2 commits into
nrjdalal:mainfrom
bryanprimus:feat/add-init-commit-option-after-cloning
Jul 3, 2026
Merged

feat: add --init and --commit flags for git initialization after clone#63
nrjdalal merged 2 commits into
nrjdalal:mainfrom
bryanprimus:feat/add-init-commit-option-after-cloning

Conversation

@bryanprimus

@bryanprimus bryanprimus commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Adds flags to turn a fresh clone into a git repo — no extra manual steps.

Closes #61.

Motivation

gitpick intentionally strips .git when cloning (great for scaffolding), but users who want to track their own changes had to run git init (and optionally git add + git commit) after every clone. This automates it.

Flags

  • --init — initialize the cloned output as a new git repository.
    • tree/repo → git init in the target; blob → in the parent directory.
    • idempotent (skips if .git exists); refuses to init the current working directory.
  • --auto-commit — create an initial commit with the default message chore: gitpick'ed (implies --init).
  • --commit <msg> — create an initial commit with <msg> (implies --init). A plain required-value string flag, so a message starting with -, a stray URL, or an empty value can't be silently mis-parsed.

Safety — staging is scoped to exactly what was cloned

  • stages only the cloned file / picked paths / cloned tree via a NUL-delimited --pathspec-from-file, so unrelated contents of a pre-existing -o target are never swept in, and huge picks can't overflow the argv limit (separators normalized to / for Windows);
  • an empty pick skips the commit instead of falling back to git add .;
  • if the commit fails (e.g. no git identity), the clone still succeeds and git's real error is surfaced.

Usage

gitpick owner/repo my-app --init                      # just init
gitpick owner/repo my-app --auto-commit               # init + commit (chore: gitpick'ed)
gitpick owner/repo my-app --commit "feat: scaffold"   # init + commit with a message
gitpick owner/repo/blob/main/config.toml ./config.toml --commit "chore: add config"

Tests

--init (tree/blob), --auto-commit default message, --commit <msg> (tree/blob), idempotency, missing-identity error surfacing, cwd refusal, pre-existing-dir staging scope, and the empty-pick guard. Full suite green.

@nrjdalal

Copy link
Copy Markdown
Owner

Review

Overview

Adds --init (runs git init) and --commit <msg> / -m (implies --init, then git add . && git commit -m) after clone. For blob clones, the repo is initialized in the parent of the target file. Documented in README.md + --help, wired at all four clone call sites (local interactive copy, remote interactive pick, watch loop, and single clone), with four new tests.

Strengths

  • Small, well-scoped change with a single helper initGitRepo reused everywhere.
  • Idempotent git init (skips if .git already exists).
  • Sensible blob handling — git init in the file's parent directory.
  • README, --help, and tests all updated together.

Issues / Risks

1. Watch mode will fail on the second tick (bin/index.ts:656).
setInterval calls initGitRepo on every tick. git init is guarded by the .git check, but git commit -m ... is not — on iteration 2 with no changes you'll get nothing to commit, working tree clean and spawn will throw, killing the watcher. Even if there are changes, this produces an unexpected commit per interval. Suggest gating --commit so it runs only the first time (e.g., skip commit if HEAD already exists, or run init/commit outside the interval).

2. git commit requires user.name / user.email.
If the user has no git identity configured globally, the command errors out after a successful clone — surprising since the primary action succeeded. Consider catching the spawn error and printing a friendly hint (✖ git commit failed — configure user.name / user.email), or at least a try/catch that doesn't bubble a non-zero exit.

3. Blob target without a directory pollutes CWD.
gitpick owner/repo/blob/main/file.txt file.txt --initpath.dirname(\"file.txt\") is \".\", so git init runs in the user's current directory. That is almost certainly not what they want. Worth either warning, or requiring an explicit directory for blob + --init.

4. Hard-coded \"repository\" at two call sites (bin/index.ts:411, :593).
initGitRepo(targetDir, \"repository\", options) is passed in the interactive branches, but the helper's type parameter is typed as string. Tighten to \"blob\" | \"repository\" (or reuse config[\"type\"]) so the call sites don't silently drift.

5. git add . semantics for blob into non-empty directory.
git add . picks up anything in the spawn's cwd. For a blob clone into an existing non-empty directory (parent had other files before the clone), those unrelated files get staged and committed too. Probably fine given the scaffolding framing, but worth calling out in the README.

6. Help-text alignment.
-m, --commit <msg> is wider than the other two-column flags, so the description column shifts. Minor cosmetic.

Tests

Four new tests cover tree/blob × init/commit happy paths. Gaps worth adding:

  • Idempotency: calling --init when .git already exists should not error.
  • Watch mode: assert no crash on the second tick (related to Test #1).
  • --commit without git user config — confirms the error surface.

Security

options.commit flows into spawn(\"git\", [\"commit\", \"-m\", options.commit]) as an argv element, not a shell string — no injection risk. 👍

Recommendation

Approve after addressing #1 (watch-mode re-commit) and #2 (graceful failure when git identity is unset). The other items are polish.

@nrjdalal

nrjdalal commented Apr 21, 2026

Copy link
Copy Markdown
Owner

One more thought: there's no default commit message right now — commit is typed as string in parseArgs, so passing --commit / -m without a value errors out. Could we default it to "init awesomeness" when the flag is passed bare? Makes the zero-friction path even smoother:

gitpick owner/repo --commit   # → "init awesomeness"

@bryanprimus

Copy link
Copy Markdown
Contributor Author

Thanks for the review!! I've pushed updates addressing all your points:

  1. Watch mode: Moved initGitRepo outside the watch interval so it only runs once.
  2. Missing git identity: Wrapped git commit in a try/catch. It now prints a friendly warning instead of crashing the successful clone.
  3. CWD pollution: Added a guard to gracefully skip git init and show a warning if a user tries to clone a blob directly into the CWD with --init.
  4. Hard coded types: Refactored initGitRepo to check the actual filesystem (fs.statSync) instead of passing around type strings. This removes the hardcoded "repository" strings entirely and makes it much safer.
  5. git add . semantics: Added a note in the README clarifying this behavior when cloning into existing directories.
  6. Help text alignment: Fixed the spacing in both the CLI output and README.
  7. Default commit message: Implemented the "init awesomeness" default! Since Node's util.parseArgs doesn't support optional string flags, I added a tiny pre-parse step to inject the default value if --commit is passed bare.
  8. Tests: Added the requested tests in cli.test.ts covering idempotency, the watch mode second tick, and the missing git config error surface.

Let me know if something is still missing. 🙏

@nrjdalal
nrjdalal force-pushed the feat/add-init-commit-option-after-cloning branch 11 times, most recently from b2bf739 to 858436a Compare July 3, 2026 05:14
bryanprimus and others added 2 commits July 3, 2026 11:48
… clone

Closes nrjdalal#61.

gitpick strips `.git` when cloning; these flags let users start tracking their
scaffolded output without extra manual steps.

- --init: initialize the cloned output as a new git repository (idempotent —
  skips if .git already exists). For a blob, inits the parent directory.
- --auto-commit: create an initial commit with message "chore: gitpick'ed".
- --commit <msg>: create an initial commit with <msg> (empty falls back to the
  default). Both committing flags imply --init. `--commit` is a plain
  required-value string flag, so a message beginning with `-`, a stray URL, or
  an empty value can't be silently mis-parsed.

Safety / robustness:
- refuses to initialize the current working directory (file or directory);
- stages only the cloned file / picked paths / cloned tree (interactive picks
  stage the exact copied files, not the picked directory), so unrelated
  contents of a pre-existing target directory are never swept into the commit;
- an empty pick prints a notice and skips the commit rather than `git add .`;
- `git add --force` so a `.gitignore` that rode along in the clone can't abort
  staging of files the user explicitly asked to pick;
- large picks are staged via a NUL-delimited pathspec file (--pathspec-from-file,
  git >= 2.25) so a huge tree can't overflow the argv limit (E2BIG), falling
  back to argv `git add` on older git; separators normalized to "/" so
  Windows-cloned paths still match git's index;
- any git failure (init or commit) is surfaced but never undoes the already
  successful clone; skip warnings show under --tree and are silenced only by
  --quiet.

Refactor: the git plumbing lives in bin/utils/init-git-repo.ts (keeping
index.ts at orchestration altitude per AGENTS.md); temp-dir/file naming is a
shared tempName() helper; the two interactive copy loops share a copySelected()
helper so the staging-scope logic can't drift between them.

Also reorders the CLI options help (code + README) to the maintainer's layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ships the --init / --auto-commit / --commit git-init feature as a new major.
Version differs from the npm `latest` tag, so merging this to `main` triggers a
`latest` publish via release.yml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@nrjdalal
nrjdalal force-pushed the feat/add-init-commit-option-after-cloning branch from 858436a to 332bca1 Compare July 3, 2026 06:19
@nrjdalal
nrjdalal merged commit aa0193c into nrjdalal:main Jul 3, 2026
1 check 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.

Feature Request: Option to Initialize Git Repository After Cloning

2 participants