---
title: "The branch diff (GitHub's three-dot diff, merge base to head)"
description: "Computed in the Worker from Artifacts reads, with no clone: the merge\nbase, a walk of the two trees that skips equal subtrees, the changed\nblobs only, and a line diff (patience, then bounded Myers between its\nanchors, as `git diff --patience`). Exact renames (the same blob\nmoved) show as `renamed`; there is no similarity rename detection.\n\n`max_bytes` bounds the bytes of hunk lines returned. Files past the\nbudget keep their entry with `patch_omitted: budget`. A text file over\n8 MiB on either side has `patch_omitted: too_large` and null counts.\n\n**Files changed** (`patches=1`): the answer is a `BranchDiff`, each\nfile with its own unified patch in git's format (`patch`, ready for a\ndiff view such as @pierre/diffs' `processFile`), or null when left\nout: a binary (a NUL in the first 8,000 bytes), a text file over 8 MiB\non either side, or past 2 MiB of patches in all. At most 1,000 files\nare listed (`too_many_files`, with `files_total`). Main and the head\ncome from Pando's stored heads; the answer is kept by (main, head),\nwhich never changes, so a repeat costs no Artifacts read, and `ETag`\nis the two shas (a repeat with `If-None-Match` is a 304). `format`,\n`hunks`, `max_bytes` and `paths` do not apply.\n\n**Files changed, streamed** (`patches=1&stream=1`, the web's branch\npage, for a branch of any size): `application/x-ndjson`, one\n`BranchDiffLine` a line, each sent as soon as it is known: `start`\n(the ends, the merge base, `files_total`, `too_many_files`), then one\n`file` per changed file (a `DiffFile` with its `patch`) in a file tree's order\n(folders before files at each level, by name), then `end` (`stats`,\n`truncated`); `error` if the diff fails after its start. At most 5,000\nfiles, and 32 MiB of patches in all. Each pair of blobs diffed is kept\nin R2, so the next head of a branch reads only the pairs a push\nchanged; the whole answer is kept by (main, head) once streamed, and\nstreamed from there after with the same `ETag` and 304. An answer\nbeing computed has no `ETag` (`Cache-Control: no-store`): it may stop\npart way, with an `error` line, and the next request goes on from the\npairs already kept.\n"
---

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

Path: Pando API › branches

`GET /v1/monorepos/{owner}/{monorepo}/repos/{repo}/branches/{branch}/diff`

Computed in the Worker from Artifacts reads, with no clone: the merge
base, a walk of the two trees that skips equal subtrees, the changed
blobs only, and a line diff (patience, then bounded Myers between its
anchors, as `git diff --patience`). Exact renames (the same blob
moved) show as `renamed`; there is no similarity rename detection.

`max_bytes` bounds the bytes of hunk lines returned. Files past the
budget keep their entry with `patch_omitted: budget`. A text file over
8 MiB on either side has `patch_omitted: too_large` and null counts.

**Files changed** (`patches=1`): the answer is a `BranchDiff`, each
file with its own unified patch in git's format (`patch`, ready for a
diff view such as @pierre/diffs' `processFile`), or null when left
out: a binary (a NUL in the first 8,000 bytes), a text file over 8 MiB
on either side, or past 2 MiB of patches in all. At most 1,000 files
are listed (`too_many_files`, with `files_total`). Main and the head
come from Pando's stored heads; the answer is kept by (main, head),
which never changes, so a repeat costs no Artifacts read, and `ETag`
is the two shas (a repeat with `If-None-Match` is a 304). `format`,
`hunks`, `max_bytes` and `paths` do not apply.

**Files changed, streamed** (`patches=1&stream=1`, the web's branch
page, for a branch of any size): `application/x-ndjson`, one
`BranchDiffLine` a line, each sent as soon as it is known: `start`
(the ends, the merge base, `files_total`, `too_many_files`), then one
`file` per changed file (a `DiffFile` with its `patch`) in a file tree's order
(folders before files at each level, by name), then `end` (`stats`,
`truncated`); `error` if the diff fails after its start. At most 5,000
files, and 32 MiB of patches in all. Each pair of blobs diffed is kept
in R2, so the next head of a branch reads only the pairs a push
changed; the whole answer is kept by (main, head) once streamed, and
streamed from there after with the same `ETag` and 304. An answer
being computed has no `ETag` (`Cache-Control: no-store`): it may stop
part way, with an `error` line, and the next request goes on from the
pairs already kept.

## Authentication

Requires one of the following:

- `credential`, http, header `Authorization`
- `session`, apiKey, in cookie

## Path parameters

- `branchDiff.path.owner` (string, required) — The monorepo's owner, a namespace (a person's login or an organization). Matched without case.
  - pattern `^[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9])){0,38}$`
