DEV Community

BeanBean
BeanBean

Posted on Originally published at nextfuture.io.vn

Claude Code chạy song song: hai cách bạn mất file trong repo

Originally published on NextFuture

Bạn mở hai session Claude Code trên cùng một repo, hoặc tự sửa vài file trong lúc agent đang chạy. Nửa tiếng sau, commit của agent nuốt luôn phần việc của bạn — Git không cảnh báo một dòng nào. Dưới đây là hai cơ chế tạo ra lỗi đó và những lệnh thực sự chặn được.

Cơ chế 1: index là state dùng chung

Một bài phân tích mới tổng hợp năm case thực tế trong hơn một tuần (28/8–4/9/2026, trên hai repo: app DI² và repo blog của tác giả) khi các session Claude Code song song dùng chung một working tree. Ba trong năm case là lỗi của agent; case thứ ba chỉ lộ ra khi session bên cạnh thấy việc của mình biến mất.

Gốc lỗi: session thấy working tree sạch lúc khởi động nên mặc định mọi thay đổi mới đều là của nó. Git không ghi process nào tạo ra thay đổi, nên giả định đó không bao giờ bị phản bác.

Điểm quan trọng với dev: đổi git add -A thành add từng file không cứu được bạn. Theo bài viết, "git add chỉ kiểm soát cái được thêm vào index. git commit không kèm path sẽ commit toàn bộ index, kể cả những gì session khác đã đặt vào đó". Case 2 minh hoạ đúng điều này: session A đã stage năm thao tác git mv nhưng chưa commit; session B commit theo đúng bài học "chỉ add file của mình" — và vẫn cuốn trọn năm rename đó vào commit của nó.

Các lệnh tác giả xác nhận là trụ được: git commit --only, kiểm tra index như một bước riêng trước khi commit, và git show --stat ngay sau commit. Không lệnh nào bảo vệ bạn khi hai session sửa cùng một file — chỗ đó mỗi session cần một Git worktree riêng.

Cơ chế 2: routine cleanup xoá file bắt đầu bằng chữ số

Rủi ro thứ hai nằm trong chính Claude Code. Theo GitHub issue #34210, hàm nền concurrentSessionCleanup() chạy mỗi lần start session, mỗi lần autocompact và định kỳ sau đó, để dọn file lock .json chết trong ~/.claude/sessions/. Nó liệt kê mọi file trong thư mục, cắt đuôi .json nếu có, rồi đưa phần còn lại vào parseInt(name, 10) — không kiểm tra tên file có thực sự toàn chữ số hay không.

parseInt chỉ đọc các chữ số đứng đầu và bỏ im lặng phần còn lại, nên file tên 2026-01-01_notes.md được hiểu là PID 2026. Nếu không có process PID 2026 nào đang chạy — và platform không phải WSL, trường hợp code miễn trừ rõ ràng — routine gọi thẳng fs.unlink(). Không confirm, không warning, không log, không thùng rác để khôi phục.

Người báo lỗi (michaelk-q) tái hiện bằng ba bước: tạo một file tên bắt đầu bằng chữ số trong ~/.claude/sessions/, mở session Claude Code thứ hai, nhìn file đầu tiên biến mất. Issue nộp kèm sẵn fix một dòng: if (!/^\d+\.json$/.test(file)) continue;. Anthropic gắn nhãn bug, data-loss, high-priority — rồi đóng issue với zero comment.

Giữ đúng tỷ lệ: đây là một báo cáo đơn lẻ, không phải tỷ lệ đo được trên toàn install base; bài viết tự chấm severity mức trung bình (4.0) vì thiệt hại phụ thuộc thói quen để file cá nhân trong thư mục nội bộ của tool.

Checklist trước lần chạy song song tiếp theo

  • Mỗi session một git worktree riêng khi workflow cho phép.

  • Thay git add -A && git commit bằng git commit --only <paths>.

  • Chạy git show --stat sau mỗi commit của agent; thấy file lạ thì xử lý ngay.

  • Dọn ~/.claude/sessions/: file cá nhân có tên bắt đầu bằng chữ số là nhóm rủi ro cao nhất.

  • Với thao tác destructive, coi "cái này là của mình" là giả định cần kiểm chứng, không phải quan sát.

Theo dõi tiếp: issue #34210 đã đóng mà chưa có phản hồi maintainer, nên fix một dòng đó chưa chắc đã vào release nào. Tới lúc đó, hãy xem ~/.claude/sessions/ là vùng chỉ dành cho tool.


This article was originally published on NextFuture. Follow us for more fullstack & AI engineering content.

Top comments (0)