Sổ tay kỹ thuật

Git rebase workflow – interactive, fixup, force-with-lease

how-to#git· cập nhật 2026-11-06

Dùng khi cần làm gọn lịch sử feature branch trước khi mở hoặc cập nhật PR, gồm rebase lên main, gộp commit fixup, giải conflict và push an toàn.

Sửa trang này
Mục lục

Tóm tắt: git fetch → git rebase origin/main → sửa commit cũ bằng git commit --fixup=<sha> + git rebase -i --autosquash → giải conflict (git add + git rebase --continue) → git push --force-with-lease. Chỉ rebase branch của riêng bạn, không rebase main hay branch dùng chung.

Luồng hoạt động

flowchart TD A[git fetch origin] --> B["git rebase origin/main"] B --> C{Conflict?} C -- có --> D["sửa file, git add"] D --> E[git rebase --continue] E --> C C -- không --> F["git commit --fixup / rebase -i --autosquash"] F --> G[chạy test] G --> H[git push --force-with-lease]

Lệnh

Cấu hình nên bật

git config --global pull.rebase true          # git pull = fetch + rebase
git config --global rebase.autoSquash true    # rebase -i tự xếp fixup!/squash!
git config --global rebase.autoStash true     # tự stash/unstash khi working tree bẩn
git config --global rebase.updateRefs true    # Git >= 2.38: cập nhật luôn các branch xếp chồng
git config --global rerere.enabled true       # nhớ cách giải conflict, lần sau tự áp dụng

Cập nhật feature branch theo main

git switch feature/bgp-policy
git fetch origin
git rebase origin/main
# xong thì kiểm tra
git log --oneline origin/main..HEAD

Chỉ muốn rebase lại các commit trong branch, giữ nguyên điểm gốc (không kéo main mới):

git rebase -i --keep-base origin/main

Sửa một commit cũ bằng fixup + autosquash

git log --oneline origin/main..HEAD
# a1b2c3d add route-policy PASS-ALL
# e4f5a6b add BGP neighbor template
 
# sửa file, rồi gắn thay đổi vào commit e4f5a6b
git add -p
git commit --fixup=e4f5a6b              # tạo commit "fixup! add BGP neighbor template"
git rebase -i --autosquash origin/main  # todo list đã xếp sẵn, chỉ cần lưu và thoát

Không muốn mở editor (dùng trong script):

GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash origin/main

Các lệnh trong todo list của rebase -i:

Lệnh Tác dụng
pick giữ commit
reword giữ commit, sửa message
edit dừng lại để amend hoặc tách commit
squash gộp vào commit trước, ghép cả message
fixup gộp vào commit trước, bỏ message
drop bỏ commit
exec <cmd> chạy lệnh (vd test) sau commit trước đó

Chạy test sau mỗi commit để đảm bảo commit nào cũng build được:

git rebase -i --exec "pytest -q" origin/main

Giải conflict

git status                      # file "both modified"
git diff                        # xem marker <<<<<<< ======= >>>>>>>
# sửa file, hoặc chọn hẳn một phía:
git restore --ours   path/file  # khi rebase: "ours" = base mới (main)
git restore --theirs path/file  # khi rebase: "theirs" = commit của bạn đang được áp lại
git add path/file
git rebase --continue
# bỏ qua commit hiện tại / huỷ toàn bộ rebase
git rebase --skip
git rebase --abort

Khi rebase, ours/theirs bị đảo so với khi merge. --ours là phía branch bạn đang rebase lên (main), --theirs là commit của bạn.

Push sau khi rebase

git push --force-with-lease                  # từ chối nếu remote có commit bạn chưa fetch
git push --force-with-lease --force-if-includes   # Git >= 2.30, an toàn hơn khi IDE tự fetch nền

Không dùng git push --force trần: nó ghi đè cả commit người khác vừa đẩy lên.

Stacked branch (PR xếp chồng)

# feat-b được tách ra từ feat-a; rebase feat-b và tự dời luôn feat-a
git switch feat-b
git rebase --update-refs origin/main
git push --force-with-lease origin feat-a feat-b

Lỗi thường gặp

Triệu chứng Nguyên nhân Cách xử lý
! [rejected] ... (non-fast-forward) sau rebase Lịch sử đã viết lại git push --force-with-lease
! [rejected] ... (stale info) Remote có commit mới mà bạn chưa fetch git fetch, xem git log HEAD..origin/<branch>, rebase lên rồi push lại
Conflict lặp lại ở nhiều commit Cùng vùng code bị sửa nhiều lần Bật rerere.enabled, hoặc squash trước rồi rebase
fixup! không tự xếp Thiếu --autosquash và chưa bật rebase.autoSquash Thêm --autosquash
cannot rebase: You have unstaged changes Working tree bẩn git stash hoặc --autostash
unknown option 'update-refs' Git < 2.38 Nâng Git, hoặc rebase từng branch thủ công
Rebase xong mất commit Chọn nhầm drop hoặc giải conflict sai git reflog → git reset --hard HEAD@{n} (xem troubleshooting)

Tham khảo