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

# Git Operations

> Clone, inspect, branch, commit, and push repositories inside a runtime

Every runtime can drive `git` against a repository in its own filesystem. Each
operation runs `git` directly in the sandbox — no shell — and returns the exit
code together with the raw `stdout` and `stderr`, so you can read git's output
exactly as you would locally.

The same eleven operations are available through the Python SDK, the CLI, and the
REST API.

| Operation                                                                     | Endpoint (`POST /v1/agents/runtime/{id}/…`) | Python SDK                       | CLI                         |
| ----------------------------------------------------------------------------- | ------------------------------------------- | -------------------------------- | --------------------------- |
| [Clone](/documentation/agentruntime/git-operations/git-clone)                 | `/git/clone`                                | `runtime.git.clone(...)`         | `runtime git clone`         |
| [Status](/documentation/agentruntime/git-operations/git-status)               | `/git/status`                               | `runtime.git.status(...)`        | `runtime git status`        |
| [List branches](/documentation/agentruntime/git-operations/git-list-branches) | `/git/branches`                             | `runtime.git.branch_list(...)`   | `runtime git branch`        |
| [Checkout](/documentation/agentruntime/git-operations/git-checkout)           | `/git/checkout`                             | `runtime.git.checkout(...)`      | `runtime git checkout`      |
| [Fetch](/documentation/agentruntime/git-operations/git-fetch)                 | `/git/fetch`                                | `runtime.git.fetch(...)`         | `runtime git fetch`         |
| [Pull](/documentation/agentruntime/git-operations/git-pull)                   | `/git/pull`                                 | `runtime.git.pull(...)`          | `runtime git pull`          |
| [Push](/documentation/agentruntime/git-operations/git-push)                   | `/git/push`                                 | `runtime.git.push(...)`          | `runtime git push`          |
| [Add](/documentation/agentruntime/git-operations/git-add)                     | `/git/add`                                  | `runtime.git.add(...)`           | `runtime git add`           |
| [Commit](/documentation/agentruntime/git-operations/git-commit)               | `/git/commit`                               | `runtime.git.commit(...)`        | `runtime git commit`        |
| [Create branch](/documentation/agentruntime/git-operations/git-create-branch) | `/git/branch/create`                        | `runtime.git.create_branch(...)` | `runtime git branch-create` |
| [Delete branch](/documentation/agentruntime/git-operations/git-delete-branch) | `/git/branch/delete`                        | `runtime.git.delete_branch(...)` | `runtime git branch-delete` |

Every method is also available on the async client as
`await client.runtime.git.<operation>(runtime_id, ...)`.

## Network access

Guest egress is deny-by-default. Clone, fetch, pull, and push need a
[network policy](/documentation/agentruntime/getting-started/network-policies)
attached to the runtime; the local operations do not.

## Credentials

Clone, fetch, pull, and push each accept an `auth_token` for a private HTTPS
remote. The token authenticates that single operation: it is sent as an HTTP
`Authorization` header and is never written into the repository, so it does not
appear in `.git/config` or `remote.origin.url` and cannot be read back by code
running in the sandbox.

That means credentials do not carry over between operations — a repository cloned
with a token needs the token again to pull, fetch, or push. Supply it per call:

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
runtime.git.clone(url=REPO_URL, path=repo, auth_token=TOKEN)
runtime.git.pull(repo, auth_token=TOKEN)
runtime.git.push(repo, auth_token=TOKEN)
```

On `push`, `auth_token` takes precedence over `username`/`password`, which remain
available for remotes that need a real account.

The CLI reads the token from `GRAVIXLAYER_GIT_TOKEN` when `--auth-token` is not
given, so a workflow can put it in the environment instead of on the command line.

## Working on a checkout

Git runs as the same sandbox user that
[`run_cmd`](/documentation/agentruntime/sdk-usage) runs commands as, so a
checkout is writable by the build that follows it — install dependencies, run a
test suite, and write generated files into the tree without any ownership fixup:

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
runtime.git.clone(url=REPO_URL, path=repo, auth_token=TOKEN)
runtime.run_cmd("bash", args=["-lc", f"cd {repo} && npm ci && npm test"])
```

A destination directory that does not exist yet is created for you, including any
missing parent directories, which is why `/home/user/repo` works on a fresh runtime.

