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

# Git

Clone a repository, inspect changes, commit work, push a branch, or open a pull request from inside a box.

***

## Configure Git Access

If you want to work with private repositories, push changes, or create pull requests, create the box with a GitHub token.

<Note>
  For a fine-grained token, the following permissions are sufficient for basic usage:

  * **Contents** — Read and write
  * **Pull requests** — Read and write
</Note>

```bash title=".env" {2} theme={"system"}
UPSTASH_BOX_API_KEY=box_xxxxxxxxxxxxxxxxxxxxxxxx
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxx
```

<CodeGroup>
  ```tsx box.ts {5-7} theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({
    runtime: "node",
    git: {
      token: process.env.GITHUB_TOKEN,
    },
  })
  ```

  ```python box.py theme={"system"}
  import os
  from upstash_box import Box

  box = Box.create(
      runtime="node",
      git={"token": os.environ["GITHUB_TOKEN"]},
  )
  ```
</CodeGroup>

### Git identity

You can also set the git author identity that will be used for commits made inside the box. Both fields are optional and applied to the container's global git config on creation.

| Field       | Type     | Default             | Description                              |
| ----------- | -------- | ------------------- | ---------------------------------------- |
| `token`     | `string` | —                   | GitHub token for private repos and push  |
| `userName`  | `string` | `"Upstash Box"`     | Value written to `git config user.name`  |
| `userEmail` | `string` | `"box@upstash.com"` | Value written to `git config user.email` |

<CodeGroup>
  ```tsx box.ts {5-9} theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({
    runtime: "node",
    git: {
      token: process.env.GITHUB_TOKEN,
      userName: "deploy-bot",
      userEmail: "deploy-bot@acme.com",
    },
  })
  ```

  ```python box.py theme={"system"}
  import os
  from upstash_box import Box

  box = Box.create(
      runtime="node",
      git={
          "token": os.environ["GITHUB_TOKEN"],
          "user_name": "deploy-bot",
          "user_email": "deploy-bot@acme.com",
      },
  )
  ```
</CodeGroup>

If `userName` or `userEmail` are omitted, the box uses the defaults (`"Upstash Box"` / `"box@upstash.com"`). Omitting `token` is fine for public repositories where push access is not required.

***

## Quickstart

### Clone a repository

<CodeGroup>
  ```tsx box.ts theme={"system"}
  await box.git.clone({
    repo: "https://github.com/acme/web-app",
    branch: "main",
  })

  await box.cd("web-app")

  await box.git.exec({
    args: ["checkout", "-b", "fix/empty-state"],
  })
  ```

  ```python box.py theme={"system"}
  box.git.clone(repo="https://github.com/acme/web-app", branch="main")

  box.cd("web-app")

  box.git.exec(args=["checkout", "-b", "fix/empty-state"])
  ```
</CodeGroup>

### Inspect what changed

Use `status()` for a compact summary and `diff()` to diff the repo's uncommitted changes against the initial state.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const status = await box.git.status()
  const diff = await box.git.diff()

  console.log(status)
  console.log(diff)
  ```

  ```python box.py theme={"system"}
  status = box.git.status()
  diff = box.git.diff()

  print(status)
  print(diff)
  ```
</CodeGroup>

### Commit and push

After your code changes are ready, create a commit and push the branch.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const commit = await box.git.commit({
    message: "fix: handle empty state in dashboard",
  })

  await box.git.push({ branch: "fix/empty-state" })

  console.log(commit.sha)
  console.log(commit.message)
  ```

  ```python box.py theme={"system"}
  commit = box.git.commit(message="fix: handle empty state in dashboard")

  box.git.push(branch="fix/empty-state")

  print(commit.sha)
  print(commit.message)
  ```
</CodeGroup>

### Open a pull request

Create a PR once your branch is pushed.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const pr = await box.git.createPR({
    title: "fix: handle empty state in dashboard",
    body: "Improves the dashboard empty state and avoids a broken loading flow.",
    base: "main",
  })

  console.log(pr.url)
  ```

  ```python box.py theme={"system"}
  pr = box.git.create_pr(
      title="fix: handle empty state in dashboard",
      body="Improves the dashboard empty state and avoids a broken loading flow.",
      base="main",
  )

  print(pr.url)
  ```
</CodeGroup>

***

## API

### Clone

Clones a repository into the current working directory in the box.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  await box.git.clone({
    repo: "https://github.com/acme/api",
  })

  // 👇 you can also select a branch during clone:
  await box.git.clone({
    repo: "https://github.com/acme/api",
    branch: "develop",
  })
  ```

  ```python box.py theme={"system"}
  box.git.clone(repo="https://github.com/acme/api")

  # 👇 you can also select a branch during clone:
  box.git.clone(repo="https://github.com/acme/api", branch="develop")
  ```
