Fundamentals
Git, Phần 5: Rebase replay commit lên parent mới
Rebase replay commit lên parent mới, tạo id mới — giữ lịch sử viết lại ở local đến khi team đồng ý.
- Gieo
- Chăm lần cuối

Phần 2 merge hai tip bằng merge commit. Rebase là cách khác gộp nhánh: replay commit như thể chúng bắt đầu từ base mới hơn. Sau bài này bạn chờ commit id mới, biết rebase viết lại branch bạn chạy nó, và coi force-push là “thay tip remote người khác có thể đã clone” — không phải sửa bình thường.
Đây là Phần 5 trong loạt sáu phần. Phần 6 gắn chuyển ref với chính sách team. Ở đây câu hỏi cơ học: object nào xuất hiện khi commit được replay?
Nó là gì?
git rebase <upstream> tìm merge base giữa branch hiện tại và <upstream>, tạm gỡ commit chỉ thuộc branch bạn, dịch branch bắt đầu tại tip <upstream>, rồi cherry-pick từng commit đã gỡ theo thứ tự. Mỗi lần replay tạo commit object mới với hash mới, dù tree diff giống commit cũ. Commit cũ vẫn tồn tại local đến garbage collection, nhưng tên branch trượt dọc chuỗi mới.
Trong lúc replay Git có thể dừng vì conflict — cùng kiểu xung đột nội dung như merge. Sửa file, git add, rồi git rebase --continue. git rebase --abort trả branch về tip trước rebase.
Interactive rebase (git rebase -i) cho sắp xếp lại, squash hoặc bỏ commit trong danh sách replay. Cùng quy tắc: commit viết lại là id mới.
So với merge: merge giữ cả hai tip và thêm commit nối. Rebase vẽ đường thẳng như bạn branch muộn hơn. Không cái nào “đúng hơn”; chúng mã hóa hình lịch sử khác nhau. Phần 6 là nơi team chọn mặc định.
Khi nào dùng?
Rebase feature branch local lên main đã cập nhật khi muốn câu chuyện tuyến tính trước review, và không ai dựa việc vào tip feature cũ.
Dùng interactive rebase dọn commit WIP trước khi chia sẻ — squash fixup, bỏ thí nghiệm — vẫn khi branch còn của bạn.
Tránh rebase (hoặc force-push kết quả) khi người khác đã fetch commit đó và xây tiếp. Clone họ vẫn trỏ id cũ; branch viết lại của bạn là đồ thị khác. Phục hồi cần phối hợp, không phải cờ Git bí mật.
git pull --rebase áp cùng ý replay sau fetch: đặt commit local lên origin/main. Tiện; vẫn viết lại id commit local so với trạng thái trước pull.
Demo tương tác
Bắt đầu từ đồ thị chữ V: main và feature đều lớn sau Base. Bấm rebase lên main. Xem commit feature biến khỏi tip và node mới xếp thẳng trên main. Demo nên hiện nhãn id đổi dù thay đổi file trông giống.
Minh họa tương tác
Rebase replays each commit onto the new base. The old C3 is no longer on the branch; the replay gets a new hash.
Commit C1 is the base. C2 is main's tip. C3 is feature's commit off C1. Press git rebase main to hide C3, show replayed commit C3 prime with parent C2, and slide the feature label to C3 prime. A token moves along the new parent edge. Reset restores the diverged setup.
- C1 is shared history. main advanced to C2 while feature still sits on C3 off C1.
- The feature label and HEAD still point at the old commit C3.
- git rebase main hides C3 and creates C3 prime with parent C2.
- C3 prime is a different id even if the patch text matches. feature now names it.
- Reset returns to the diverged graph with C3 on feature.
main at C2 · feature at C3
Code
Repo throwaway, file không liên quan mỗi bên để replay sạch. Git 2.43.0.windows.1.
$ git init -b main
$ git commit -m "Base" # db7012d
$ git switch -c feature
$ git commit -m "Feature work" # 29682a2
$ git switch main
$ git commit -m "Main work" # cd9bbed
$ git log --oneline --graph --decorate --all
* 29682a2 (feature) Feature work
| * cd9bbed (HEAD -> main) Main work
|/
* db7012d Base
$ git switch feature
Switched to branch 'feature'
$ git rebase main
Rebasing (1/1)
Successfully rebased and updated refs/heads/feature.
$ git log --oneline --graph --decorate --all
* a501479 (HEAD -> feature) Feature work
* cd9bbed (main) Main work
* db7012d Base
Trước rebase tip feature là 29682a2. Sau rebase tip feature là a501479. Cùng message và hình tree cho commit đó, id khác. 29682a2 mồ côi trừ khi ref khác vẫn trỏ.
Nếu đã git push origin feature tại 29682a2, push thường a501479 bị từ chối. git push --force-with-lease (hoặc --force) bảo remote dịch origin/feature tới tip mới. Có thể vứt tip cũ khỏi remote chia sẻ — đồng đội cần reset hoặc rebase việc của họ. Chỉ dùng khi team chờ điều đó.
$ # conflict during rebase: fix files, then
$ git add .
$ git rebase --continue
$ # or abandon
$ git rebase --abort
Mã nguồn
Mã nguồn
Chỉ đọcTooling/Git/rebase-replay.sh
Chỉ đọc
# Feature branched from an older main tip
git switch -c feature
# Main moved forward while you worked
git switch main
git commit -m "Main advance"
# Replay your commit onto today's main (new commit id)
git switch feature
git rebase main
Ưu và nhược điểm
+ Ưu điểm
- Lịch sử tuyến tính dễ đọc trong git log --oneline khi review thích một commit một ý.
- Rebase lên main thử từng commit replay với tip main mới nhất, đôi khi bắt lỗi tích hợp sớm.
- Interactive rebase squash ồn trước khi chia sẻ không thêm merge node.
− Nhược điểm
- Mỗi commit replay là id mới, phá ai dựa tip cũ đến khi họ đối chiếu.
- Dừng conflict giữa rebase giống merge nhưng lệnh phục hồi khác (--continue versus merge --abort).
- Force-push sau rebase là sự kiện chính sách, không phải sở thích cá nhân, trên branch chia sẻ.
Mẹo
- 01Trước rebase, ghi hash tip cũ bằng git rev-parse feature; reflog cũng giữ nếu cần so.
- 02Chỉ rebase branch bạn sở hữu hoặc team cho phép viết lại rõ ràng.
- 03Ưu tiên git push --force-with-lease hơn --force; fail nếu origin dịch kể từ fetch cuối.
- 04Khi conflict, đọc git status; nó báo rebase tạm dừng và file nào cần stage.
- 05Nếu đã push commit trước rebase, báo đồng đội trước khi force-push branch đã replay.
- 06So merge và rebase bằng vẽ đồ thị: merge giữ ngã ba; rebase xóa ngã ba khỏi nhánh feature.
Series
- Phần 1: Git, Phần 1: Commit là snapshot, branch là nhãn dán
- Phần 2: Git, Phần 2: Merge nối hai nhánh snapshot
- Phần 3: Git, Phần 3: Restore, revert và reset đụng các lớp khác nhau
- Phần 4: Git, Phần 4: Remote là một repository khác
- Phần 5: Git, Phần 5: Rebase replay commit lên parent mới
- Phần 6: Git, Phần 6: Team thống nhất lịch sử thế nào
Tiếp theo
Bài kế trong đường đọc: Git, Phần 6: Team thống nhất lịch sử thế nào