Skip to content

Git auto-init: optional X-Git-Remote header to configure origin on the new repo #476

Description

@melvincarvalho

Context

When JSS auto-inits a repo on first git-receive-pack push (#466/#469), the resulting .git/config has no remotes configured. That's correct for the create-on-push semantics — JSS doesn't know where the client cloned from.

In practice this bites pod operators who later cd into the pod-side install dir and want to track upstream:

$ cd pod-data/public/apps/chrome
$ git pull
fatal: no upstream branch configured
$ git pull origin
fatal: 'origin' does not appear to be a git repository

The user has to manually git remote add origin <upstream> and git branch --set-upstream-to for every installed app.

Proposal

When a push triggers auto-init, optionally read an X-Git-Remote HTTP header from the client. If present, validated, and not already configured on the (just-auto-init'd) repo, run the equivalent of:

git -C <repoAbs> remote add origin <value>
git -C <repoAbs> branch --set-upstream-to=origin/main main   # if HEAD is main

so the operator can git pull later without ceremony.

Surface

POST /public/apps/foo/git-receive-pack HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/x-git-receive-pack-request
X-Git-Remote: https://github.com/solid-apps/foo
...

Constraints

  • Only on auto-init path. Don't touch .git/config of a pre-existing repo — that's the operator's territory, surprise-edits there are unacceptable.
  • Validate the value. URL must match ^https?://[A-Za-z0-9._/:-]+$. Reject git@, ssh://, file://, anything with shell metacharacters, anything with ... This is the same sort of guard tryAutoInitRepo already needs against symlink shenanigans (called out in its docstring).
  • No-op if not present. Header is purely opt-in; existing clients keep working.
  • Run after git init, before the push proceeds. Otherwise the push could race with the config write.
  • Use git remote add and git branch --set-upstream-to via spawnSync — don't hand-roll the config file. git writes the right shape.

Scope

~25 LoC + a test in test/git-auto-init.test.js:

it('configures origin from X-Git-Remote when present on first push', async () => {
  const url = `${baseUrl}/public/apps/penny/info/refs?service=git-receive-pack`;
  const res = await fetch(url, {
    headers: { 'X-Git-Remote': 'https://github.com/solid-apps/penny' }
  });
  assert.strictEqual(res.status, 200);
  const configPath = path.resolve(DATA_DIR, 'public/apps/penny/.git/config');
  const cfg = readFileSync(configPath, 'utf8');
  assert.ok(cfg.includes('[remote "origin"]'), 'origin should be configured');
  assert.ok(cfg.includes('url = https://github.com/solid-apps/penny'));
});

Plus a negative test: malformed URL → header silently ignored, push still succeeds.

Why this is JSS-level (not jspod-level)

  • Only JSS knows when auto-init fires (the trigger that "the repo is new and we can safely write config")
  • Works for any client (jspod install, raw git push, future tools), not just the wrapper
  • Operators who deploy JSS directly benefit too

Cross-references

Metadata

Metadata

Assignees

No one assigned

    Labels

    pluginCould be implemented as a plugin (#206); core/plugin line defined in #564

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions