Spheroman / Spheroman/newgit

`export --include` writes a withheld path into the export but `git add -A` ignores it, so it is not in the repository

Open
#94 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

question
Dominant language
Rust
Stars
0
Forks
0
Avg merge
1h 58m
Merged PRs (30d)
48

Description

Summary

newgit export --include <path> copies a withheld tracker path into the
export and reports it as included, but the file is not committed: the export's
git add -A respects the project .gitignore, and a tracker owns its paths by
adding them to that same .gitignore. The path ships with the directory and
not with the repository.

git status in the result then reports a clean tree, because ignored files are
hidden — which is a problem, since the command's own closing line tells you to
check the result before publishing it.

Reproduction

A user-audience lane owning a gitignored path:

# .newgit/trackers/local-env.toml
audience = "user"
storage  = "local"
paths    = [".env.local"]
$ newgit export feature/x --to /tmp/out --include .env.local
  source:   314 files @ 493ac6ca
  tracker:  local-env     included (--include overrode audience user, 1 file)
  commit:   eac6ee35

The file is there, with content:

$ cat /tmp/out/.env.local
CSR_ADMIN_CREDENTIALS={"tok":"staff"}

but git does not have it:

$ cd /tmp/out
$ git ls-files .env.local            # (nothing)
$ git check-ignore -v .env.local
.gitignore:18:.env.local        .env.local
$ git status --porcelain .env.local  # (nothing)
$ git clone -q . /tmp/cloned && ls /tmp/cloned/.env.local
ls: /tmp/cloned/.env.local: No such file or directory

The file count is identical to an export without --include — 314 either way.

Cause

init_export_repo (crates/newgit-core/src/source.rs:401):

run_git(&["init", "--quiet", "-b", branch, "--", dest])?;
run_git(&["-C", dest, "add", "-A"])?;

add -A honours the .gitignore that was copied in with the source tree, and
newgit tracker track is what put the lane's paths in that file. So every
tracker path is ignored in the export by construction, --include or not.
export.rs has already done its job correctly by this point — included is
counted at export.rs:127 and the path is written out; the loss happens one
layer down at the git add.

Why it matters

Two readings, and they want opposite fixes, which is why I am not sure which
this is:

  1. Intended. Trackers exist so lane content never enters source history,
    and the reference says so. An export that committed lane content would
    contradict the invariant, so --include legitimately means "put it on
    disk", not "put it in git".

  2. A gap. export is documented as "Write an instance out as an ordinary
    Git repository". --include is documented as "Include this path regardless
    of tracker audience", and the output says it "overrode audience user". A
    reader has no cue that the override stops at the worktree. The natural use —
    handing someone a working instance of a branch — does not survive the clone
    they will make of it.

Either way the verification story is inverted. The command says:

This is a path-level filter, not concealment. Check the result before
publishing it.

and git status — the way nearly anyone would check — shows a clean tree while
a credentials file sits on disk. The safety direction is right (it fails
closed, and I confirmed nothing withheld reaches the object store), but the
check the tool recommends cannot see what --include just did.

Suggested fix

If (1): one line under --include in the reference — an included tracker path
is written into the export but stays untracked, because tracker paths are
gitignored; copy the directory rather than cloning it. Possibly also soften the
output from included to something like included (untracked — gitignored).

If (2): force them in after the bulk add, in init_export_repo:

run_git(&["-C", dest, "add", "-A"])?;
if !included_paths.is_empty() {
    let mut args = vec!["-C", dest, "add", "-f", "--"];
    args.extend(included_paths.iter().map(|p| p.as_str()));
    run_git(&args)?;
}

export.rs already knows exactly which paths were force-included, so the list
is to hand.

Found while integrating newgit into a Go/Postgres monorepo; the lane in the
reproduction is the .env.local pattern from #83.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in crates/newgit-core/src/source.rs at init_export_repo and inspect export.rs around line 127, then reproduce the .env.local case described in the issue. Check the reference and existing export tests to determine whether --include should affect Git tracking or only the worktree. Done means the chosen behavior is implemented or documented, and the recommended verification accurately reflects the result.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, rust
Domain
cli, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.