> ## 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.

# Import Namespace

> Push large repositories into Code Storage. Code Storage immediately moves them to cold storage to keep disk use low.

The `+import` namespace moves a whole repository into Code Storage in one push. To reach it, insert
`+import` before `.git` in the repository URL:

```bash theme={"theme":{"light":"github-light","dark":"min-dark"}}
git push https://t:JWT@your-org.code.storage/my-imported-repo+import.git --all
```

Code Storage fans the pack out to all storage nodes, then immediately enqueues a cold-storage job.
The repository moves to object storage before the next read, and it does not stay on hot disk.

Three rules apply to this URL:

* **It accepts a push only.** A `git clone` or a `git fetch` against the import URL returns an error
  that tells you to use the normal repository URL.
* **An import push creates normal branches.** Code Storage does not hide the refs. A normal
  `git clone` shows every branch you pushed.
* **A [synced repository](/docs/guides/github-sync) cannot use it.** Code Storage refuses an import push
  to a repository that has a sync base, so an imported ref never reaches a connected GitHub
  repository.

Code Storage stores refs from the Import Namespace and
[Ephemeral Namespace](/docs/guides/ephemeral-branches) differently. A normal `git clone` excludes an
ephemeral ref but includes an imported ref.

Use `+import` when:

* You must import many repositories at once
* You will not use the repositories immediately
* You must keep disk use low during the import

<Note>
  Code Storage enqueues cold archival on a push only. Use the normal repository URL to clone, fetch,
  or pull. Code Storage thaws an archived repository before the read.
</Note>

## Setup

Add a named remote when you import more than one branch:

```bash theme={"theme":{"light":"github-light","dark":"min-dark"}}
git remote add import https://t:JWT@your-org.code.storage/repo-id+import.git
```

This remote behaves like any other HTTPS remote.

## Quick start

Create the repository first, then push to the import remote:

```bash theme={"theme":{"light":"github-light","dark":"min-dark"}}
# 1. Create the target repository. The repo claim in the token supplies its name.
curl "$CODE_STORAGE_BASE_URL/repos" \
  -X POST \
  -H "Authorization: Bearer $CODE_STORAGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"default_branch": "main"}'

# 2. Add the import remote (replace org and JWT)
git remote add import https://t:eyJhbGciOiJSUzI1NiI...@your-org.code.storage/my-imported-repo+import.git

# 3. Push. Code Storage starts cold archival after the push completes.
git push import main
```

After the push succeeds, Code Storage schedules the repository for cold storage. It first sends the
data to all storage nodes. Then it sends the data to object storage.

## SDK workflow

