Skip to content

Create initial commits with <Git.Commit> under xmd run #750

Description

@taras

Story

As someone starting a Git repository, I want <Git.Add> and <Git.Commit> in an ordinary xmd run document to create its first commit, so I do not need a separate native Git bootstrap step.

Example

Given a directory containing README.md:

git init --initial-branch=main

xmd run -e '# Commit README.md with the initial commit message

Stage `README.md` for the commit.

<Git.Add paths="README.md" />

Commit the staged file with the message `Initial commit`.

<Git.Commit message="Initial commit" as="commitId" />'

The run stages README.md, creates a zero-parent commit on main, and binds that commit's full object ID to commitId.

An unborn repository is a valid Git checkout whose initial branch exists symbolically but does not have a HEAD commit yet.

Current gap

Ambient repository discovery finds the checkout root and common Git directory, but treats failure to resolve HEAD as if the invocation were outside Git:

this element needs a repository, and it is written outside a <Repository> in a directory that is not inside a Git checkout.

The live Git operation contract also assumes that every checkout has a commit and HEAD tree, and that every new commit has exactly one parent. Relaxing discovery alone therefore cannot support an initial commit safely.

Contract

Where ordinary repository operations are supported—the Deno source CLI and compiled xmd—a valid unborn checkout is selected as the ambient Repository.

<Git.Add> keeps its existing path validation, index behavior, output, and failure semantics.

When the index contains staged changes, <Git.Commit> in an unborn checkout:

  • creates a commit with zero parents;
  • updates the checkout's symbolic branch to that commit;
  • binds the full object ID through as;
  • preserves the existing author, committer, signing, hook, index, and read-back behavior.

An empty index retains the existing no-empty-commit refusal and creates no commit.

The live ordinary-run state represents unavailable pre-commit values with null, never a sentinel or invented object ID:

  • the ambient RepositoryIdentity.creationCommit is null when the checkout is selected before its first commit;
  • the pre-operation checkout commit and headTree are null;
  • the initial commit's parent is null;
  • successful post-operation state contains the real commit and tree object IDs.

Repository selection and identity remain stable for the whole execution. The identity's creationCommit therefore stays null; it is not rewritten after <Git.Commit>. Operations later in the same execution read the repository's live state and observe the newly created commit.

Before the initial commit, an operation that requires an existing commit—such as creating a worktree or pushing a branch—refuses with an actionable unborn-repository diagnosis. After <Git.Commit> succeeds, the same operation uses the new commit under the already selected Repository. With the usual origin and Git-host configuration, this includes <Git.Push> and <PullRequest>.

A directory that is not a Git checkout retains the existing outside-a-repository refusal.

Ordinary --journal behavior does not change: ordinary repository effects remain live and are not retained or replayed as workflow effects.

Workflow <Repositories> behavior also does not change:

  • every workflow Repository still has a real pinned creationCommit;
  • retained workflow checkout and commit records still require real commit, HEAD-tree, and parent object IDs;
  • replay rejects a retained record that substitutes null for those required workflow values;
  • an empty remote or unborn checkout does not become a valid workflow base.

This issue does not add ordinary repository-operation providers to the Node or Bun source CLIs.

Acceptance

  • In a fresh git init --initial-branch=main checkout, <Git.Add paths="README.md" /> followed by <Git.Commit message="Initial commit" as="commitId" /> creates a zero-parent commit containing README.md.
  • commitId equals the resulting HEAD object ID.
  • Live pre-operation results use null for the absent commit, HEAD tree, and parent; successful post-operation results contain valid object IDs.
  • The ambient Repository selection does not change after the commit.
  • A later <Git.Push> in the same execution can push the new branch to a configured empty origin, and subsequent Git-host composition consumes that pushed commit without reselecting the Repository.
  • Attempting <Git.Commit> with an empty index refuses and leaves the checkout unborn.
  • An operation requiring an existing commit refuses actionably before the initial commit and succeeds under its existing contract after the commit.
  • A file-backed document and an inline xmd run -e document resolve the same ambient checkout.
  • A non-Git directory retains the existing outside-a-repository error, while an unborn checkout does not receive it.
  • Ordinary diagnostic journals continue to contain no repository effects.
  • Retained workflow parsers reject absent creation commits, checkout commits, HEAD trees, and commit parents.
  • Existing ordinary, linked-worktree, managed-worktree, and workflow Repository behavior remains unchanged.
  • architecture.md, specs/workflow-workspace-spec.md, and the ordinary-run requirements in specs/executable-mdx-spec.md describe the resulting boundary.

Evidence

Run the focused integration and contract suites:

deno task test packages/workflow/tests/run-composition-ambient.test.ts packages/workflow/tests/run-composition-remote.test.ts packages/workflow/tests/git-add.test.ts packages/workflow/tests/git-commit.test.ts packages/cli/tests/run-composition-deno.test.ts packages/cli/tests/inline-cli.test.ts

The evidence includes the successful initial-commit path, empty-index refusal, pre-commit refusal for operations that need HEAD, same-execution post-commit behavior, outside-Git behavior, unchanged ordinary journaling, and strict workflow parsing.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions