Skip to content

feat(git): tag management with restore for deleted tags and branches - #354

Open
Wz58luck wants to merge 6 commits into
1lck:previewfrom
Wz58luck:feat/git-tag-management
Open

feat(git): tag management with restore for deleted tags and branches#354
Wz58luck wants to merge 6 commits into
1lck:previewfrom
Wz58luck:feat/git-tag-management

Conversation

@Wz58luck

@Wz58luck Wz58luck commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Closes #342

实现内容

共享命令(rust/lithe-core)

  • git.write 新增 createTag / deleteTag
    • createTagname + revision + 可选 message;非空 message 创建附注标签(git tag -a),否则轻量标签。创建前探测重名(A tag named '<name>' already exists)与目标可解析性(Could not resolve tag target '<rev>'),返回稳定 invalid_request 错误而非解析本地化 stderr。
    • deleteTag:删除前用 git cat-file 采集标签类型与原始 annotation(换行保真,剔除签名块),rev-parse <ref>{} 取剥离后的目标提交;成功响应携带结构化 tagDeletionname / deletedTarget / kind / message)。
  • deleteBranch 删除前解析分支指向的提交,成功后返回结构化 branchDeletionname / deletedTarget),供宿主提供"还原"入口;分支不存在时返回稳定错误 The branch '<name>' does not exist
  • 契约文档 rust-core-api.mdshared/fixtures/git/write.json 已同步更新,供第二个平台后续消费。

macOS

  • Git Log 提交行右键新增 "New Tag…":名称 + 可选 Message 对话框,本地校验行内即时提示(不发起请求),重名等服务端错误同样在对话框内展示、不关闭。
  • 引用列表 Tags 分组右键新增 "Delete Tag…":destructive 确认框,写明标签名与对协作者的影响。
  • 删除标签/分支成功后,Git Log 顶部显示 "Deleted tag/branch 'x' [Restore] [×]" 横幅(对齐 IDEA "已删除的分支 [还原]" 体验):还原用记录的目标提交重建,失败(如同名已被重建)保留记录可重试;关闭横幅或关闭项目后清除会话记录,不做跨会话持久化。
  • 还原不保留原 tagger/时间戳;删除分支使用 git branch -d(安全删除),不会出现未合并提交被舍弃的场景。

验证

076bc46ec936dc164dd394ef2422f7c9 0044f33e-2d1f-45bc-b90e-6307ef804eaf ad8a90c1-6bab-499f-b262-aaeccddb4ecd 969c2404-dba1-4006-91be-fa6e6e38a494

- Add git.createTag / git.deleteTag to lithe-core with pre-flight
  validation (duplicate name, unresolvable target, missing tag) and a
  structured tagDeletion record carrying the peeled target and original
  annotation for session-scoped restore
- Document both operations in rust-core-api.md and extend write.json
  fixtures for the second platform
- macOS: New Tag dialog on commit rows with inline validation, Delete
  Tag confirmation on tag references, and a deleted-tag banner with
  restore and dismiss
- deleteBranch resolves refs/heads/<name> before deleting and returns a
  structured branchDeletion record with the previous commit, so hosts can
  recreate the branch without re-querying
- Document the record in rust-core-api.md and extend write.json fixtures
- macOS: deleted-branch banner in the Git log with restore and dismiss,
  sharing the deleted-tag notice UI
…agement

# Conflicts:
#	macos/Tests/LitheGitModuleTests/GitModuleTests.swift
#	shared/contracts/rust-core-api.md
#	shared/fixtures/git/write.json
@Wz58luck
Wz58luck requested a review from 1lck as a code owner August 30, 2026 12:02

@1lck 1lck left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体实现方向是对的,CI 也已通过。下面几项建议在合并前修正;另外附了后续可维护性改进建议。

Comment thread rust/lithe-core/src/git/mod.rs Outdated
Comment thread rust/lithe-core/src/git/mod.rs Outdated
Comment thread macos/Sources/LitheGitModule/Application/GitFeatureModel.swift
Comment thread macos/Sources/LitheGitModule/Services/GitService.swift
@1lck