Generate a JWT-authenticated import URL with the SDK. Use the URL with standard Git commands:

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

  const store = new GitStorage({
    name: 'your-org',
    key: process.env.PIERRE_PRIVATE_KEY,
  });

  // Create the repository
  const repo = await store.createRepo({ id: 'my-imported-repo' });

  // Generate a write-capable URL for the import remote
  const importUrl = await repo.getImportRemoteURL({
    permissions: ['git:read', 'git:write'],
    ttl: 3600,
  });

  // Use in a shell command or CI step
  console.log(`git remote add import ${importUrl}`);
  console.log(`git push import main`);
  ```

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

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

  # Create the repository
  repo = await storage.create_repo(id="my-imported-repo")

  # Generate a write-capable URL for the import remote
  import_url = await repo.get_import_remote_url(
      permissions=["git:read", "git:write"],
      ttl=3600,
  )

  print(f"git remote add import {import_url}")
  print("git push import main")
  ```

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

  // Create the repository
  repo, err := client.CreateRepo(ctx, storage.CreateRepoOptions{
  	ID: "my-imported-repo",
  })

  // Generate a write-capable URL for the import remote
  importURL, err := repo.ImportRemoteURL(ctx, storage.RemoteURLOptions{
  	Permissions: []storage.Permission{
  		storage.PermissionGitRead,
  		storage.PermissionGitWrite,
  	},
  	TTL: time.Hour,
  })

  fmt.Printf("git remote add import %s\n", importURL)
  fmt.Println("git push import main")
  ```
</CodeGroup>

## Bulk import

To import many repositories, read each item in your source list. Push each repository through the
import remote:

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

  const store = new GitStorage({
    name: 'your-org',
    key: process.env.PIERRE_PRIVATE_KEY,
  });

  async function importRepo(localPath: string, repoId: string) {
    const repo = await store.createRepo({ id: repoId });

    const importUrl = await repo.getImportRemoteURL({
      permissions: ['git:read', 'git:write'],
      ttl: 3600,
    });

    execSync(`git -C ${localPath} remote add cs-import ${importUrl}`);
    execSync(`git -C ${localPath} push cs-import --all`);
    execSync(`git -C ${localPath} push cs-import --tags`);
  }

  const repos = [
    { path: '/repos/service-a', id: 'service-a' },
    { path: '/repos/service-b', id: 'service-b' },
    { path: '/repos/service-c', id: 'service-c' },
  ];

  for (const r of repos) {
    await importRepo(r.path, r.id);
    console.log(`imported ${r.id}`);
  }
  ```

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

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

  async def import_repo(local_path: str, repo_id: str):
      repo = await storage.create_repo(id=repo_id)

      import_url = await repo.get_import_remote_url(
          permissions=["git:read", "git:write"],
          ttl=3600,
      )

      subprocess.run(["git", "-C", local_path, "remote", "add", "cs-import", import_url], check=True)
      subprocess.run(["git", "-C", local_path, "push", "cs-import", "--all"], check=True)
      subprocess.run(["git", "-C", local_path, "push", "cs-import", "--tags"], check=True)

  repos = [
      {"path": "/repos/service-a", "id": "service-a"},
      {"path": "/repos/service-b", "id": "service-b"},
      {"path": "/repos/service-c", "id": "service-c"},
  ]

  for r in repos:
      await import_repo(r["path"], r["id"])
      print(f"imported {r['id']}")
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  ctx := context.Background()
  client, err := storage.NewClient(storage.Options{
  	Name: "your-org",
  	Key:  os.Getenv("PIERRE_PRIVATE_KEY"),
  })

  importRepo := func(localPath string, repoID string) error {
  	repo, err := client.CreateRepo(ctx, storage.CreateRepoOptions{ID: repoID})
  	if err != nil {
  		return err
  	}

  	importURL, err := repo.ImportRemoteURL(ctx, storage.RemoteURLOptions{
  		Permissions: []storage.Permission{
  			storage.PermissionGitRead,
  			storage.PermissionGitWrite,
  		},
  		TTL: time.Hour,
  	})
  	if err != nil {
  		return err
  	}

  	commands := [][]string{
  		{"git", "-C", localPath, "remote", "add", "cs-import", importURL},
  		{"git", "-C", localPath, "push", "cs-import", "--all"},
  		{"git", "-C", localPath, "push", "cs-import", "--tags"},
  	}
  	for _, command := range commands {
  		if err := exec.Command(command[0], command[1:]...).Run(); err != nil {
  			return err
  		}
  	}

  	return nil
  }

  repos := []struct {
  	Path string
  	ID   string
  }{
  	{Path: "/repos/service-a", ID: "service-a"},
  	{Path: "/repos/service-b", ID: "service-b"},
  	{Path: "/repos/service-c", ID: "service-c"},
  }

  for _, item := range repos {
  	if err := importRepo(item.Path, item.ID); err != nil {
  		panic(err)
  	}
  	fmt.Printf("imported %s\n", item.ID)
  }
  ```
</CodeGroup>

## How it works

When you push to a `+import` remote:

1. The gateway receives the pack
2. The gateway unpacks the pack
3. Code Storage sends the objects to all three storage nodes, as it does for a normal push
4. Code Storage immediately enqueues a cold-storage job
5. Code Storage sends the repository to object storage (S3)
6. Code Storage removes the repository from hot disk

When you later clone or fetch from the repository:

* Code Storage detects that the repository is cold and thaws it automatically
* The thaw time depends on the repository size. The client receives a message to retry until the
  thaw is complete

## URL format

The import remote URL follows the same pattern as other namespaced remotes:

```
https://t:{jwt}@{org}.code.storage/{repo-id}+import.git
```

## Caveats

* **Still fans out first**: Code Storage copies the push to all storage nodes before cold archival.
  You cannot skip replication.
* **Reads trigger thaw**: A later clone or fetch thaws the repository. The first read takes more
  time.
* **Push only**: The import URL rejects read commands with this error:
  `reads are disabled for +import remotes; use the repository remote for clone/fetch`. Use the
  normal URL to read the repository.
