> ## Documentation Index
> Fetch the complete documentation index at: https://code.storage/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# repo.createCommit()

> Build and push a commit to a branch using the fluent commit builder.

> [!WARNING]
>
> This page documents the earlier Code Storage SDKs: `@pierre/storage`, `pierre-storage`, and
> `code-storage-go`. New code uses the [Pierre SDK](https://code.storage/docs/sdks.md). To move code to the new SDK, use the
> [`pierre-migrate`
> skill](https://github.com/pierrecomputer/skills/tree/main/skills/pierre-migrate).

```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
const fs = await import('node:fs/promises');

const result = await repo
  .createCommit({
    targetBranch: 'main',
    commitMessage: 'Update dashboard docs',
    expectedHeadSha: currentHeadSha, // optional safety check
    author: { name: 'Docs Bot', email: 'docs@example.com' },
  })
  .addFileFromString('docs/changelog.md', '# v2.1.0\n- refresh docs\n')
  .addFile('public/logo.svg', await fs.readFile('assets/logo.svg'))
  .deletePath('docs/legacy.txt')
  .send();

console.log(result.commitSha);
console.log(result.refUpdate.newSha);
console.log(result.refUpdate.oldSha);
```

```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
result = await (
    repo.create_commit(
        target_branch="main",
        commit_message="Update dashboard docs",
        author={"name": "Docs Bot", "email": "docs@example.com"},
    )
    .add_file_from_string("docs/changelog.md", "# v2.1.0\n- refresh docs\n")
    .add_file("public/logo.svg", b"<svg/>")
    .delete_path("docs/legacy.txt")
    .send()
)

print(result["commit_sha"])
print(result["ref_update"]["new_sha"])
print(result["ref_update"]["old_sha"])
```

```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
// Build a commit and add files
builder, err := repo.CreateCommit(storage.CommitOptions{
	TargetBranch:  "main",
	CommitMessage: "Update dashboard docs",
	Author:        storage.CommitSignature{Name: "Docs Bot", Email: "docs@example.com"},
})

// Add and delete files, then send the commit
result, err := builder.
	AddFileFromString("docs/changelog.md", "# v2.1.0\n- refresh docs\n", nil).
	AddFile("public/logo.svg", bytes.NewReader([]byte("<svg/>")), nil).
	DeletePath("docs/legacy.txt").
	Send(context.Background())

// Inspect the result
fmt.Println(result.CommitSHA)
fmt.Println(result.RefUpdate.NewSHA)
fmt.Println(result.RefUpdate.OldSHA)
```

If the backend rejects the update (for example, the branch moved past `expectedHeadSha`),
`repo.createCommit().send()` throws a `RefUpdateError` containing the status, reason, and ref
details.

## Builder Methods

**addFile(...)** `string`

Attach bytes, async iterables, readable streams, or buffers.

**addFileFromString(...)** `string`

Add UTF-8 text files.

**deletePath(...)** `string`

Remove files or folders.

**send()** `string`

Finalize the commit and receive metadata about the new commit.

## Options

**targetBranch** `string` *required*

Branch name that will receive the commit (for example `main`).

**commitMessage** `string` *required*

The commit message.

**author** `string` *required*

Provide `name` and `email` for the commit author.

**expectedHeadSha** `string`

Commit SHA that must match the remote tip; omit to fast-forward unconditionally.

**baseBranch** `string`

Mirrors the `base_branch` metadata field. Point to an existing branch whose tip should seed
`targetBranch` if it does not exist. When bootstrapping a new branch, omit `expectedHeadSha` so
the service copies from `baseBranch`; if both fields are provided and the branch already exists,
the `expectedHeadSha` guard still applies.

**ephemeral** `string`

Store the branch under the `refs/namespaces/ephemeral/...` namespace. When enabled, the commit is
kept out of the primary Git remotes (for example, GitHub) but remains available through storage
APIs.

**ephemeralBase** `string`

Use alongside `baseBranch` when the seed branch also lives in the ephemeral namespace. Requires
`baseBranch` to be set.

**committer** `string`

Provide `name` and `email`. If omitted, the author identity is reused.

**signal** `string`

Abort an in-flight upload with `AbortController`.

**targetRef** `string`

Deprecated. Fully qualified ref (for example `refs/heads/main`). Prefer `targetBranch`.

**refPolicies** `object[]`

Ordered ref policy rules (`{ pattern, ops? }`) in the JWT for this call. Code Storage uses the first rule that matches the target ref. Python: `ref_policies`. Go: `RefPolicies` with type `storage.RefPolicyList`. See [Ref Policies](https://code.storage/docs/repos/ref-policies.md).

## Response

**commitSha** `string`

The SHA of the created commit

**treeSha** `string`

The SHA of the commit's tree object

**targetBranch** `string`

The branch that received the commit

**packBytes** `number`

Size of the uploaded pack in bytes

**blobCount** `number`

Number of blobs in the commit

**refUpdate** `object`

Contains `branch`, `oldSha`/`old_sha`, and `newSha`/`new_sha`

## Streaming Large Files

Use streams or async generators to upload large files without loading them into memory:

```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
import { createReadStream } from 'node:fs';

// Simplest approach: Node.js ReadableStream
await repo
  .createCommit({
    targetBranch: 'assets',
    expectedHeadSha: 'abc123...',
    commitMessage: 'Upload latest design bundle',
    author: { name: 'Assets Uploader', email: 'assets@example.com' },
  })
  .addFile('assets/design-kit.zip', createReadStream('/tmp/large-file.zip'))
  .send();

// Alternative: Async generator for custom chunking
async function* fileChunks() {
  const fs = await import('node:fs/promises');
  const file = await fs.open('/tmp/large-file.zip', 'r');
  const chunkSize = 1024 * 1024; // 1MB chunks

  try {
    while (true) {
      const buffer = Buffer.alloc(chunkSize);
      const { bytesRead } = await file.read(buffer, 0, chunkSize);
      if (bytesRead === 0) break;
      yield buffer.subarray(0, bytesRead);
    }
  } finally {
    await file.close();
  }
}

await repo
  .createCommit({
    targetBranch: 'assets',
    commitMessage: 'Upload with custom chunking',
    author: { name: 'Assets Uploader', email: 'assets@example.com' },
  })
  .addFile('assets/design-kit.zip', fileChunks())
  .send();
```

```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
# Async generator for streaming files in chunks
async def file_chunks():
    """Generate file chunks asynchronously."""
    with open("/tmp/large-file.zip", "rb") as f:
        while chunk := f.read(1024 * 1024):  # Read 1MB at a time
            yield chunk

result = await (
    repo.create_commit(
        target_branch="assets",
        expected_head_sha="abc123...",
        commit_message="Upload latest design bundle",
        author={"name": "Assets Uploader", "email": "assets@example.com"},
    )
    .add_file("assets/design-kit.zip", file_chunks())
    .send()
)
```

```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
// Stream a large file without loading it into memory
file, err := os.Open("/tmp/large-file.zip")
defer file.Close()

// Create a commit and attach the stream
builder, err := repo.CreateCommit(storage.CommitOptions{
	TargetBranch:  "assets",
	CommitMessage: "Upload latest design bundle",
	Author:        storage.CommitSignature{Name: "Assets Uploader", Email: "assets@example.com"},
})

_, err = builder.AddFile("assets/design-kit.zip", file, nil).Send(context.Background())
```

The SDK automatically chunks files to 4 MiB segments, so you can stream large assets (videos,
archives, datasets) without buffering them entirely in memory.

## Response

The `send()` method returns the following:


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.