Summary
Running libra init --from-git-repository . against an existing, relatively large Git repository was interrupted before conversion completed. The command left a valid-looking .libra directory behind, but no imported branch, remote, or commit history.
The resulting repository cannot retry conversion because a second invocation is rejected as re-initialization:
error: cannot use --from-git-repository on an already-initialized repository
libra status consequently reports No commits yet and lists the entire existing Git worktree as untracked. The original .git repository remains intact.
Environment and observed repository
- Libra:
0.22.19
- Platform: Linux
- Source Git HEAD:
1524ecab726a5eb663b8de09a37082ffa601d073 on main
- Source object count: 69,256
- Source pack size: approximately 422 MB
Git remains healthy and reports only the pre-existing worktree changes. Libra reports:
On branch main
No commits yet
Untracked files:
... the complete worktree ...
Additional Libra observations:
libra show-ref
error: no matching refs found
libra remote -v
(no output)
libra log --all --oneline -10
fatal: your current branch 'main' does not have any commits yet
The .libra database confirms this is an incomplete operation rather than a status-rendering issue:
reference contains only the initialized main HEAD plus empty internal intent/traces branches.
- There are no local/remote refs pointing at Git commits.
- There is no
remote.origin.url.
- The latest operation row is
command_name=init, status=running, with no end_ts.
- Its operation journal remains in phase
mutation.
- No
libra init or libra fetch process is still running.
There was no coredump and no kernel OOM record for the incident window, so the exact external termination mechanism cannot be proven. Ctrl-C, SIGTERM, an execution timeout, or an unlogged resource kill remain possible.
Reproduction
The state-machine failure can be reproduced independently of the exact termination mechanism:
-
Start with a non-empty Git repository, preferably one large enough that import takes noticeable time.
-
Run:
libra init --vault false --from-git-repository .
-
Interrupt or terminate the process while it is fetching/converting objects.
-
Run libra status, libra show-ref, and libra remote -v.
-
Retry the init command.
Actual result:
.libra survives as an initialized but history-less repository.
- The worktree is shown as entirely untracked.
- Retry is rejected because
.libra already exists.
- There is no supported resume or rollback path.
Expected result:
- Conversion should either complete fully, or leave the target in a state where conversion can be retried safely.
- An interrupted conversion should not be presented as a normal empty Libra repository.
- Stale
running operation state should be detected and surfaced with actionable recovery guidance.
Analysis
The conversion is not atomic across repository initialization and import. run_init_internal creates the repository layout/database and initial refs before calling convert_from_git_repository (src/command/init.rs, around the init_config / initialize_refs calls and later conversion call). Re-initialization then explicitly rejects --from-git-repository.
This ordering creates a permanent partial state whenever the process exits after .libra creation but before fetch/setup commits the imported refs and remote configuration. Normal Result error handling is insufficient for SIGINT/SIGTERM/OOM/process death.
There is also a likely large-repository reliability amplifier in the local Git transport. LocalClient::fetch_objects calls collect_git_repo_entries, which accumulates every reachable commit, tree, blob, and tag in a Vec<Entry>, then encode_pack_bytes builds the complete encoded pack in memory before returning it. For a 422 MB compressed Git pack, peak memory can be substantially larger than the source pack due to decoded object storage plus encoded buffers. This is an implementation risk inferred from the code; it is not proven as the termination cause in this incident.
Existing init_from_git_test coverage exercises successful conversion with small fixtures and ordinary validation failures, but does not cover interruption recovery or a realistically large packed source.
Suggested direction
- Stage conversion in a temporary Libra directory/database and publish it atomically only after fetch, refs, remote config, HEAD setup, and checkout succeed.
- Alternatively, persist an explicit conversion-in-progress marker and allow idempotent resume/retry when the repository contains no completed imported refs.
- On ordinary conversion errors, roll back all target state created by this invocation when the target did not previously contain a Libra repository.
- Detect stale
init operations and emit a recovery command instead of silently treating the repository as an empty initialized repo.
- Stream local Git object traversal/pack encoding, or otherwise bound peak memory, rather than retaining the full decoded object graph and encoded pack simultaneously.
- Add tests that terminate conversion after initialization and assert retry/recovery behavior, plus a packed large-object fixture or bounded-memory regression test.
Current manual recovery
The only practical recovery is to move/remove the incomplete .libra directory and rerun conversion while preserving .git:
mv .libra .libra.incomplete
libra init --vault false --from-git-repository .
This workaround is risky without careful guidance because .libra may contain user-owned data in other partial-state scenarios.
Summary
Running
libra init --from-git-repository .against an existing, relatively large Git repository was interrupted before conversion completed. The command left a valid-looking.libradirectory behind, but no imported branch, remote, or commit history.The resulting repository cannot retry conversion because a second invocation is rejected as re-initialization:
libra statusconsequently reportsNo commits yetand lists the entire existing Git worktree as untracked. The original.gitrepository remains intact.Environment and observed repository
0.22.191524ecab726a5eb663b8de09a37082ffa601d073onmainGit remains healthy and reports only the pre-existing worktree changes. Libra reports:
Additional Libra observations:
The
.libradatabase confirms this is an incomplete operation rather than a status-rendering issue:referencecontains only the initializedmainHEAD plus empty internalintent/tracesbranches.remote.origin.url.command_name=init,status=running, with noend_ts.mutation.libra initorlibra fetchprocess is still running.There was no coredump and no kernel OOM record for the incident window, so the exact external termination mechanism cannot be proven. Ctrl-C, SIGTERM, an execution timeout, or an unlogged resource kill remain possible.
Reproduction
The state-machine failure can be reproduced independently of the exact termination mechanism:
Start with a non-empty Git repository, preferably one large enough that import takes noticeable time.
Run:
Interrupt or terminate the process while it is fetching/converting objects.
Run
libra status,libra show-ref, andlibra remote -v.Retry the init command.
Actual result:
.librasurvives as an initialized but history-less repository..libraalready exists.Expected result:
runningoperation state should be detected and surfaced with actionable recovery guidance.Analysis
The conversion is not atomic across repository initialization and import.
run_init_internalcreates the repository layout/database and initial refs before callingconvert_from_git_repository(src/command/init.rs, around theinit_config/initialize_refscalls and later conversion call). Re-initialization then explicitly rejects--from-git-repository.This ordering creates a permanent partial state whenever the process exits after
.libracreation but before fetch/setup commits the imported refs and remote configuration. NormalResulterror handling is insufficient for SIGINT/SIGTERM/OOM/process death.There is also a likely large-repository reliability amplifier in the local Git transport.
LocalClient::fetch_objectscallscollect_git_repo_entries, which accumulates every reachable commit, tree, blob, and tag in aVec<Entry>, thenencode_pack_bytesbuilds the complete encoded pack in memory before returning it. For a 422 MB compressed Git pack, peak memory can be substantially larger than the source pack due to decoded object storage plus encoded buffers. This is an implementation risk inferred from the code; it is not proven as the termination cause in this incident.Existing
init_from_git_testcoverage exercises successful conversion with small fixtures and ordinary validation failures, but does not cover interruption recovery or a realistically large packed source.Suggested direction
initoperations and emit a recovery command instead of silently treating the repository as an empty initialized repo.Current manual recovery
The only practical recovery is to move/remove the incomplete
.libradirectory and rerun conversion while preserving.git:This workaround is risky without careful guidance because
.libramay contain user-owned data in other partial-state scenarios.