Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ batch document.
| restore | partial | `--source`, `--staged`, `--worktree`, path restore, `--pathspec-from-file`/`--pathspec-file-nul`, `--overlay`/`--no-overlay` (real toggle, last wins — overlay only creates/updates source paths and never removes tracked paths absent from the source; default no-overlay removes them), and `--no-progress` (accepted no-op — Libra's restore renders no progress meter) are supported; conflict-stage restore `--ours`/`-2` and `--theirs`/`-3` write the chosen merge stage to the working tree only (index left unmerged), a plain restore over an unmerged path is refused (`LBR-CONFLICT-001`, exit 128), and `--ignore-unmerged` skips unmerged paths; a modify/delete conflict (the requested side deleted the file — its stage absent) removes the working-tree file and exits 0 in the default no-overlay mode (restoring a deletion means deleting; matches `git restore`), while `--overlay` instead errors `does not have our/their version` (exit 128); mid-rebase `--ours`/`--theirs` follow Git's swap (stages read verbatim, so `--ours` = the branch rebased onto / new base, `--theirs` = the commit being replayed), whereas merge/cherry-pick keep ours = HEAD / theirs = incoming; `--ours`/`--theirs` operate only on unmerged paths — a non-conflicted pathspec is skipped (or `PathspecNotMatched` when every pathspec is non-conflicted), and Libra intentionally does not fall through to Git's stage-0 (index) restore for such paths so a dirty file is never silently reverted; `--merge` (and `--conflict=merge|diff3`) rewrites the working tree for unmerged paths with the conflict markers rebuilt from the index stages — Libra's whole-file `ours`/`theirs` markers (generic `ours`/`theirs` labels — `diff3` also emits the base block; `zdiff3` is not supported; unlike `libra merge`/`cherry-pick`, which now write line-level markers, restore's index-stage rebuild stays whole-file), not Git's line-level 3-way; only the `--progress` meter is not exposed |
| status | supported | common Git status surface plus `--porcelain` v1/v2, `-u`/`--untracked-files` (`no`/`normal`/`all`; bare = `all`, short attached values `-uno`/`-uall`/`-unormal`), `--short`, `--long` (explicit default; conflicts with `--short`/`--porcelain`), `--branch`/`-b`, `-z` NUL-terminated output, `--find-renames`, `--renames`/`--no-renames` (toggle rename detection; `--no-renames` wins), `--column`/`--no-column` (toggle column layout; `--no-column` countermands `--column`, last wins, and status is not columnar by default so `--no-column` alone is a no-op), and `--ahead-behind`/`--no-ahead-behind` supported; Libra dirty-cache extensions (lore.md 1.1, mutually exclusive, also conflict with `--porcelain`/`--short`/`--ignored`): `--scan` (normal full status + atomic cache rebuild, TOCTOU-guarded on the index fingerprint + HEAD, scan lock with stale-steal), `--cached` (consume the snapshot — O(dirty), no worktree walk, no HEAD-tree loads; any freshness doubt degrades to the full status with a hint; snapshot semantics: post-scan worktree-only edits are invisible until rescanned or marked via `libra dirty`; unrelated to Git's `--cached`), `--check-dirty` (re-verify only the cached set, pruning rows proven clean); default status JSON gains no keys — the modes add `mode`/`freshness`/`cache_state`/`cached_paths`(+`checked_paths`/`stale_paths`) |
| clean | partial | `-n`, `-f`, `-d`, `-x`, `-X`, `-e`/`--exclude`, and `<pathspec>...` positional filtering are supported; `-i` is intentionally different/not exposed |
| stash | partial | `push` / `pop` / `list` / `apply` / `drop` / `show` / `branch` / `clear` supported; `stash show` supports the file-level summary (`--name-only` / `--name-status`) and `-p`/`--patch` (unified diff of the stashed changes, via the shared diff engine). `stash push` supports `-m`, `-u` / `--include-untracked` (with `--no-include-untracked` to countermand it; last one wins, and untracked files are excluded by default so `--no-include-untracked` alone is a no-op), `-a` / `--all`, `-k`/`--keep-index`, and `-- <pathspec>` (stash only the changes to the named paths/dirs — file or directory, `.` selects the whole tree — leaving the rest of the working tree intact; a pathspec matching nothing tracked is `LBR-CLI-003`; `-u`/`-a`/`-k` cannot be combined with a pathspec — `LBR-CLI-002`); included untracked/ignored files are stored in a third stash parent and restored by `apply` / `pop`. `apply` / `pop` perform the three-way restore against the CURRENT working tree (not HEAD), so unrelated uncommitted changes — including the paths a pathspec push left behind — are preserved. Deferred: `pop/apply --index`, `create`, and `store` (see [docs/development/commands/_compatibility.md#d8-stash-create](docs/development/commands/_compatibility.md#d8-stash-create) and [#d9-stash-store](docs/development/commands/_compatibility.md#d9-stash-store)) |
| stash | partial | `push` / `pop` / `list` / `apply` / `drop` / `show` / `branch` / `clear` supported; `stash show` supports the file-level summary (`--name-only` / `--name-status`) and `-p`/`--patch` (unified diff of the stashed changes, via the shared diff engine). `stash push` supports `-m`, `-u` / `--include-untracked` (with `--no-include-untracked` to countermand it; last one wins, and untracked files are excluded by default so `--no-include-untracked` alone is a no-op), `-a` / `--all`, `-k`/`--keep-index`, and `-- <pathspec>` (stash only the changes to the named paths/dirs — file or directory, `.` selects the whole tree — leaving the rest of the working tree intact; a pathspec matching nothing tracked is `LBR-CLI-003`; `-u`/`-a`/`-k` cannot be combined with a pathspec — `LBR-CLI-002`); included untracked/ignored files are stored in a third stash parent and restored by `apply` / `pop`. `apply` / `pop` perform the three-way restore against the CURRENT working tree (not HEAD), so unrelated uncommitted changes — including the paths a pathspec push left behind — are preserved; by default they leave the current index intact, so restored tracked changes appear as unstaged working-tree changes. Deferred: `pop/apply --index`, `create`, and `store` (see [docs/development/commands/_compatibility.md#d8-stash-create](docs/development/commands/_compatibility.md#d8-stash-create) and [#d9-stash-store](docs/development/commands/_compatibility.md#d9-stash-store)) |
| lfs | partial | built-in Libra LFS command; uses `.libra_attributes`, not Git LFS filters/hooks (see [docs/development/commands/_compatibility.md#d5-git-lfs-gitattributes-filter--hooks-bridge](docs/development/commands/_compatibility.md#d5-git-lfs-gitattributes-filter--hooks-bridge)); `lfs.lockEnforce` (lore.md 2.8, Libra extension — git-lfs has no equivalent config): opt-in `off`(default)|`warn`|`block` gate on `add`/`commit` against locks held by OTHERS (server-side ours/theirs split via `POST locks/verify`; holding the lock is permission), covering staged new+modified+DELETED paths (deletions never reach the push-time OID check — this gate is their only guard); zero overhead when unset or no LFS-tracked path is staged; warn prints per-lock stderr warnings + records the warning (exit-code-on-warning contract) and proceeds; block aborts BEFORE any blob/index write on `add` (atomic; after `-a` auto-staging on `commit`, matching pre-commit-hook semantics) with LBR-CONFLICT-002 + hints; matrix: 404=no locking API→no-op (mirrors push), 403→warn proceeds/block fails AuthPermissionDenied, transport/5xx→warn proceeds/block FAILS CLOSED (LBR-NET-001 — an opted-in hard guarantee must not silently degrade; escape hatches named), explicit offline intent→skip+recorded warning BOTH modes (deletion residual documented), detached HEAD→skip+warning, no remote at all→structural no-op, fresh no-upstream branch does NOT skip (falls back to remote.origin.url); invalid value=hard usage error (never silently off); `--dry-run`/`--porcelain` previews never touch the network; push-time verification stays the authoritative backstop (TOCTOU acknowledged) |
| ls-files | partial | default cached listing plus `--cached`/`-c`, `--deleted`/`-d`, `--modified`/`-m`, `--stage` / `-s`, `--abbrev[=<n>]` (fixed-length object-name abbreviation in `-s`/`--stage` output; bare = 7), `--others`/`-o`, `--exclude-standard`, `-i`/`--ignored` (list only the ignored set — `-i -o` ignored untracked files, `-i -c` tracked files matching an exclude pattern; requires `-o`/`-c` and an exclude source — `--exclude-standard` or an explicit `-x`/`-X` pattern — else exit 128, matching Git), `<pathspec>...`, `--error-unmatch`, `-z` text output, status tags `-t` (H/R/C/?/M), unmerged-only `-u`/`--unmerged`, `--full-name` (accepted no-op; Libra always prints repo-root-relative paths), explicit exclude sources `-x`/`--exclude <pattern>` and `-X`/`--exclude-from <file>` (gitignore syntax; filter the `--others` listing and count toward the `-i` ignored set), `--eol` (prefix each cached entry with `i/<eol> w/<eol> attr/<attr>` line-ending info — `lf`/`crlf`/`mixed`/`none`/`-text` for the index blob and the worktree file, byte-compatible with `git ls-files --eol`; `attr/` is always empty as Libra has no `.gitattributes`), and JSON/machine output supported; pathspecs resolve from the caller's CWD and pathspecs outside the repo are rejected; resolve-undo and sparse-checkout integration are not exposed |
| log | partial | common Git log surface plus the named `--pretty`/`--format` presets `oneline`/`short`/`full`/`fuller`/`reference`/`raw` (`medium` is the default), `--range` revision expressions, `--all`, `--reverse`, `--author-date-order` (sort by author date instead of committer date; timestamp-only, no topological constraint), `--date-order` (accepted no-op; selects the default committer-date order, conflicts with `--author-date-order`), `--no-expand-tabs` (accepted no-op; Libra never expands tabs in commit messages), `--no-notes` (accepted no-op; Libra's log never displays notes inline), `--no-mailmap` (accepted no-op; Libra's log never applies a mailmap), `--no-show-signature` (accepted no-op; Libra's log never displays commit signatures inline), `--follow`, `-L`, `--parents`/`--children` (append parent / in-range child ids after each commit hash), `-i`/`--regexp-ignore-case` + `--invert-grep` (case-insensitive / inverted `--grep`), `--patch-with-stat` (diffstat block then patch, Git's synonym for `-p --stat`; an explicit `-p --stat` likewise shows both), and positional revision-range syntax (`log A..B` / `A...B` / `^A` / a bare `<rev>`, followed by optional pathspecs; a bare name that is both a revision and a path is rejected as ambiguous — use `--range`) supported; the `--expand-tabs[=<n>]` tab expansion, `--show-signature` signature display, and exact function-range tracking remain partial; Libra extensions (lore.md 1.9): `--trailer <KEY[=VALUE]>` (repeatable AND filter over the commit's Git-qualifying trailer block — key ASCII case-insensitive, `=VALUE` exact on the unfolded value; Git has no such flag, nearest is a fragile `--grep='^Key: '`) and `--only-trailers` (show only each commit's trailer block, key-filtered when combined with `--trailer`; nearest Git equivalent `--pretty='%(trailers)'`, whose placeholder is not yet implemented); `--json log` gains an additive `trailers: [{key,value}]` field (empty array when none; `body` unchanged) |
Expand Down
10 changes: 7 additions & 3 deletions docs/commands/stash.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ libra stash clear [--force]

## Description

`libra stash` saves your local modifications to a new stash entry and reverts the working directory to match HEAD. By default, `stash push` records tracked index/worktree changes and leaves untracked files alone. Use `-u` / `--include-untracked` to include visible untracked files, or `-a` / `--all` to include ignored files too. Pass `-- <pathspec>...` (file or directory paths; `.` selects the whole tree) to stash only the changes to those paths, leaving every other change in the working tree. A pathspec cannot be combined with `-u`/`-a`/`-k`. The modifications can be restored later with `libra stash pop` or `libra stash apply`, which replay the stash onto the CURRENT working tree (not HEAD) — so any unrelated uncommitted change you made in the meantime, including the paths a pathspec push left behind, is preserved. If `stash push` is run on a clean working tree and no requested untracked files exist, it exits successfully as a no-op and reports that there are no local changes to save.
`libra stash` saves your local modifications to a new stash entry and reverts the working directory to match HEAD. By default, `stash push` records tracked index/worktree changes and leaves untracked files alone. Use `-u` / `--include-untracked` to include visible untracked files, or `-a` / `--all` to include ignored files too. Pass `-- <pathspec>...` (file or directory paths; `.` selects the whole tree) to stash only the changes to those paths, leaving every other change in the working tree. A pathspec cannot be combined with `-u`/`-a`/`-k`. The modifications can be restored later with `libra stash pop` or `libra stash apply`, which replay the stash onto the CURRENT working tree (not HEAD) — so any unrelated uncommitted change you made in the meantime, including the paths a pathspec push left behind, is preserved. Default `apply` / `pop` leave the current index intact, so restored tracked changes appear as unstaged working-tree changes; Git's `--index` restore mode is not exposed yet. If `stash push` is run on a clean working tree and no requested untracked files exist, it exits successfully as a no-op and reports that there are no local changes to save.

Stash entries are stored as specially-structured commit objects under `.libra/refs/stash`, with a flat-file list tracking the stash stack. Each stash captures both the index state and worktree state at the time of creation.

Expand Down Expand Up @@ -60,7 +60,7 @@ libra stash push -- src/main.rs docs/

#### `pop`

Apply the top stash entry and remove it from the stash list. Equivalent to `apply` followed by `drop`.
Apply the top stash entry and remove it from the stash list. Equivalent to `apply` followed by `drop`. By default, restored tracked changes are written to the working tree only and are not staged.

| Argument | Description |
|----------|-------------|
Expand All @@ -84,7 +84,7 @@ libra stash list

#### `apply`

Apply a stash entry without removing it from the stash list. Useful when you want to apply the same stash to multiple branches.
Apply a stash entry without removing it from the stash list. Useful when you want to apply the same stash to multiple branches. By default, restored tracked changes are written to the working tree only and are not staged.

| Argument | Description |
|----------|-------------|
Expand Down Expand Up @@ -380,6 +380,10 @@ The structured envelope always emits the full `files` list. The `--name-only` /

`stash push -u` and `stash push -a` use a third stash parent for the untracked/all snapshot, matching Git's object topology. `stash apply` and `stash pop` restore those files as untracked worktree files. If a local file would be overwritten during restore, the apply/pop operation fails and keeps the stash entry intact.

### How `pop` / `apply` treat the index

Default `stash pop` and `stash apply` restore tracked content to the working tree while leaving the current index unchanged. A change that was staged when stashed comes back as an unstaged working-tree edit unless a future `--index` mode is added. This matches Git's default `stash pop` / `stash apply` behavior and prevents a later `libra commit` from committing restored stash content before the user runs `libra add`.

### How `--keep-index` works

`stash push --keep-index` stores the same stash metadata as a normal push, then writes the saved index back and restores the worktree to the index state. For a mixed file with both staged and unstaged edits, the staged content remains in the index and worktree, while the unstaged delta is saved in the stash.
Expand Down
2 changes: 1 addition & 1 deletion docs/development/commands/merge.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ flowchart TD

### --autostash(lore.md 1.8)

- 合并属主状态机(非 pull 的 push/pop 包裹):`stash::push_held_stash`(tracked-only,写 stash 提交对象但**不入 refs/stash**)→ sidecar `merge-autostash.json`(原子+fsync,MERGE_AUTOSTASH 模拟;held 提交仅由此文件可达——**未来 GC/prune 必须视其为根**)→ 硬重置 → 合并。统一 finalize(每个动作后运行):无 merge-state → 回贴(干净→删 sidecar;冲突→`store_stash_commit` 提升入 stash list + 通知,回贴 all-or-nothing——`apply_stash_commit` 在写任何工作树/索引前失败,并新增纯添加 vs 未跟踪文件碰撞守卫;其它错误→警告+保留 sidecar,合并结果不变);有 merge-state → held。`--restart` 以 `preserve_held_autostash` 跳过陈旧回收(否则 held stash 会被误降级)。陈旧 sidecar(崩溃残留)在下次合并启动时提升入 stash list(警告注明可能与已回贴内容重复)。配置 `merge.autostash` git-bool,非法值硬错误;`--dry-run` 下配置启用被静默抑制(dry-run 零写入契约)。已知限制(文档化):与 stash pop 同源的 index/worktree 分离不保真(staged-only 且工作树回退的内容会丢——继承 stash 行为);`libra commit` 不终结合并(Libra 需 `merge --continue`,故 sidecar 不会被普通 commit 触发回贴);并发合并进程间 sidecar 无锁(与 merge-state.json 同级暴露)。
- 合并属主状态机(非 pull 的 push/pop 包裹):`stash::push_held_stash`(tracked-only,写 stash 提交对象但**不入 refs/stash**)→ sidecar `merge-autostash.json`(原子+fsync,MERGE_AUTOSTASH 模拟;held 提交仅由此文件可达——**未来 GC/prune 必须视其为根**)→ 硬重置 → 合并。统一 finalize(每个动作后运行):无 merge-state → 回贴(干净→删 sidecar;冲突→`store_stash_commit` 提升入 stash list + 通知,回贴 all-or-nothing——`apply_stash_commit` 在写工作树前完成冲突/碰撞预检,且默认不重建 index,并新增纯添加 vs 未跟踪文件碰撞守卫;其它错误→警告+保留 sidecar,合并结果不变);有 merge-state → held。`--restart` 以 `preserve_held_autostash` 跳过陈旧回收(否则 held stash 会被误降级)。陈旧 sidecar(崩溃残留)在下次合并启动时提升入 stash list(警告注明可能与已回贴内容重复)。配置 `merge.autostash` git-bool,非法值硬错误;`--dry-run` 下配置启用被静默抑制(dry-run 零写入契约)。已知限制(文档化):与 stash pop 同源的 index/worktree 分离不保真(staged-only 或混合修改回贴后内容会回到工作树,但原 staged 状态不会保留,会表现为未暂存修改);`libra commit` 不终结合并(Libra 需 `merge --continue`,故 sidecar 不会被普通 commit 触发回贴);并发合并进程间 sidecar 无锁(与 merge-state.json 同级暴露)。

## 实现历史

Expand Down
Loading
Loading