> ## 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](/docs/repos/github-sync) and
[Generic Sync](/docs/repos/generic-sync).

## 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](/docs/repos/ephemeral-branches) 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](/docs/getting-started/quick-start).

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  import { GitStorage } from '@pierre/storage';

  const store = new GitStorage({
    name: process.env.PIERRE_ORG!,
    key: process.env.PIERRE_PRIVATE_KEY!,
  });

  // Fork at the latest commit (HEAD)
  const fork = await store.createRepo({
    id: 'my-fork',
    baseRepo: {
      id: 'template-repo', // Source repository ID
    },
  });

  // Fork at a specific branch
  const branchFork = await store.createRepo({
    id: 'feature-fork',
    baseRepo: {
      id: 'template-repo',
      ref: 'develop', // Fork from tip of 'develop' branch
    },
  });

  // Fork at a specific commit
  const commitFork = await store.createRepo({
    id: 'snapshot-fork',
    baseRepo: {
      id: 'template-repo',
      sha: 'abc123def456...', // Fork at exact commit
    },
  });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  import os
  from pierre_storage import GitStorage

  storage = GitStorage({
      "name": os.environ["PIERRE_ORG"],
      "key": os.environ["PIERRE_PRIVATE_KEY"],
  })

  # Fork at the latest commit (HEAD)
  fork = await storage.create_repo(
      id="my-fork",
      base_repo={
          "id": "template-repo",  # Source repository ID
      },
  )

  # Fork at a specific branch
  branch_fork = await storage.create_repo(
      id="feature-fork",
      base_repo={
          "id": "template-repo",
          "ref": "develop",  # Fork from tip of 'develop' branch
      },
  )

  # Fork at a specific commit
  commit_fork = await storage.create_repo(
      id="snapshot-fork",
      base_repo={
          "id": "template-repo",
          "sha": "abc123def456...",  # Fork at exact commit
      },
  )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  ctx := context.Background()

  // Fork at the latest commit (HEAD)
  fork, err := client.CreateRepo(ctx, storage.CreateRepoOptions{
  	ID: "my-fork",
  	BaseRepo: storage.ForkBaseRepo{
  		ID: "template-repo",
  	},
  })

  // Fork at a specific branch
  branchFork, err := client.CreateRepo(ctx, storage.CreateRepoOptions{
  	ID: "feature-fork",
  	BaseRepo: storage.ForkBaseRepo{
  		ID:  "template-repo",
  		Ref: "develop",
  	},
  })

  // Fork at a specific commit
  commitFork, err := client.CreateRepo(ctx, storage.CreateRepoOptions{
  	ID: "snapshot-fork",
  	BaseRepo: storage.ForkBaseRepo{
  		ID:  "template-repo",
  		SHA: "abc123def456...",
  	},
  })
  ```

  ```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/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"'" }
      }
    }'
  ```
</CodeGroup>

`baseRepo` takes `id`, `ref`, and `sha`. In the HTTP API, `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. The new default branch is the top-level `default_branch`, or else the default branch name of
the source. See [`createRepo()`](/docs/sdk/repos/repo-create) for the full parameter list and resolution
order. That page also explains which default branch the fork inherits.

## Use cases

### Project templates

