# Migrating from Vault to Git

This tutorial walks you through migrating from a legacy Hex-Rays Vault repository to a new Git-based repository.

During the migration, you can choose to move all IDBs into a single repository, or migrate each IDB individually into its own repo.

{% hint style="info" %}
The legacy Vault backend is planned for deprecation in future releases.
{% endhint %}

## Prerequisites

* A Git client installed
* The **Vault to Git migration utility** — available from the [Download Center](https://my.hex-rays.com/dashboard/download-center/installers/release/sdk-and-utilities/9.4) under *SDK and Utilities*
* An active IDA Pro subscription with the Teams Add-on
* The `git-ida` clean filter on `PATH`. It ships with IDA Pro 9.4+; verify with:

  ```bash
  git-ida version
  ```
* Read access to your existing Vault server's data:
  * The vault SQLite database file (typically `hexvault.sqlite3`)
  * The vault file storage directory — the same path your Vault server was launched with (the value of its `-d` / `--vault-dir` flag)
* A destination Git server you can push to (GitHub, GitLab, Gitea, Bitbucket, etc.).

{% hint style="warning" %}
The migration replays Vault history from scratch, so each destination repository must be **empty** — no `README`, no `.gitignore`, no initial commit.
{% endhint %}

{% hint style="success" %}
If you don't already run a Git server on-premise, see [Recommended Git Server Setup](/9.4/add-ons/teams/admin/git-backend-on-premise-setup.md) for a lightweight Gitea-based option.
{% endhint %}

* A machine to run `vault2git` on with:
  * Enough free disk space for the output Git repository — plan for **roughly 2× the size of your vault data**
  * Enough RAM to comfortably hold the largest single IDB in memory while the `git-ida` clean filter processes it (16 GB is comfortable for typical vaults; very large vaults benefit from more)

## Before You Begin

1. **Stop active vault sessions.** No analyst should be checking files into the vault while the migration runs — any check-ins made during the run will not be captured.
2. **Decide on a migration layout.**

   | Layout                         | When to use                                                           |
   | ------------------------------ | --------------------------------------------------------------------- |
   | **All IDBs in one repository** | Smaller teams, related projects, simplest workflow                    |
   | **One IDB per repository**     | Independent projects with separate access controls or different teams |
3. **Prepare the destination Git server.** Create one empty repository (single-repo layout) or one empty repository per IDB (per-IDB layout).
4. **Verify SSH (or HTTPS) access** to the destination from the machine that will run `vault2git`:

   ```bash
   git ls-remote git@your-git-server:org/repo.git
   ```

## Migration Steps

The examples below assume you've set a few environment variables to keep commands short:

```bash
export VAULT_DIR=/path/to/vault/files
export VAULT_DB=/path/to/hexvault.sqlite3
export GIT_REPO=/path/to/output/git-repo
export REMOTE_URL=git@your-git-server:org/repo.git
```

### 1. Inspect the vault

List every IDB tracked in the vault. This is read-only — it makes no changes:

```bash
vault2git \
  --vault-dir "$VAULT_DIR" \
  --db        "$VAULT_DB" \
  --list-files
```

You should see entries like:

```
//project-a/binary1.i64
//project-a/binary2.i64
//project-b/firmware.i64
```

If the listing is empty or doesn't match what you expect, double-check `--vault-dir` and `--db` against your Vault server configuration before continuing.

### 2. Run the migration

Pick the option that matches the layout you decided on.

#### Option A — All IDBs into a single repository

```bash
vault2git \
  --vault-dir "$VAULT_DIR" \
  --db        "$VAULT_DB" \
  --git-repo  "$GIT_REPO" \
  --push      "$REMOTE_URL" \
  --log       migration.log
```

The utility will:

1. Initialize a fresh Git repository at `$GIT_REPO`.
2. Walk the Vault history chronologically.
3. Create one Git commit per Vault check-in, preserving the original author, timestamp, and commit message.
4. Push each commit to the remote as it completes (`--push`).

A full transcript is written to `migration.log` and also streamed to your terminal.

#### Option B — One IDB per repository

For this layout, run `vault2git --file <vault-path>` once per IDB, each into its own output directory and remote:

```bash
vault2git \
  --vault-dir "$VAULT_DIR" \
  --db        "$VAULT_DB" \
  --git-repo  /path/to/git-repos/project-a-binary1 \
  --file      "//project-a/binary1.i64" \
  --push      git@your-git-server:org/project-a-binary1.git \
  --log       project-a-binary1.log
```

Repeat for each IDB you saw in step 1. A small shell loop driven by the output of `--list-files` is the easiest way to script this.

### 3. Useful options

| Option       | Purpose                                                                                                                                                 |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--verbose`  | Print extra per-commit progress, including the file currently being reconstructed. Recommended for large vaults.                                        |
| `--log PATH` | Tee all output to a log file in addition to the terminal. Recommended for any non-trivial migration.                                                    |
| `--lfs`      | Initialize the output repository with [Git LFS](https://git-lfs.com). Use only if your Git server supports LFS and your team is set up to work with it. |
| `--resume`   | Resume an interrupted migration; see [Resuming a Migration](#resuming-a-migration) below.                                                               |

### 4. Verify the result

When `vault2git` reports `Migration complete`, sanity-check the new repository.

Count commits and inspect the most recent ones:

```bash
cd "$GIT_REPO"
git log --oneline | wc -l         # total commits
git log --oneline -10             # last 10 commits
```

Spot-check the history of an individual IDB:

```bash
git log -- path/to/binary.i64
```

Finally, clone the remote into a fresh directory and open the IDB in IDA Pro through the Teams Git integration to confirm everything works end-to-end.

### 5. Switch your team to the Git workflow

Once you're satisfied with the verification:

1. Decommission the old Vault server, or set it to read-only.
2. Have each analyst clone the new Git repository.
3. Open IDBs through the IDA Pro Teams Git integration. From this point on, all check-ins go to Git rather than the Vault.

## Resuming a Migration

Migrations of large vaults can take many hours. If `vault2git` is interrupted (system reboot, network drop, etc.), restart it with `--resume`:

```bash
vault2git \
  --vault-dir "$VAULT_DIR" \
  --db        "$VAULT_DB" \
  --git-repo  "$GIT_REPO" \
  --push      "$REMOTE_URL" \
  --log       migration.log \
  --resume
```

`--resume` reads the small state file `.git/vault2git-state` inside the output repository, skips every Vault commit that's already been replayed, and picks up exactly where it left off. Always prefer `--resume` over starting from scratch — unless you've upgraded the `vault2git` binary mid-migration, in which case start fresh.

## Troubleshooting

### **`Error: --vault-dir does not contain expected file directories.`**

The path passed to `--vault-dir` must be the same path your Vault server was launched with. The utility prints a hint listing candidate subdirectories — follow the hint.

### **`Error: git-ida is not installed or not in PATH.`**

The `git-ida` clean filter ships with IDA Pro 9.4+. Make sure the directory containing it is on your `PATH`, then verify with `git-ida version`.

### **`Error: remote is not reachable.`**

Verify access with `git ls-remote $REMOTE_URL`. Common causes: the SSH key on the migration machine isn't authorized on the destination server, or the destination repository doesn't exist yet.

### **Initial push rejected**

The destination repository must be empty. Re-create it without auto-initialization (no README, no `.gitignore`), then re-run with `--resume`.

### **`WARNING: removing stale index.lock (previous vault2git run was interrupted)`**

This is normal recovery output when restarting after a previous run was killed mid-stage. No action required.

### **A few files failed to stage**

If the migration log shows messages like `IDB file(s) failed to stage (clean filter error?)`, the corresponding `git add failed:` lines immediately above identify the affected files and the underlying error. Fix the cause (typically missing or corrupt vault blobs) and re-run with `--resume` to retry only the missing commits.

## Command Reference

| Argument          | Required                    | Description                                              |
| ----------------- | --------------------------- | -------------------------------------------------------- |
| `--vault-dir DIR` | yes                         | Vault file storage directory                             |
| `--db PATH`       | yes                         | Path to the Vault SQLite database                        |
| `--git-repo DIR`  | yes (unless `--list-files`) | Output Git repository directory                          |
| `--push URL`      | no                          | Push to a remote after each commit                       |
| `--file PATH`     | no                          | Migrate a single Vault path (e.g., `//project/file.i64`) |
| `--list-files`    | no                          | Print every Vault file path and exit                     |
| `--lfs`           | no                          | Initialize Git LFS in the output repository              |
| `--resume`        | no                          | Resume an interrupted migration                          |
| `--log PATH`      | no                          | Tee all output to a log file                             |
| `--verbose`       | no                          | Detailed progress output                                 |
| `--version`       | no                          | Print version and exit                                   |
| `--help`          | no                          | Print usage and exit                                     |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hex-rays.com/9.4/add-ons/teams/how-tos/migrating-from-vault-to-git.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