- `branchDiff.path.monorepo` (string, required) — The monorepo's name within its owner (or an old name). Matched without case.
  - pattern `^[a-z0-9](?:[a-z0-9._]|-(?!-)){0,38}$`
- `branchDiff.path.repo` (string, required) — The repo's `name` (`projects-web`).
- `branchDiff.path.branch` (string, required) — The branch name, `/` encoded as `%2F`.

## Query parameters

- `branchDiff.query.format` (string, optional)
  - one of `"json"`, `"patch"`; default `"json"`
- `branchDiff.query.hunks` (string, optional) — `1` to include per-file hunks in JSON.
  - one of `"0"`, `"1"`; default `"0"`
- `branchDiff.query.max_bytes` (integer, optional) — Budget for hunk bytes. Default 1048576, maximum 8388608.
  - min 0
- `branchDiff.query.paths` (string, optional) — Path prefixes, comma-separated or repeated (`paths=src/auth/&paths=README.md`).
- `branchDiff.query.patches` (string, optional) — `1`: Files changed, a `BranchDiff` (see above).
  - one of `"0"`, `"1"`; default `"0"`
- `branchDiff.query.stream` (string, optional) — `1` with `patches=1`: Files changed as NDJSON, a `BranchDiffLine` a line (see above).
  - one of `"0"`, `"1"`; default `"0"`

## Code samples

### cURL

```curl
curl --request GET \
  --url https://app.gitpando.com/v1/monorepos/string/string/repos/string/branches/string/diff \
  --header 'Authorization: Bearer <token>'
```

### TypeScript

```typescript
const url = 'https://app.gitpando.com/v1/monorepos/string/string/repos/string/branches/string/diff';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error(err));
```

### Python

```python
import requests

url = "https://app.gitpando.com/v1/monorepos/string/string/repos/string/branches/string/diff"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.text)
```

## Responses

### 200

JSON (a `BranchDiff` with `patches=1`), or `text/x-patch` for `format=patch`: a unified diff with
`diff --git` headers, ready for `git apply` or
`plannotator review --patch-file -`. In patch form, files past the
budget are left out and the response carries
`X-Pando-Diff-Omitted: <count>`.

#### Body (application/json)

One of:

- [Diff](/api/schemas/Diff/)
- [BranchDiff](/api/schemas/BranchDiff/)

##### Example

```json
{
  "base_branch": "string",
  "base": "string",
  "head": "string",
  "merge_base": "string",
  "truncated": true,
  "stats": {
    "files": 0,
    "additions": 0,
    "deletions": 0
  },
  "files": [
    {
      "path": "string",
      "old_path": "string",
      "status": "added",
      "old_sha": "string",
      "new_sha": "string",
      "old_mode": "string",
      "new_mode": "string",
      "binary": true,
      "additions": 0,
      "deletions": 0,
      "hunks": [
        {
          "old_start": 0,
          "old_lines": 0,
          "new_start": 0,
          "new_lines": 0,
          "lines": [
            "string"
          ]
        }
      ],
      "patch_omitted": "binary"
    }
  ]
}
```

#### Body (text/x-patch)

##### Example

```text
string
```

#### Body (application/x-ndjson)

One of:

- `object`
- `object`
- `object`
- `object`

##### Example

```json
{
  "type": "start",
  "base_branch": "string",
  "base": "string",
  "head": "string",
  "merge_base": "string",
  "files_total": 0,
  "too_many_files": true
}
```

### 304

`patches=1` with `If-None-Match` naming this (main, head).

### 404

An error

#### Example

```json
{
  "error": {
    "code": "string",
    "message": "string",
    "paths": [
      "string"
    ],
    "checks": {
      "sha": "string",
      "state": "success",
      "required": [
        "string"
      ],
      "checks_unknown": "string",
      "missing": [
        "string"
      ],
      "statuses": [
        {
          "sha": "string",
          "context": "string",
          "state": "pending",
          "target_url": "string",
          "description": "string",
          "creator": "string",
          "app": "string",
          "created_at": "2019-08-24T14:15:22Z"
        }
      ]
    }
  }
}
```

