Files
KohakuHub/docs/api/branches.md
2025-10-24 18:45:55 +08:00

10 KiB

title, description, icon
title description icon
Branches & Tags API Branch/tag management, merge, revert, reset operations i-carbon-branch

Branches & Tags API

Manage branches, tags, and advanced Git operations (merge, revert, reset).


Branches

Create Branch

Pattern: POST /api/{repo_type}s/{namespace}/{name}/branch

Authentication: Required (delete permission)

Request Body:

{
  "branch": "feature-branch",
  "revision": "main"
}

Fields:

  • branch: New branch name (required)
  • revision: Source revision (branch/commit, default: "main")

Response:

{
  "success": true,
  "message": "Branch 'feature-branch' created"
}

Status Codes:

  • 200 OK - Branch created
  • 404 Not Found - Repository or source revision not found
  • 409 Conflict - Branch already exists

Delete Branch

Pattern: DELETE /api/{repo_type}s/{namespace}/{name}/branch/{branch}

Authentication: Required (delete permission)

Protection: Cannot delete "main" branch

Response:

{
  "success": true,
  "message": "Branch 'feature-branch' deleted"
}

Status Codes:

  • 200 OK - Branch deleted
  • 400 Bad Request - Attempting to delete main branch
  • 404 Not Found - Repository or branch not found

Merge Branches

Pattern: POST /api/{repo_type}s/{namespace}/{name}/merge/{source_ref}/into/{destination_branch}

Authentication: Required (write permission)

Request Body:

{
  "message": "Merge feature into main",
  "metadata": {
    "author": "alice"
  },
  "strategy": "dest-wins",
  "force": false,
  "allow_empty": false,
  "squash_merge": false
}

Fields (all optional):

  • message: Commit message
  • metadata: Additional metadata
  • strategy: Conflict resolution
    • "dest-wins": Destination wins on conflict
    • "source-wins": Source wins on conflict
    • null: Fail on conflict (default)
  • force: Force merge even with conflicts
  • allow_empty: Allow merge with no changes
  • squash_merge: Squash all commits into one

Response:

{
  "success": true,
  "message": "Successfully merged feature into main",
  "result": {
    "reference": "commit_hash",
    "summary": {
      "added": 5,
      "removed": 2,
      "changed": 3
    }
  }
}

Status Codes:

  • 200 OK - Merged successfully
  • 409 Conflict - Merge conflict (use strategy to resolve)
  • 500 Internal Server Error - Merge failed

Auto-tracking:

  • LFS objects tracked automatically
  • Commit recorded in database
  • User attribution preserved

Revert Commit

Pattern: POST /api/{repo_type}s/{namespace}/{name}/branch/{branch}/revert

Authentication: Required (write permission)

Purpose: Create new commit that undoes changes from a specific commit

Request Body:

{
  "ref": "commit_id_to_revert",
  "parent_number": 1,
  "message": "Revert: broken feature",
  "metadata": {
    "reason": "broke production"
  },
  "force": false,
  "allow_empty": false
}

Fields:

  • ref: Commit ID or ref to revert (required)
  • parent_number: For merge commits (default: 1)
  • message: Commit message (optional)
  • metadata: Additional metadata (optional)
  • force: Force revert even with conflicts
  • allow_empty: Allow empty revert

Response:

{
  "success": true,
  "message": "Successfully reverted commit abc123de on branch 'main'",
  "new_commit_id": "new_commit_hash"
}