## End-to-end example

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import uuid

  from gravixlayer import GravixLayer

  client = GravixLayer()

  policy = client.network_policies.create(
      name=f"git-egress-{uuid.uuid4().hex[:8]}",
      egress_mode="allow_all",
      description="Temporary egress for git",
  )

  runtime = None
  try:
      runtime = client.runtime.create(
          template="base-small",
          network_policy_ids=[policy.id],
          timeout=600,
      )
      repo = "/home/user/repo"

      runtime.git.clone(
          url="https://github.com/octocat/Hello-World.git",
          path=repo,
          branch="master",
          depth=1,
      )

      runtime.git.create_branch(repo, "demo-branch")
      runtime.git.checkout(repo, "demo-branch")

      runtime.file.write(f"{repo}/note.txt", "hello\n")
      runtime.git.add(repo, paths=["note.txt"])
      runtime.git.commit(
          repo,
          "add note",
          author_name="Demo",
          author_email="demo@example.com",
      )

      print(runtime.git.status(repo).stdout)
  finally:
      if runtime is not None:
          runtime.kill()
      client.network_policies.delete(policy.id)
  ```

  ```bash CLI theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  REPO=/home/user/repo

  gravixlayer runtime git clone "$RT" https://github.com/octocat/Hello-World.git \
    --target-dir "$REPO" --branch master --depth 1

  gravixlayer runtime git branch-create "$RT" demo-branch --path "$REPO"
  gravixlayer runtime git checkout "$RT" demo-branch --path "$REPO"

  gravixlayer runtime git add "$RT" --path "$REPO" --files note.txt
  gravixlayer runtime git commit "$RT" --path "$REPO" \
    -m "add note" --author-name Demo --author-email demo@example.com

  gravixlayer runtime git status "$RT" --path "$REPO"
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  API="https://api.gravixlayer.ai/v1/agents/runtime/$RT/git"
  AUTH=(-H "Authorization: Bearer $GRAVIXLAYER_API_KEY" -H "Content-Type: application/json")
  REPO=/home/user/repo

  curl -sS -X POST "$API/clone" "${AUTH[@]}" \
    -d "{\"url\":\"https://github.com/octocat/Hello-World.git\",\"path\":\"$REPO\",\"branch\":\"master\",\"depth\":1}"

  curl -sS -X POST "$API/branch/create" "${AUTH[@]}" \
    -d "{\"repository_path\":\"$REPO\",\"branch_name\":\"demo-branch\"}"

  curl -sS -X POST "$API/checkout" "${AUTH[@]}" \
    -d "{\"repository_path\":\"$REPO\",\"ref_name\":\"demo-branch\"}"

  curl -sS -X POST "$API/add" "${AUTH[@]}" \
    -d "{\"repository_path\":\"$REPO\",\"paths\":[\"note.txt\"]}"

  curl -sS -X POST "$API/commit" "${AUTH[@]}" \
    -d "{\"repository_path\":\"$REPO\",\"message\":\"add note\",\"author_name\":\"Demo\",\"author_email\":\"demo@example.com\"}"

  curl -sS -X POST "$API/status" "${AUTH[@]}" \
    -d "{\"repository_path\":\"$REPO\"}"
  ```
</CodeGroup>

## Interpreting the response

Every operation returns the same shape:

| Field       | Type    | Description                                    |
| ----------- | ------- | ---------------------------------------------- |
| `success`   | boolean | Whether the git command completed successfully |
| `exit_code` | integer | Process exit code from `git`                   |
| `stdout`    | string  | Standard output from `git`                     |
| `stderr`    | string  | Standard error from `git`                      |
| `error`     | string  | Error message when the operation fails         |

`success: false` means git itself reported a failure — a merge conflict, a
rejected push, a missing ref. The reason is in `stderr`, and the HTTP status is
still `200` because the request was handled correctly. An HTTP error status means
the request never reached git: a bad parameter, a runtime that is not running, or
a runtime you do not have access to.

Note that git writes progress and many ordinary messages to `stderr`, so a
non-empty `stderr` on its own does not indicate failure — check `success`.

The CLI exits with git's own exit code, so `&&` chains and workflow steps stop on
a failed operation the same way they would running git locally:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
gravixlayer runtime git clone "$RT" "$REPO_URL" --target-dir "$REPO" \
  && gravixlayer runtime exec "$RT" -- make test
```

## Timeouts

Operations that contact a remote are allowed up to 10 minutes; operations
confined to the local repository are allowed up to 30 seconds. Use `depth` on
clone to keep large repositories well inside the limit.

## Other git commands

For anything outside these eleven operations — `git log`, `git diff`, `git rebase`,
submodules, tags — run git through the command API:

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
r = runtime.run_cmd(
    "git",
    args=["-C", "/home/user/repo", "log", "--oneline", "-10"],
)
print(r.stdout)
```
