Sổ tay kỹ thuật

Git troubleshooting – detached HEAD, commit nhầm branch, push bị reject

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

Dùng khi Git ở trạng thái lạ, lỡ commit nhầm branch, reset mất commit hoặc push bị từ chối, kèm cách cứu bằng reflog.

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

Triệu chứng chính: HEAD detached at ..., commit lên main thay vì feature branch, git reset --hard xong mất commit, ! [rejected] ... (fetch first) hoặc (non-fast-forward) khi push.

Lỗi thường gặp

Triệu chứng Nguyên nhân Cách xử lý
HEAD detached at a1b2c3d Checkout một commit/tag thay vì branch Giữ việc đang làm: git switch -c rescue; bỏ: git switch main
Commit nhầm lên main (chưa push) Quên tạo branch Xem mục "Commit nhầm branch" bên dưới
Mất commit sau reset --hard / rebase HEAD đã dời, commit vẫn còn trong reflog git reflog → git branch recover <sha>
Stash bị drop nhầm Stash là commit không còn ref git fsck --no-reflog | grep 'dangling commit' → git stash apply <sha>
! [rejected] main -> main (fetch first) Remote có commit mới git pull --rebase rồi push
! [rejected] ... (non-fast-forward) Bạn vừa rebase/amend Branch riêng: git push --force-with-lease; branch chung: không force, dùng git revert
GH006: Protected branch update failed Branch được bảo vệ trên GitHub Push lên branch khác và mở PR
GH001: Large files detected File > 100 MB trong lịch sử Bỏ file khỏi commit (git reset --soft) hoặc dùng Git LFS
fatal: Not possible to fast-forward, aborting. pull.ff=only và hai bên đã rẽ nhánh git pull --rebase
refusing to merge unrelated histories Hai repo không chung gốc (vd repo mới tạo có README) git pull origin main --allow-unrelated-histories (chỉ khi chắc chắn)
Your branch and 'origin/x' have diverged Cả local và remote có commit riêng git log --oneline --left-right HEAD...origin/x rồi rebase hoặc merge
Lỡ commit secret Secret nằm trong lịch sử, xoá file ở commit sau không đủ Rotate secret trước, rồi xem git-secret-leak

Các bước khoanh vùng

1. Biết mình đang ở đâu

git status
git branch -vv                      # branch hiện tại, upstream, ahead/behind
git log --oneline --graph -15 --all

2. Commit nhầm branch (chưa push)

# Đang ở main, có 2 commit lẽ ra thuộc feature
git branch feature/fix-acl          # giữ 2 commit ở branch mới
git reset --hard origin/main        # đưa main về như remote
git switch feature/fix-acl

Nếu feature branch đã tồn tại sẵn thì cherry-pick sang:

git switch feature/fix-acl
git cherry-pick <sha1> <sha2>
git switch main && git reset --hard origin/main

Nếu đã push lên main thì không reset, dùng git revert <sha> để tạo commit đảo ngược.

3. Cứu commit bằng reflog

git reflog -20
# e4f5a6b HEAD@{0}: reset: moving to HEAD~3
# 9c8d7e6 HEAD@{1}: commit: add prefix-list
git branch recover 9c8d7e6          # an toàn: tạo branch trỏ vào commit cũ
# hoặc đưa branch hiện tại về đó
git reset --hard HEAD@{1}

Reflog chỉ có trên máy local và mặc định giữ khoảng 90 ngày (commit không còn ref giữ khoảng 30 ngày) trước khi git gc dọn.

4. Undo đúng mức

Tình huống Lệnh
Sửa message commit cuối (chưa push) git commit --amend
Bỏ commit cuối, giữ code git reset --soft HEAD~1
Commit đã push lên branch chung git revert <sha>
Huỷ merge đang dở git merge --abort
Huỷ rebase đang dở git rebase --abort
Lấy lại 1 file từ commit trước git restore --source=HEAD~1 -- path/file

Kiểm tra nhanh

git status -sb
git log --oneline --left-right --graph HEAD...@{upstream}   # < local, > remote
git fetch --prune && git branch -vv | grep ': gone]'        # branch có remote đã bị xoá
git reflog -10
git fsck --no-reflog | grep 'dangling commit'

Trước thao tác nguy hiểm, tạo branch backup: git branch backup/$(date +%F-%H%M). Tốn 0 byte, cứu được cả buổi chiều.