Forking creates a new repository from an existing Code Storage repository at a specific point in time. Unlike other integrations (which maintain a live connection), forks are independent copies—changes to the original don’t affect the fork, and vice versa.
When to use forking
- Templates: Create new projects from a starter template
- Experimentation: Test changes without affecting the original repository
- Snapshots: Capture a repository’s state at a specific commit or branch
- Isolation: Give each user or agent their own copy to work with
Quick start
import { GitStorage } from '@pierre/storage';
const store = new GitStorage({
name: 'your-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
},
});
Fork options
The repository ID (name) to fork from
Branch or tag name to fork from. Forks the tip of this ref.
Exact commit SHA to fork at. Overrides ref if both are provided.
Resolution order:
- If
sha is provided, fork at that exact commit
- If
ref is provided, fork at the tip of that branch/tag
- Otherwise, fork at the source repository’s HEAD
Default branch behavior
The forked repository inherits the default branch from the source:
// Source repo has 'main' as default branch
const fork = await store.createRepo({
baseRepo: { id: 'source-repo' },
});
console.log(fork.defaultBranch); // 'main' (inherited)
// Override the default branch
const customFork = await store.createRepo({
baseRepo: { id: 'source-repo' },
defaultBranch: 'develop',
});
console.log(customFork.defaultBranch); // 'develop'
Use cases
Project templates
Create new projects from a starter template:
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'
);
Per-agent workspaces
Give each AI agent its own isolated copy:
async function createAgentWorkspace(
sourceRepo: string,
agentId: string,
taskId: string
) {
// Fork the source repo for this agent's task
const workspace = await store.createRepo({
id: `agents/${agentId}/${taskId}`,
baseRepo: { id: sourceRepo },
});
// Agent can now work independently
const url = await workspace.getRemoteURL({
permissions: ['git:read', 'git:write'],
ttl: 3600,
});
return { workspace, url };
}
Point-in-time snapshots
Capture a repository’s state before making risky changes:
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');
Forking vs Syncing
| Feature | Forking | Syncing |
|---|
| Source | Code Storage repositories | External Git providers |
| Connection | One-time copy | Continuous sync |
| Updates | Independent after fork | Automatically synced |
| Use case | Templates, snapshots, isolation | Mirror external repositories |
Use forking when you want an independent copy. Use syncing when you want to maintain a live connection to an external repository.
Limitations
- Same organization: You can only fork repositories within your own organization
- No relationship tracking: Forks are independent—there’s no “parent” reference after creation
- Full copy: Forks include all branches and history up to the fork point