- `branchDiff.response.404.error` (object, required)
  - `branchDiff.response.404.error.code` (string, required)
  - `branchDiff.response.404.error.message` (string, required)
  - `branchDiff.response.404.error.paths` (array<string>, optional)
  - `branchDiff.response.404.error.checks` (object, optional) — GitHub's combined status, plus the required contexts and which are missing.
    - `branchDiff.response.404.error.checks.sha` (string | null, required)
    - `branchDiff.response.404.error.checks.state` (string, required) — `success` when the merge gate passes; `missing` when a required context has not reported; `unknown` while the required checks are (an unforced merge is refused).
      - one of `"success"`, `"pending"`, `"failure"`, `"error"`, `"missing"`, `"unknown"`
    - `branchDiff.response.404.error.checks.required` (array | null, required) — Null while unknown.
    - `branchDiff.response.404.error.checks.checks_unknown` (string | null, required) — Why the required checks are unknown, in plain words: "Pando couldn't read this monorepo's required checks; try again", or "pando.toml line 3: expected comma or end of structure; fix it on main, or merge with force". Null otherwise.
    - `branchDiff.response.404.error.checks.statuses` (array<object>, required) — The latest status per context.
      - `branchDiff.response.404.error.checks.statuses.sha` (string, required)
      - `branchDiff.response.404.error.checks.statuses.context` (string, required)
      - `branchDiff.response.404.error.checks.statuses.state` (string, required)
        - one of `"pending"`, `"success"`, `"failure"`, `"error"`
      - `branchDiff.response.404.error.checks.statuses.created_at` (string, required)
        - format `date-time`
      - `branchDiff.response.404.error.checks.statuses.target_url` (string | null, optional)
      - `branchDiff.response.404.error.checks.statuses.description` (string | null, optional)
      - `branchDiff.response.404.error.checks.statuses.creator` (string, optional) — The member who posted it (a login); `app:<slug>` for a status posted with a status token or by a CI integration; `hook:<hook id>` for a status token from a web hook with no app.
      - `branchDiff.response.404.error.checks.statuses.app` (string | null, optional) — The CI service that reported it (`buildkite`, `github-actions`, ...), stamped by Pando from a status token or a CI integration, never from the body or `target_url`. Null when a member posted it with their own credential. The web shows the service's mark for a slug it knows.
    - `branchDiff.response.404.error.checks.missing` (array<string>, optional)

### 409

`no_merge_base`: the branch shares no history with the default branch.

#### Example

```json
{
  "error": {
    "code": "string",
    "message": "string",
    "paths": [
      "string"
    ],
    "checks": {
      "sha": "string",
      "state": "success",
      "required": [
        "string"
      ],
      "checks_unknown": "string",
      "missing": [
        "string"
      ],
      "statuses": [
        {
          "sha": "string",
          "context": "string",
          "state": "pending",
          "target_url": "string",
          "description": "string",
          "creator": "string",
          "app": "string",
          "created_at": "2019-08-24T14:15:22Z"
        }
      ]
    }
  }
}
```

- `branchDiff.response.409.error` (object, required)
  - `branchDiff.response.409.error.code` (string, required)
  - `branchDiff.response.409.error.message` (string, required)
  - `branchDiff.response.409.error.paths` (array<string>, optional)
  - `branchDiff.response.409.error.checks` (object, optional) — GitHub's combined status, plus the required contexts and which are missing.
    - `branchDiff.response.409.error.checks.sha` (string | null, required)
    - `branchDiff.response.409.error.checks.state` (string, required) — `success` when the merge gate passes; `missing` when a required context has not reported; `unknown` while the required checks are (an unforced merge is refused).
      - one of `"success"`, `"pending"`, `"failure"`, `"error"`, `"missing"`, `"unknown"`
    - `branchDiff.response.409.error.checks.required` (array | null, required) — Null while unknown.
    - `branchDiff.response.409.error.checks.checks_unknown` (string | null, required) — Why the required checks are unknown, in plain words: "Pando couldn't read this monorepo's required checks; try again", or "pando.toml line 3: expected comma or end of structure; fix it on main, or merge with force". Null otherwise.
    - `branchDiff.response.409.error.checks.statuses` (array<object>, required) — The latest status per context.
      - `branchDiff.response.409.error.checks.statuses.sha` (string, required)
      - `branchDiff.response.409.error.checks.statuses.context` (string, required)
      - `branchDiff.response.409.error.checks.statuses.state` (string, required)
        - one of `"pending"`, `"success"`, `"failure"`, `"error"`
      - `branchDiff.response.409.error.checks.statuses.created_at` (string, required)
        - format `date-time`
      - `branchDiff.response.409.error.checks.statuses.target_url` (string | null, optional)
      - `branchDiff.response.409.error.checks.statuses.description` (string | null, optional)
      - `branchDiff.response.409.error.checks.statuses.creator` (string, optional) — The member who posted it (a login); `app:<slug>` for a status posted with a status token or by a CI integration; `hook:<hook id>` for a status token from a web hook with no app.
      - `branchDiff.response.409.error.checks.statuses.app` (string | null, optional) — The CI service that reported it (`buildkite`, `github-actions`, ...), stamped by Pando from a status token or a CI integration, never from the body or `target_url`. Null when a member posted it with their own credential. The web shows the service's mark for a slug it knows.
    - `branchDiff.response.409.error.checks.missing` (array<string>, optional)


Source: https://docs.gitpando.com/api/branches/branchDiff/index.md