1lck commented Aug 31, 2026

Copy link
Copy Markdown
Owner

补充的维护性建议:

  • Swift tag 名称即时校验应与 Rust 的 refname 规则保持一致,尤其是逐级 ref component(例如 foo/.bar);最好由共享 fixture 驱动边界测试。
  • GitTagDeletion.kind 建议改为 GitTagKind 枚举,并在恢复时校验 kindmessage 的组合,避免异常数据静默改变 tag 类型。
  • 明确两个恢复横幅的产品策略(tag/branch 是否并存、何时覆盖),并为连续删除、失败后重试补状态测试。
  • probe 与 mutation 之间存在 TOCTOU 窗口;至少确保 mutation 失败时不写入恢复记录,必要时在删除前后校验 ref OID。

1lck and others added 2 commits August 31, 2026 11:40
限制标签目标为提交对象,并保留注释标签的原始换行。\n统一恢复状态策略、标签类型约束与跨端名称校验。\n\nRefs 1lck#354
@Wz58luck
Wz58luck requested a review from 1lck August 31, 2026 09:32
)
.with_details(peeled.output));
}
let mut result = execute_git(root, &["tag".into(), "-d".into(), name.clone()], None)?;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 这里的 peeled 是前面 probe 得到的目标 OID,但实际删除仍只按 tag 名称执行 git tag -d。如果另一个 Git 进程在两步之间 force-update 同名 tag,实际删除的是新目标,返回的 tagDeletion.deletedTarget 却仍是旧目标;Restore 会静默指回错误提交。下面的 ref_exists 只确认 ref 最终不存在,不能确认删除的是预期 OID。

建议获取未 peel 的 ref object OID,并使用带 expected-old-OID 的原子删除(例如 git update-ref --delete <ref> <expectedOid>);如果 OID 已变化,应返回明确失败且不生成恢复记录。delete_branch 的 probe-then-mutate 路径也需要同样的一致性保护。

if reference.kind == .tag {
Divider()

Button("Delete Tag…", role: .destructive) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 这里对所有 tag 引用都展示删除入口,但 Core 的 deleteTag 要求 refs/tags/<name>^{commit} 能够解析。合法的 tree/blob tag(例如 git tag tree-tag HEAD^{tree})会正常出现在 Tags 列表中,却在确认后必然失败。

如果 commit-only 是有意的恢复契约,建议在引用模型中带出是否可 peel 到 commit,并禁用或隐藏该操作、说明原因;否则需要扩展 deletion record 以支持非 commit target 的恢复。建议同时补一个 tree/blob tag 的回归测试,确保 UI 可用性和 Core 能力保持一致。

@1lck

1lck commented Aug 31, 2026

Copy link
Copy Markdown
Owner

@Wz58luck 我基于最新 head 63af49a 又检查了一遍,并补充了两条行级评论。

整体实现方向是合理的:#342 的提交行新建 tag、Tags 列表删除、确认界面和会话内恢复流程都已经接通;命令构造与结构化恢复记录放在 rust/lithe-core,共享契约、fixture、类型约束和针对性测试也同步完成,这部分设计值得保留。

目前仍有阻塞合并的问题:删除前 probe 到的 ref OID 与实际 mutation 没有原子一致性保护,并发更新同名 tag/branch 时可能删除新目标、却按旧目标生成恢复记录,最终 Restore 会静默恢复到错误提交。另外,合法的 tree/blob tag 当前会显示一个必然失败的删除操作,建议按行级评论统一 UI 能力与 Core contract。

验证方面,Rust Core、Swift bridge、Windows 边界检查以及 macOS Git 模块重点测试均通过。PR 的完整 Swift 稳定性任务仍失败在已有的 15 秒超时测试 bundledJdtlsRuntimeIgnoresProjectRunJDK();本地完整稳定性验证也只复现了既有的 installationCatalogUsesOfficialFallbacks() 超时,没有发现与本 PR Git 改动直接相关的失败。剩余测试缺口主要是并发 ref 变化、非 commit tag,以及 context-menu/sheet 的 UI 级覆盖。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants