Tóm tắt nhanh: Nếu lỡ push .env lên Git, hãy coi secret là đã bị lộ: revoke hoặc rotate credential ngay, kiểm tra phạm vi ảnh hưởng, rồi mới quyết định có cần rewrite history hay không. Xóa file ở commit mới không đủ an toàn vì dữ liệu cũ vẫn nằm trong lịch sử Git.
Lỡ push .env lên Git là một sự cố bảo mật, không chỉ là lỗi dọn file. Một API key, mật khẩu database hoặc token đã xuất hiện trong remote có thể bị sao chép qua clone, fork, cache hoặc commit cũ [1]. Vì vậy, câu hỏi đúng không phải là “xóa file thế nào?” mà là “credential nào đã lộ, còn dùng được không và cần cô lập ra sao?”.
Bài này hướng dẫn quy trình xử lý lỡ push .env lên Git theo thứ tự ưu tiên: vô hiệu hóa secret, điều tra phạm vi, làm sạch lịch sử khi cần và ngăn sự cố lặp lại. Cách làm phù hợp cho GitHub, GitLab và các remote Git tương tự.

Lỡ push .env lên Git cần làm gì ngay?
Nếu file .env đã lên remote, hãy tạm coi mọi secret trong file đã bị lộ. Việc đầu tiên là revoke hoặc rotate credential; đừng chờ dọn xong Git history mới làm bước này.
- Ngừng sử dụng credential đang nằm trong file.
- Revoke hoặc rotate API key, password, token, private key liên quan.
- Kiểm tra log truy cập, billing, quyền IAM và các hệ thống dùng credential đó.
- Thông báo cho owner hoặc security contact nếu repository dùng chung.
- Sau khi hệ thống an toàn, mới làm sạch working tree và history.
GitHub cũng khuyến nghị revoke hoặc rotate secret trước khi rewrite history, vì chỉ cần credential không còn hiệu lực thì rủi ro truy cập trái phép đã giảm ngay [1]. History rewrite là bước bổ sung, không thay thế việc khóa credential.

Xác định secret nào đã bị lộ
Trước khi sửa repository, hãy lập danh sách những gì từng xuất hiện trong .env. Mục tiêu là không bỏ sót credential đã nằm trong commit hoặc bản build.
Nhóm credential cần kiểm tra
- API key của dịch vụ thanh toán, email, bản đồ, AI hoặc analytics.
- Database URL, username, password và connection string.
- JWT secret, session secret, webhook secret và signing key.
- SSH private key, cloud access key, registry token và CI/CD secret.
- Thông tin môi trường staging hoặc production bị ghi nhầm vào file.
Đừng chỉ nhìn commit mới nhất. Dùng các lệnh sau để kiểm tra diff và lịch sử cục bộ:
git status
git log --all -- .env
git log -p --all -- .env
git grep -n -I -E 'API_KEY|TOKEN|PASSWORD|SECRET' $(git rev-list --all)Lệnh cuối có thể nặng với repository lớn. Nếu repository có nhiều branch hoặc tag, hãy kiểm tra phạm vi ref đầy đủ thay vì chỉ xem nhánh main.
Revoke và rotate credential trước khi xóa file
Revoke làm credential cũ mất hiệu lực; rotate tạo credential mới để ứng dụng tiếp tục hoạt động. Trong incident thật, nên làm cả hai theo tài liệu của nhà cung cấp.
- Xác định service owner và credential đang dùng ở đâu.
- Thu hồi key/token/password cũ trên dashboard của nhà cung cấp.
- Tạo credential mới với quyền tối thiểu cần thiết.
- Cập nhật secret store, CI/CD variables và môi trường deploy.
- Chạy smoke test, rồi kiểm tra log để chắc rằng credential cũ không còn được dùng.
Không đăng credential mới vào issue, pull request, chat hoặc commit “để kiểm tra”. Nếu cần chia sẻ, dùng secret manager hoặc cơ chế biến môi trường của CI/CD.

Xóa .env khỏi commit mới nhất
Nếu secret đã được rotate, hãy đưa .env ra khỏi trạng thái tracked và thêm quy tắc ignore. Đây là bước ngăn file tiếp tục bị commit, nhưng chưa xóa dữ liệu khỏi lịch sử.
printf "\n.env\n.env.*\n!.env.example\n" >> .gitignore
git rm --cached .env
git add .gitignore
git commit -m "chore: stop tracking local env file"
git push origin maingit rm --cached bỏ file khỏi index nhưng giữ file trên máy. Nếu file đang chứa secret thật, hãy tạo .env.example chỉ với tên biến và giá trị mẫu:
APP_ENV=local
DATABASE_URL=postgresql://user:password@localhost:5432/app
API_KEY=replace-with-local-keyBài .gitignore không hoạt động và Git commit nhầm file giúp kiểm tra các trường hợp file đã tracked hoặc đã nằm trong commit.
Xóa .env khỏi Git history bằng git-filter-repo
Chỉ cần xóa file ở commit mới nhất là chưa đủ. Dữ liệu vẫn có thể tồn tại trong commit cũ, branch, tag, fork hoặc clone của đồng đội [2]. Khi rủi ro còn đáng kể sau khi rotate, hãy làm việc trên một bản clone sạch và rewrite history bằng git-filter-repo.
Trước hết, tạo mirror clone để không làm hỏng thư mục làm việc hiện tại:
git clone --mirror git@github.com:ORG/REPO.git repo-clean.git
cd repo-clean.git
git-filter-repo --sensitive-data-removal \
--invert-paths \
--path .envNếu file từng đổi tên hoặc nằm ở nhiều đường dẫn, cần thêm từng --path. GitHub lưu ý rằng rewrite history sẽ đổi commit hash, ảnh hưởng pull request, branch protection, chữ ký commit và mọi clone cũ [1][2]. Vì vậy, hãy thông báo trước, tạm dừng merge và thống nhất thời điểm force-push.