Important Notes:

  • Creates NEW commit (doesn't delete history)
  • LFS files automatically handled (no recoverability check needed)
  • If conflicts: returns 409 error

Status Codes:

  • 200 OK - Reverted successfully
  • 404 Not Found - Commit not found
  • 409 Conflict - Revert caused conflicts

Reset Branch

Pattern: POST /api/{repo_type}s/{namespace}/{name}/branch/{branch}/reset

Authentication: Required (write permission)

Purpose: Reset branch to a specific commit (like git reset --hard)

Request Body:

{
  "ref": "commit_id_to_reset_to",
  "message": "Reset to stable version",
  "force": false
}

Fields:

  • ref: Commit ID or ref to reset to (required)
  • message: Commit message (optional)
  • force: Skip LFS recoverability check

Safety Checks:

  1. Main branch requires force: true
  2. LFS file availability checked (unless force: true)
  3. Creates new commit (preserves history)

Response:

{
  "success": true,
  "message": "Successfully reset branch 'main' to commit abc123de (new commit created)",
  "commit_id": "new_commit_hash"
}

LFS Recoverability Check:

  • Validates all LFS files from target commit still exist
  • Checks all commits between target and HEAD
  • If files garbage-collected: returns 400 error

Error if LFS unavailable:

{
  "error": "Cannot reset to commit abc123: 5 LFS file(s) across 3 commit(s) have been garbage collected",
  "missing_files": ["model.safetensors", "data.bin"],
  "affected_commits": ["commit1", "commit2", "commit3"],
  "recoverable": false
}

Use force: true to bypass check (may break LFS refs)

Status Codes:

  • 200 OK - Reset successful
  • 400 Bad Request - LFS files not recoverable or main branch without force
  • 404 Not Found - Commit not found

Implementation Details:

  • Uses diff-based approach (not destructive)
  • Restores files from target commit
  • Syncs File table after reset
  • Records reset commit in database

Tags

Create Tag

Pattern: POST /api/{repo_type}s/{namespace}/{name}/tag

Authentication: Required (delete permission)

Request Body:

{
  "tag": "v1.0.0",
  "revision": "main",
  "message": "Release version 1.0"
}

Fields:

  • tag: Tag name (required)
  • revision: Source revision (default: "main")
  • message: Tag message (optional)

Response:

{
  "success": true,
  "message": "Tag 'v1.0.0' created"
}

Status Codes:

  • 200 OK - Tag created
  • 404 Not Found - Repository or revision not found
  • 500 Internal Server Error - Failed to create tag

Delete Tag

Pattern: DELETE /api/{repo_type}s/{namespace}/{name}/tag/{tag}

Authentication: Required (delete permission)

Response:

{
  "success": true,
  "message": "Tag 'v1.0.0' deleted"
}

Status Codes:

  • 200 OK - Tag deleted
  • 404 Not Found - Repository or tag not found
  • 500 Internal Server Error - Failed to delete tag

Usage Examples

Merge Feature Branch

import requests

API_BASE = "http://localhost:28080/api"
TOKEN = "your_token"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

# Merge feature into main
response = requests.post(
    f"{API_BASE}/models/username/repo/merge/feature-branch/into/main",
    json={
        "message": "Merge feature: Add new model",
        "strategy": "dest-wins"  # Main wins on conflicts
    },
    headers=HEADERS
)

result = response.json()
print(f"Merged: {result['message']}")
print(f"Commit: {result['result']['reference']}")

Revert Bad Commit

# Find the bad commit
commits_resp = requests.get(
    f"{API_BASE}/models/username/repo/commits/main?limit=10",
    headers=HEADERS
)
commits = commits_resp.json()["commits"]
bad_commit = commits[0]["id"]  # Latest commit

# Revert it
revert_resp = requests.post(
    f"{API_BASE}/models/username/repo/branch/main/revert",
    json={
        "ref": bad_commit,
        "message": "Revert: broken model weights"
    },
    headers=HEADERS
)

result = revert_resp.json()
print(f"Reverted: {result['new_commit_id']}")

Reset to Previous Version

# Reset to 3 commits ago
commits_resp = requests.get(
    f"{API_BASE}/models/username/repo/commits/main?limit=5",
    headers=HEADERS
)
commits = commits_resp.json()["commits"]
target_commit = commits[3]["id"]  # 3 commits back

# Reset (with LFS check)
reset_resp = requests.post(
    f"{API_BASE}/models/username/repo/branch/main/reset",
    json={
        "ref": target_commit,
        "message": "Reset to stable version",
        "force": False  # Check LFS availability
    },
    headers=HEADERS
)

if reset_resp.status_code == 400:
    # LFS files not available
    error = reset_resp.json()
    print(f"Cannot reset: {error['error']}")
    print(f"Missing files: {error['missing_files']}")

    # Force reset anyway (may break)
    reset_resp = requests.post(
        f"{API_BASE}/models/username/repo/branch/main/reset",
        json={"ref": target_commit, "force": True},
        headers=HEADERS
    )

result = reset_resp.json()
print(f"Reset to: {result['commit_id']}")

Create Release Tag

# Tag current main branch
tag_resp = requests.post(
    f"{API_BASE}/models/username/repo/tag",
    json={
        "tag": "v1.0.0",
        "revision": "main",
        "message": "Release version 1.0 - Production ready"
    },
    headers=HEADERS
)

result = tag_resp.json()
print(result["message"])

# Download specific version
file_url = f"{API_BASE}/models/username/repo/resolve/v1.0.0/model.safetensors"

Git Command Equivalents

Branches

# Create branch
POST /branch {"branch": "feature", "revision": "main"}
# git checkout -b feature main

# Delete branch
DELETE /branch/feature
# git branch -d feature

# Merge
POST /merge/feature/into/main {"strategy": "dest-wins"}
# git checkout main && git merge feature -X theirs

Tags

# Create tag
POST /tag {"tag": "v1.0", "revision": "main"}
# git tag v1.0 main

# Delete tag
DELETE /tag/v1.0
# git tag -d v1.0

Advanced Operations

# Revert
POST /branch/main/revert {"ref": "abc123"}
# git revert abc123

# Reset
POST /branch/main/reset {"ref": "abc123"}
# git reset --hard abc123 (but creates new commit)

Best Practices

Branching Strategy:

  • Use main for production
  • Create feature branches for development
  • Merge with dest-wins to protect main
  • Tag releases for versioning

LFS Considerations:

  • Reset checks LFS availability (prevent broken refs)
  • Use force: true only if you understand the risk
  • Keep lfs_keep_versions high enough for your workflow
  • Monitor storage after resets/reverts

Safety:

  • Always use force: false first (see errors)
  • Test merges on feature branches first
  • Tag before risky operations (easy rollback)
  • Document reset/revert reasons in commit message

Next Steps