Create new projects from a starter template:

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  async function createProjectFromTemplate(templateId: string, projectName: string, userId: string) {
    const project = await store.createRepo({
      id: `${userId}/${projectName}`,
      baseRepo: { id: templateId },
    });

    // Customize the new project
    await project
      .createCommit({
        targetBranch: 'main',
        commitMessage: 'Initialize project',
        author: { name: 'System', email: 'system@example.com' },
      })
      .addFileFromString('README.md', `# ${projectName}\n\nCreated by ${userId}`)
      .send();

    return project;
  }

  // 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"}}
  async def create_project_from_template(
      template_id: str,
      project_name: str,
      user_id: str
  ):
      project = await storage.create_repo(
          id=f"{user_id}/{project_name}",
          base_repo={"id": template_id},
      )

      # Customize the new project
      commit = project.create_commit(
          target_branch="main",
          commit_message="Initialize project",
          author={"name": "System", "email": "system@example.com"},
      )
      commit.add_file_from_string(
          "README.md",
          f"# {project_name}\n\nCreated by {user_id}"
      )
      await commit.send()

      return project

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

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  func createProjectFromTemplate(ctx context.Context, templateID, projectName, userID string) (*storage.Repo, error) {
  	// Fork the template repo
  	project, err := client.CreateRepo(ctx, storage.CreateRepoOptions{
  		ID:       userID + "/" + projectName,
  		BaseRepo: storage.ForkBaseRepo{ID: templateID},
  	})
  	if err != nil {
  		return nil, err
  	}

  	// Customize the new project
  	builder, err := project.CreateCommit(storage.CommitOptions{
  		TargetBranch:  "main",
  		CommitMessage: "Initialize project",
  		Author:        storage.CommitSignature{Name: "System", Email: "system@example.com"},
  	})
  	if err != nil {
  		return nil, err
  	}

  	_, err = builder.AddFileFromString(
  		"README.md",
  		"# "+projectName+"\n\nCreated by "+userID,
  		nil,
  	).Send(ctx)
  	if err != nil {
  		return nil, err
  	}

  	return project, nil
  }

  // Usage
  project, err := createProjectFromTemplate(context.Background(), "templates/react-starter", "my-new-app", "user-123")
  ```
</CodeGroup>

### Point-in-time snapshots

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

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  async function createSnapshot(repoId: string, label: string) {
    const source = await store.findOne({ id: repoId });
    const commits = await source.listCommits({ limit: 1 });
    const headSha = commits.commits[0].sha;

    const snapshot = await store.createRepo({
      id: `snapshots/${repoId}/${label}`,
      baseRepo: {
        id: repoId,
        sha: headSha,
      },
    });

    return snapshot;
  }

  // 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"}}
  async def create_snapshot(repo_id: str, label: str):
      source = await storage.find_one(id=repo_id)
      commits = await source.list_commits(limit=1)
      head_sha = commits["commits"][0]["sha"]

      snapshot = await storage.create_repo(
          id=f"snapshots/{repo_id}/{label}",
          base_repo={
              "id": repo_id,
              "sha": head_sha,
          },
      )

      return snapshot

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

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  func createSnapshot(ctx context.Context, repoID, label string) (*storage.Repo, error) {
  	// Capture the current HEAD SHA
  	source, err := client.FindOne(ctx, storage.FindOneOptions{ID: repoID})
  	if err != nil {
  		return nil, err
  	}
  	commits, err := source.ListCommits(ctx, storage.ListCommitsOptions{Limit: 1})
  	if err != nil {
  		return nil, err
  	}
  	headSHA := commits.Commits[0].SHA

  	// Fork at the captured commit
  	return client.CreateRepo(ctx, storage.CreateRepoOptions{
  		ID: "snapshots/" + repoID + "/" + label,
  		BaseRepo: storage.ForkBaseRepo{
  			ID:  repoID,
  			SHA: headSHA,
  		},
  	})
  }

  // Before a major refactor
  backup, err := createSnapshot(context.Background(), "my-project", "pre-refactor-2024-01")
  ```
</CodeGroup>

## Fork or sync

| `operation` | Source | Ongoing connection | Best for |
| - | - | - | - |
| `fork` | A Code Storage repository | No | Templates, snapshots, isolated copies |
| [`sync`](/docs/repos/github-sync) | An external Git provider | Yes | Repositories that should stay mirrored |

In the HTTP API, a fork is `base_repo` and a sync is `upstream`. Set at most one of them 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](/docs/repos/github-sync#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 [`pullUpstream()`](/docs/sdk/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