Sau khi kiểm tra kết quả, cập nhật remote bằng force push có kiểm soát:
git show-ref
git fsck --full
git push --force --mirror originKhông chạy git push --force --mirror trên repository đang có người khác cập nhật mà chưa thống nhất. Nếu branch được bảo vệ, hãy dùng quy trình tạm mở quyền hoặc nhờ repository administrator thực hiện. History rewrite không thể xóa secret khỏi các clone hoặc fork mà bạn không kiểm soát.
Kiểm tra và ngăn sự cố lặp lại
Sau khi xử lý, hãy xem đây là một bài học về quy trình secret management. Mục tiêu là ngăn file chứa credential lọt vào commit ngay từ máy developer.
- Đưa secret vào secret manager hoặc biến môi trường của CI/CD.
- Commit
.env.examplenhưng ignore mọi file.envthực tế. - Bật secret scanning và push protection nếu nền tảng hỗ trợ.
- Thêm pre-commit hook hoặc scanner vào CI để bắt pattern nhạy cảm.
- Giới hạn quyền của token, đặt hạn sử dụng và xoay vòng định kỳ.
- Ghi incident note: credential nào lộ, thời điểm, scope ảnh hưởng, hành động đã làm.
Push protection có thể chặn một số secret trước khi chúng được ghi vào remote [3], nhưng không thay thế secret manager. Scanner có thể có giới hạn về loại token, kích thước push và pattern nhận diện [4], nên vẫn cần review thủ công.

Checklist 5 phút khi lỡ push .env lên Git
Nếu cần một quy trình ngắn, hãy thực hiện theo thứ tự này:
- Đánh dấu incident và ngừng chia sẻ commit chứa secret.
- Revoke hoặc rotate toàn bộ credential có trong
.env. - Kiểm tra log truy cập, billing, quyền và các service phụ thuộc.
- Thêm
.envvào.gitignore, giữ lại.env.example. - Quyết định history rewrite dựa trên mức độ nhạy cảm và phạm vi remote.
- Nếu rewrite, thông báo team, làm sạch clone và force-push theo kế hoạch.
- Bật scanner/push protection và ghi lại bài học sau incident.
Điểm quan trọng nhất: xóa .env khỏi working tree không làm credential đã lộ trở nên an toàn. Hãy khóa quyền truy cập trước, sau đó mới dọn dấu vết và cải thiện quy trình.
Câu hỏi thường gặp
Lỡ push .env nhưng repository private thì có cần rotate không?
Có. Repository private vẫn có nhiều bản clone, quyền truy cập, log CI hoặc fork nội bộ. Hãy rotate credential trước, rồi mới đánh giá có cần rewrite history hay không.
Xóa file .env rồi commit lại có đủ không?
Không đủ nếu secret đã xuất hiện trong commit cũ. Cách đó chỉ ngăn file nằm ở phiên bản mới; muốn giảm khả năng truy cập dữ liệu cũ cần rewrite history và phối hợp làm sạch các bản clone.
Đã rotate key thì có cần xóa Git history nữa không?
Không phải lúc nào cũng cần. Nếu credential đã vô hiệu hóa và rủi ro còn lại thấp, rotate có thể là biện pháp chính. Nếu dữ liệu chứa thông tin cá nhân, private key, mật khẩu production hoặc yêu cầu compliance, nên đánh giá thêm history rewrite và hỗ trợ gỡ cache từ nền tảng.
Force push có làm mất code của đồng đội không?
Có thể. Rewrite history đổi commit hash và làm các branch, pull request hoặc clone cũ lệch lịch sử. Hãy dừng merge, thông báo team và hướng dẫn mọi người clone lại hoặc đồng bộ theo runbook trước khi force-push.
Làm sao kiểm tra file đã được Git track chưa?
Dùng git ls-files .env. Nếu lệnh trả về .env, file đang được track. Sau đó kiểm tra git log --all -- .env để biết file từng xuất hiện trong lịch sử nào.
Nguồn tham khảo
- [1] GitHub Docs: Removing sensitive data from a repository — revoke/rotate, history rewrite và phối hợp các clone.
- [2] GitHub: git-filter-repo — công cụ rewrite lịch sử Git.
- [3] GitHub Docs: Push protection — cơ chế chặn secret trước khi push.
- [4] GitHub Docs: Secret scanning detection scope — phạm vi và giới hạn nhận diện secret.
- [5] GitLab Docs: Secret detection — phát hiện secret trong quy trình GitLab.
Fan-out queries đã kiểm tra: lỡ push env lên git, xóa secret khỏi git history, git secret bị lộ phải làm gì. Các query này được dùng như proxy search footprint; chưa có volume công khai đủ tin cậy để đưa số liệu vào bài.
