# File CRUD Operations

## List Root Directory

```
GET /repos/{owner}/{repo}/contents
```

Query parameters:
- `ref` (string) - Branch, tag, or commit SHA (defaults to default branch)

```bash
# List files in root directory
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents"

# List files from a specific branch
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents?ref={branch}"
```

## Get File Content

```
GET /repos/{owner}/{repo}/contents/{filepath}
```

Returns file content as base64-encoded string. For directories, returns a listing of entries.

Query parameters:
- `ref` (string) - Branch, tag, or commit SHA

```bash
# Get a file (content is base64 encoded)
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/src/main.go"

# Get file from a specific branch
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/README.md?ref={branch}"

# Get and decode the content
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/README.md" | jq -r '.content' | base64 -d

# List a subdirectory
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/src"
```

### Get File Response

```json
{
  "name": "main.go",
  "path": "src/main.go",
  "sha": "abc123def456789",
  "size": 1234,
  "type": "file",
  "encoding": "base64",
  "content": "cGFja2FnZSBtYWluCi4uLg==",
  "download_url": "https://{FORGEJO_HOST}/owner/repo/raw/branch/main/src/main.go",
  "html_url": "https://{FORGEJO_HOST}/owner/repo/src/branch/main/src/main.go",
  "git_url": "https://{FORGEJO_HOST}/api/v1/repos/{owner}/{repo}/git/blobs/{sha}",
  "url": "https://{FORGEJO_HOST}/api/v1/repos/{owner}/{repo}/contents/src/main.go",
  "_links": {
    "self": "https://{FORGEJO_HOST}/api/v1/repos/{owner}/{repo}/contents/src/main.go",
    "git": "https://{FORGEJO_HOST}/api/v1/repos/{owner}/{repo}/git/blobs/{sha}",
    "html": "https://{FORGEJO_HOST}/owner/repo/src/branch/main/src/main.go"
  }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | File name |
| `path` | string | Full file path |
| `sha` | string | Git blob SHA (needed for update/delete) |
| `size` | int | File size in bytes |
| `type` | string | `file` or `dir` |
| `encoding` | string | Content encoding (`base64`) |
| `content` | string | Base64-encoded file content |
| `download_url` | string | Direct download URL |
| `html_url` | string | Web UI URL |
| `git_url` | string | Git API URL |
| `url` | string | API URL |
| `_links` | object | Related links (self, git, html) |

## Create File

```
POST /repos/{owner}/{repo}/contents/{filepath}
```

```bash
# Create a new file
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d "{
    \"content\": \"$(echo -n 'Hello, World!' | base64)\",
    \"message\": \"Add greeting file\"
  }" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/hello.txt"

# Create a file on a specific branch
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d "{
    \"content\": \"$(echo -n 'package main' | base64)\",
    \"message\": \"Add main.go\",
    \"branch\": \"{branch}\"
  }" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/main.go"

# Create a file and a new branch at the same time
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d "{
    \"content\": \"$(echo -n 'new feature code' | base64)\",
    \"message\": \"Add feature file\",
    \"new_branch\": \"feature/new-thing\"
  }" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/feature.txt"
```

## Update File

```
PUT /repos/{owner}/{repo}/contents/{filepath}
```

**Requires the current file SHA** (obtained from a GET request). This prevents overwriting concurrent changes.

```bash
# Step 1: Get current file SHA
SHA=$(curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/hello.txt" | jq -r '.sha')

# Step 2: Update the file
curl -s -X PUT \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d "{
    \"content\": \"$(echo -n 'Hello, Updated World!' | base64)\",
    \"message\": \"Update greeting\",
    \"sha\": \"${SHA}\"
  }" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/hello.txt"
```

## Delete File

```
DELETE /repos/{owner}/{repo}/contents/{filepath}
```

**Requires the current file SHA**.

```bash
# Step 1: Get current file SHA
SHA=$(curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/hello.txt" | jq -r '.sha')

# Step 2: Delete the file
curl -s -X DELETE \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d "{
    \"message\": \"Remove greeting file\",
    \"sha\": \"${SHA}\"
  }" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents/hello.txt"
```

## Create Multiple Files in One Commit

```
POST /repos/{owner}/{repo}/contents
```

Create, update, or delete multiple files in a single commit.

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "branch": "{branch}",
    "message": "Add multiple files",
    "files": [
      {
        "operation": "create",
        "path": "docs/guide.md",
        "content": "'$(echo -n '# Guide' | base64)'"
      },
      {
        "operation": "create",
        "path": "docs/api.md",
        "content": "'$(echo -n '# API Reference' | base64)'"
      }
    ]
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/contents"
```

## Apply Diff/Patch

```
POST /repos/{owner}/{repo}/diffpatch
```

Apply a unified diff/patch to the repository.

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "branch": "{branch}",
    "message": "Apply patch",
    "content": "--- a/file.txt\n+++ b/file.txt\n@@ -1 +1 @@\n-old line\n+new line\n"
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/diffpatch"
```

## Create/Update Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `content` | string | **Yes** (create/update) | Base64-encoded file content |
| `message` | string | **Yes** | Commit message |
| `branch` | string | No | Target branch (defaults to default branch) |
| `new_branch` | string | No | Create a new branch with this name |
| `sha` | string | **Yes** (update/delete) | Current file SHA for conflict detection |
| `author` | object | No | `{"name": "...", "email": "..."}` |
| `committer` | object | No | `{"name": "...", "email": "..."}` |

## Important Notes

- Content must be **base64 encoded** for create and update operations
- The `sha` field is **required** for update and delete — omitting it or providing a stale SHA will result in a 409 Conflict error
- To get the current SHA, first GET the file and read the `sha` field from the response
- Use `new_branch` to create a file on a new branch in a single API call (useful for PR workflows)
- Directory listings return an array of entries, each with `type` set to `file` or `dir`
