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

# Repository Forks

> Create independent repository copies for experiments, templates, and isolated development.

A fork is an independent copy of an existing Code Storage repository. It starts from one source
commit and has its own access. After the copy, a change in one repository does not reach the other.

In the HTTP API, the `base_repo` field of the create-repository request sets the source. `base_repo`
is a one-time copy of a Code Storage repository; `upstream` is a lasting link to an external Git
host. To keep a repository in sync with another host, see [GitHub Sync](https://code.storage/docs/repos/github-sync.md) and
[Generic Sync](https://code.storage/docs/repos/generic-sync.md).

## When to use a fork

* **Templates**: Create new projects from a starter template
* **Experiments**: Test changes in an independent repository
* **Snapshots**: Capture a repository's state at a specific commit or branch
* **Isolation**: Separate work across a trust or tenant boundary, or give each user an independent
  project of their own

For per-agent and per-task isolation inside a single repository, use the
[ephemeral namespace](https://code.storage/docs/repos/ephemeral-branches.md) instead. Those branches share the repository's Git
objects and its access, and you can promote the work you keep.

## Quick start

Set `PIERRE_ORG` and `PIERRE_PRIVATE_KEY` as shown in the
[Quick Start](https://code.storage/docs/getting-started/quick-start.md).

```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
import { Pierre } from '@pierre/sdk';

const pierre = new Pierre();

// Fork at the latest commit (HEAD)
const fork = await pierre.repos.create({
  repo_name: 'my-fork',
  base_repo: {
    name: 'template-repo', // Source repository name
  },
});

// Fork at a specific branch
const branchFork = await pierre.repos.create({
  repo_name: 'feature-fork',
  base_repo: {
    name: 'template-repo',
    ref: 'develop', // Fork from tip of 'develop' branch
  },
});

// Fork at a specific commit
const commitFork = await pierre.repos.create({
  repo_name: 'snapshot-fork',
  base_repo: {
    name: 'template-repo',
    ref: 'abc123def456...', // Fork at exact commit
  },
});
```

```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
from pierre import Pierre

pierre = Pierre()

# Fork at the latest commit (HEAD)
fork = pierre.repos.create(
    repo_name="my-fork",
    base_repo={
        "name": "template-repo",  # Source repository name
    },
)

# Fork at a specific branch
branch_fork = pierre.repos.create(
    repo_name="feature-fork",
    base_repo={
        "name": "template-repo",
        "ref": "develop",  # Fork from tip of 'develop' branch
    },
)

# Fork at a specific commit
commit_fork = pierre.repos.create(
    repo_name="snapshot-fork",
    base_repo={
        "name": "template-repo",
        "ref": "abc123def456...",  # Fork at exact commit
    },
)
```

```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
import (
	"context"
	"fmt"

	pierre "github.com/pierrecomputer/sdk/go"
)

ctx := context.Background()
client, err := pierre.NewClient()
if err != nil {
	return err
}

// Fork at the latest commit (HEAD)
fork, err := client.Repos.Create(ctx, pierre.ReposCreateParams{
	RepoName: pierre.String("my-fork"),
	BaseRepo: pierre.Value(pierre.BaseRepo{
		Name: "template-repo", // Source repository name
	}),
})
if err != nil {
	return err
}
fmt.Println(fork.RepoName)

// Fork at a specific branch
branchFork, err := client.Repos.Create(ctx, pierre.ReposCreateParams{
	RepoName: pierre.String("feature-fork"),
	BaseRepo: pierre.Value(pierre.BaseRepo{
		Name: "template-repo",
		Ref:  pierre.String("develop"),
	}),
})
if err != nil {
	return err
}
fmt.Println(branchFork.RepoName)

// Fork at a specific commit
commitFork, err := client.Repos.Create(ctx, pierre.ReposCreateParams{
	RepoName: pierre.String("snapshot-fork"),
	BaseRepo: pierre.Value(pierre.BaseRepo{
		Name: "template-repo",
		Ref:  pierre.String("abc123def456..."),
	}),
})
if err != nil {
	return err
}
fmt.Println(commitFork.RepoName)
```

```bash HTTP theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
# SOURCE_TOKEN is a JWT with git:read on template-repo.
curl "$PIERRE_API_BASE_URL/api/repos" \
  -X POST \
  -H "Authorization: Bearer $PIERRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "repo_name": "feature-fork",
    "base_repo": {
      "name": "template-repo",
      "ref": "develop",
      "auth": { "token": "'"$SOURCE_TOKEN"'" }
    }
  }'
```

`base_repo` takes `name`, `ref`, and `auth.token`. `ref` accepts a branch, a tag, or a commit SHA,
and defaults to the HEAD of the source. When you give no `auth.token`, the SDK signs a `git:read`
token for the source. The new default branch is the top-level `default_branch`, or else the default
branch name of the source. See [`repos.create`](https://code.storage/docs/api/repos/repo-create) for the full parameter list.

## Use cases

### Project templates

Create new projects from a starter template:

```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
async function createProjectFromTemplate(
  templateName: string,
  projectName: string,
  userId: string,
) {
  const project = await pierre.repos.create({
    repo_name: `${userId}/${projectName}`,
    base_repo: { name: templateName },
  });

  // Customize the new project
  await pierre.repos.commits.create({
    repo_name: project.repo_name,
    target_branch: 'main',
    commit_message: 'Initialize project',
    author: { name: 'System', email: 'system@example.com' },
    files: [{ path: 'README.md', content: `# ${projectName}\n\nCreated by ${userId}` }],
  });

  return project.repo_name;
}

// Usage
const project = await createProjectFromTemplate(
  'templates/react-starter',
  'my-new-app',
  'user-123',
);
```

```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
def create_project_from_template(
    template_name: str,
    project_name: str,
    user_id: str
) -> str:
    project = pierre.repos.create(
        repo_name=f"{user_id}/{project_name}",
        base_repo={"name": template_name},
    )

    # Customize the new project
    pierre.repos.commits.create(
        repo_name=project["repo_name"],
        target_branch="main",
        commit_message="Initialize project",
        author={"name": "System", "email": "system@example.com"},
        files=[
            {"path": "README.md", "content": f"# {project_name}\n\nCreated by {user_id}"},
        ],
    )

    return project["repo_name"]

# Usage
project = create_project_from_template(
    "templates/react-starter",
    "my-new-app",
    "user-123"
)
```

```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
import "strings"

createProjectFromTemplate := func(templateName, projectName, userID string) (string, error) {
	// Fork the template repo
	project, err := client.Repos.Create(ctx, pierre.ReposCreateParams{
		RepoName: pierre.String(userID + "/" + projectName),
		BaseRepo: pierre.Value(pierre.BaseRepo{Name: templateName}),
	})
	if err != nil {
		return "", err
	}

	// Customize the new project
	_, err = client.Repos.Commits.Create(ctx, pierre.ReposCommitsCreateParams{
		RepoName:      project.RepoName,
		TargetBranch:  "main",
		CommitMessage: "Initialize project",
		Author:        pierre.GitIdentity{Name: "System", Email: "system@example.com"},
		Files: []pierre.CommitFile{
			{Path: "README.md", Content: strings.NewReader("# " + projectName + "\n\nCreated by " + userID)},
		},
	})
	if err != nil {
		return "", err
	}

	return project.RepoName, nil
}

// Usage
project, err := createProjectFromTemplate("templates/react-starter", "my-new-app", "user-123")
if err != nil {
	return err
}
fmt.Println(project)
```

### Point-in-time snapshots

Capture a repository's state before you make risky changes:

```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
async function createSnapshot(repoName: string, label: string) {
  const commits = await pierre.repos.commits.list({ repo_name: repoName, limit: 1 });
  const headSha = commits.data[0].sha;

  const snapshot = await pierre.repos.create({
    repo_name: `snapshots/${repoName}/${label}`,
    base_repo: {
      name: repoName,
      ref: headSha,
    },
  });

  return snapshot.repo_name;
}

// Before a major refactor
const backup = await createSnapshot('my-project', 'pre-refactor-2024-01');
```

```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
def create_snapshot(repo_name: str, label: str) -> str:
    commits = pierre.repos.commits.list(repo_name=repo_name, limit=1)
    head_sha = commits.data[0]["sha"]

    snapshot = pierre.repos.create(
        repo_name=f"snapshots/{repo_name}/{label}",
        base_repo={
            "name": repo_name,
            "ref": head_sha,
        },
    )

    return snapshot["repo_name"]

# Before a major refactor
backup = create_snapshot("my-project", "pre-refactor-2024-01")
```

```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
createSnapshot := func(repoName, label string) (string, error) {
	// Capture the current HEAD SHA
	commits, err := client.Repos.Commits.List(ctx, pierre.ReposCommitsListParams{
		RepoName: repoName,
		Limit:    pierre.Int(1),
	})
	if err != nil {
		return "", err
	}
	headSHA := commits.Data[0].SHA

	// Fork at the captured commit
	snapshot, err := client.Repos.Create(ctx, pierre.ReposCreateParams{
		RepoName: pierre.String("snapshots/" + repoName + "/" + label),
		BaseRepo: pierre.Value(pierre.BaseRepo{
			Name: repoName,
			Ref:  pierre.String(headSHA),
		}),
	})
	if err != nil {
		return "", err
	}
	return snapshot.RepoName, nil
}

// Before a major refactor
backup, err := createSnapshot("my-project", "pre-refactor-2024-01")
if err != nil {
	return err
}
fmt.Println(backup)
```

## Fork or sync

| Kind | HTTP field | Source | Ongoing connection | Best for |
| - | - | - | - | - |
| Fork | `base_repo` | A Code Storage repository | No | Templates, snapshots, isolated copies |
| [Sync](https://code.storage/docs/repos/github-sync.md) | `upstream` | An external Git provider | Yes | Repositories that should stay mirrored |

Set at most one of `base_repo` and `upstream` in a request. A request with both returns HTTP `400`.

### Copy a GitHub repository

A fork needs a Code Storage source. To copy a public GitHub repository, create a repository with a
public GitHub `upstream` instead. It needs no GitHub App:

```json theme={"theme":{"light":"github-light","dark":"min-dark"}}
{
  "repo_name": "my-copy",
  "upstream": {
    "provider": "github",
    "owner": "octocat",
    "name": "hello-world",
    "access": "public"
  }
}
```

[Public GitHub mode](https://code.storage/docs/repos/github-sync.md#public-github-mode) runs one import and keeps no continuous
sync. The repository keeps its link to GitHub, so it can sync again on request.

## Limitations

* **Same organization**: You can only fork repositories within your own organization
* **No relationship tracking**: Forks are independent. Code Storage keeps no "parent" reference
  after creation. No route merges a fork back into its source
* **No upstream**: A fork records no upstream, so [`repos.upstream.pull`](https://code.storage/docs/api/repos/upstream-pull)
  on a fork returns HTTP `400` with `repository has no upstream configured`. To get later changes,
  add the source repository as a second Git remote. Fetch and merge the changes
* **One branch**: A fork has one branch, at the chosen commit, with the history of that commit. It
  has no other branches and no tags


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.