</CodeGroup>

### Status

Returns the Git status output for the repository in the current working directory.

* See what files changed
* See if there are there untracked files

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const status = await box.git.status()
  ```

  ```python box.py theme={"system"}
  status = box.git.status()
  ```
</CodeGroup>

### Diff

Returns the current Git diff as a string.

* Useful to display a patch in your UI
* Review what an agent changed

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const diff = await box.git.diff()
  ```

  ```python box.py theme={"system"}
  diff = box.git.diff()
  ```
</CodeGroup>

### Commit

Creates a commit and returns commit information including the SHA and message.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const commit = await box.git.commit({
    message: "feat: add onboarding checklist",
  })
  ```

  ```python box.py theme={"system"}
  commit = box.git.commit(message="feat: add onboarding checklist")
  ```
</CodeGroup>

You can optionally override the commit author for a single commit using `authorName` and `authorEmail`. When omitted, the box's configured git identity is used (either the values set at creation via `config.git` or the latest `updateConfig` values).

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const commit = await box.git.commit({
    message: "feat: add onboarding checklist",
    authorName: "Alice",
    authorEmail: "alice@acme.com",
  })
  ```

  ```python box.py theme={"system"}
  commit = box.git.commit(
      message="feat: add onboarding checklist",
      author_name="Alice",
      author_email="alice@acme.com",
  )
  ```
</CodeGroup>

| Option        | Type     | Required | Description                                    |
| ------------- | -------- | -------- | ---------------------------------------------- |
| `message`     | `string` | Yes      | Commit message                                 |
| `authorName`  | `string` | No       | Override `--author` name for this commit only  |
| `authorEmail` | `string` | No       | Override `--author` email for this commit only |

### Push

Pushes the current branch. You can also provide a branch name explicitly.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  // 👇 push to default branch
  await box.git.push()

  // 👇 or to a specific branch
  await box.git.push({
    branch: "feature/onboarding-checklist",
  })
  ```

  ```python box.py theme={"system"}
  # 👇 push to default branch
  box.git.push()

  # 👇 or to a specific branch
  box.git.push(branch="feature/onboarding-checklist")
  ```
</CodeGroup>

### Create a PR

Creates a pull request and returns the PR URL and metadata.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const pr = await box.git.createPR({
    title: "feat: add onboarding checklist",
    body: "Adds a simple onboarding checklist to improve first-run guidance.",
    base: "main",
  })
  ```

  ```python box.py theme={"system"}
  pr = box.git.create_pr(
      title="feat: add onboarding checklist",
      body="Adds a simple onboarding checklist to improve first-run guidance.",
      base="main",
  )
  ```
</CodeGroup>

### Checkout

Switches to another branch in the current repository.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  await box.git.checkout({
    branch: "release/v1.2.0",
  })
  ```

  ```python box.py theme={"system"}
  box.git.checkout(branch="release/v1.2.0")
  ```
</CodeGroup>

### Run a custom Git command

Runs a raw Git command and returns the command output. Useful escape hatch if the built-in helpers don't cover a use case.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const result = await box.git.exec({
    args: ["branch", "--show-current"],
  })
  ```

  ```python box.py theme={"system"}
  result = box.git.exec(args=["branch", "--show-current"])
  ```
</CodeGroup>

### Update Git Config

Updates the git author identity in the running container. At least one field must be provided; the other field retains its current value.

Returns the effective identity values after the update.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  const identity = await box.git.updateConfig({
    userName: "ci-bot",
    userEmail: "ci-bot@acme.com",
  })

  console.log(identity.git_user_name)  // "ci-bot"
  console.log(identity.git_user_email) // "ci-bot@acme.com"
  ```

  ```python box.py theme={"system"}
  identity = box.git.update_config(user_name="ci-bot", user_email="ci-bot@acme.com")

  print(identity.git_user_name)   # "ci-bot"
  print(identity.git_user_email)  # "ci-bot@acme.com"
  ```
</CodeGroup>

You can update a single field — the other will not change:

<CodeGroup>
  ```tsx box.ts theme={"system"}
  // Only update the email, keep the existing user name
  const identity = await box.git.updateConfig({
    userEmail: "ci-bot@acme.com",
  })
  ```

  ```python box.py theme={"system"}
  # Only update the email, keep the existing user name
  identity = box.git.update_config(user_email="ci-bot@acme.com")
  ```
</CodeGroup>

If the box is in Running or Idle state, the new config is applied immediately inside the container (equivalent to running `git config --global` for the updated fields). Changes take effect for all subsequent commits.

| Option      | Type     | Required | Description                |
| ----------- | -------- | -------- | -------------------------- |
| `userName`  | `string` | No       | New value for `user.name`  |
| `userEmail` | `string` | No       | New value for `user.email` |

**Return value:** `{ git_user_name: string; git_user_email: string }`

***

## Examples

### Use Git with an agent

If you configured a box agent, it also has full git access.

This is especially useful when the exact git steps are not known ahead of time. For example, if the user sends an open-ended request, you may not know in advance what branch name, commit message, or final push flow makes sense.

In that case, you can let the agent inspect the repository, decide what changes are needed, and handle the git workflow itself.

<CodeGroup>
  ```tsx box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({
    runtime: "node",
    agent: {
      harness: Agent.ClaudeCode,
      model: "anthropic/claude-opus-4-6",
      apiKey: process.env.ANTHROPIC_API_KEY,
    },
    git: {
      token: process.env.GITHUB_TOKEN,
    },
  })

  await box.git.clone({
    repo: "https://github.com/acme/web-app",
    branch: "main",
  })

  await box.cd("web-app")

  const run = await box.agent.run({
    prompt: `
  Inspect this repository and fix the broken mobile navigation.

  Create a branch with a sensible name, make the necessary code and test changes, commit the changes, then push the branch and open a pull request against main.`,
  })
  ```

  ```python box.py theme={"system"}
  import os
  from upstash_box import Box, Agent

  box = Box.create(
      runtime="node",
      agent={
          "harness": Agent.CLAUDE_CODE,
          "model": "anthropic/claude-opus-4-6",
          "api_key": os.environ["ANTHROPIC_API_KEY"],
      },
      git={"token": os.environ["GITHUB_TOKEN"]},
  )

  box.git.clone(repo="https://github.com/acme/web-app", branch="main")

  box.cd("web-app")

  run = box.agent.run(
      prompt="""
  Inspect this repository and fix the broken mobile navigation.

  Create a branch with a sensible name, make the necessary code and test changes, commit the changes, then push the branch and open a pull request against main.""",
  )
  ```
</CodeGroup>

### End-to-end PR automation

<CodeGroup>
  ```tsx box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({
    runtime: "node",
    agent: {
      harness: Agent.ClaudeCode,
      model: "anthropic/claude-opus-4-6",
      apiKey: process.env.ANTHROPIC_API_KEY,
    },
    git: {
      token: process.env.GITHUB_TOKEN,
    },
  })

  await box.git.clone({
    repo: "https://github.com/acme/docs-site",
    branch: "main",
  })

  await box.cd("docs-site")

  await box.git.exec({
    args: ["checkout", "-b", "docs/deployment-troubleshooting"],
  })

  await box.agent.run({
    prompt: "Add a troubleshooting section to the deployment guide.",
  })

  await box.git.commit({
    message: "docs: add deployment troubleshooting section",
  })

  await box.git.push({ branch: "docs/deployment-troubleshooting" })

  const pr = await box.git.createPR({
    title: "docs: add deployment troubleshooting section",
    base: "main",
  })
  ```

  ```python box.py theme={"system"}
  import os
  from upstash_box import Box, Agent

  box = Box.create(
      runtime="node",
      agent={
          "harness": Agent.CLAUDE_CODE,
          "model": "anthropic/claude-opus-4-6",
          "api_key": os.environ["ANTHROPIC_API_KEY"],
      },
      git={"token": os.environ["GITHUB_TOKEN"]},
  )

  box.git.clone(repo="https://github.com/acme/docs-site", branch="main")

  box.cd("docs-site")

  box.git.exec(args=["checkout", "-b", "docs/deployment-troubleshooting"])

  box.agent.run(prompt="Add a troubleshooting section to the deployment guide.")

  box.git.commit(message="docs: add deployment troubleshooting section")

  box.git.push(branch="docs/deployment-troubleshooting")

  pr = box.git.create_pr(
      title="docs: add deployment troubleshooting section",
      base="main",
  )
  ```
</CodeGroup>
