Sự cố Commit lúc 2 giờ sáng
Trời đã khuya. Bạn vừa hoàn thành một phiên làm việc căng thẳng để tiêu diệt một lỗi nghiêm trọng. Bạn gõ git commit -m "Fix: resolve race condition" và nhấn Enter, mong đợi một thông báo thành công. Thay vào đó, Git ném vào mặt bạn một bức tường gạch:
error: gpg failed to sign the data
fatal: failed to write commit object
Lỗi này gây khó chịu vì nó khá mơ hồ. Nó hiếm khi có nghĩa là mã nguồn của bạn sai. Thông thường, nó có nghĩa là Git đã cố gắng gọi GPG để ký xác nhận công việc của bạn, nhưng GPG không tìm thấy cách nào để yêu cầu bạn nhập mật khẩu (passphrase). Đó là một sự cố giao tiếp giữa terminal của bạn và công cụ mã hóa.
Tại sao GPG lại "ngó lơ" bạn
Git không tự xử lý việc nhắc nhập mật khẩu; nó giao nhiệm vụ đó cho một trình đại diện (agent). Dưới đây là lý do tại sao quá trình bàn giao đó thường thất bại:
- Thiếu TTY: GPG không biết màn hình terminal nào để sử dụng cho cửa sổ nhập mật khẩu.
- Agent bị treo:
gpg-agentđang bị treo hoặc đã bị tắt trong nền. - Sai lệch đường dẫn: Bạn đã cài đặt nhiều phiên bản GPG và Git đang gọi sai phiên bản.
- Khóa hết hạn: Khóa GPG của bạn đã đến ngày hết hạn (thường là 1–2 năm sau khi tạo).
Bản sửa lỗi nhanh "Cần Push ngay bây giờ"
Nếu bạn đang vội, bạn thường có thể khởi động lại hệ thống bằng cách trỏ GPG thủ công vào terminal hiện tại và khởi động lại daemon chạy ngầm. Chạy ba lệnh sau:
export GPG_TTY=$(tty)
gpgconf --kill gpg-agent
gpg-agent --daemon
Hãy thử commit lại. Lúc này, nó sẽ kích hoạt cửa sổ bật lên hoặc thông báo trên terminal để nhập mật khẩu. Nếu thành công, thật tuyệt vời—nhưng bạn có thể sẽ cần các giải pháp lâu dài bên dưới để ngăn lỗi này lặp lại vào ngày mai.
Giải pháp lâu dài
1. Tự động hóa biến GPG_TTY
Đây là cách sửa lỗi hàng đầu cho người dùng Linux và macOS. Bạn cần yêu cầu shell của mình luôn xác định terminal hiển thị cho GPG. Mở tệp cấu hình profile (~/.zshrc cho Mac/Zsh hoặc ~/.bashrc cho Bash) và thêm dòng này vào cuối:
export GPG_TTY=$(tty)
Lưu tệp và làm mới phiên làm việc của bạn bằng cách chạy source ~/.zshrc.
2. Cấu hình Pinentry cho macOS và Linux
GPG sử dụng một tiện ích nhỏ gọi là pinentry để hiển thị hộp nhập mật khẩu. Trên macOS, Homebrew thường cài đặt tiện ích này ở một vị trí mà GPG không kiểm tra theo mặc định. Bạn cần chỉ định rõ ràng.
Tạo hoặc chỉnh sửa tệp ~/.gnupg/gpg-agent.conf:
# Dành cho máy Mac chạy Apple Silicon (M1/M2/M3)
pinentry-program /opt/homebrew/bin/pinentry-mac
# Dành cho máy Mac chạy Intel
# pinentry-program /usr/local/bin/pinentry-mac
# Dành cho Linux (Máy chủ/Giao diện dòng lệnh)
# pinentry-program /usr/bin/pinentry-curses
Sau khi lưu, hãy khởi động lại agent: gpgconf --kill gpg-agent.
3. Kiểm tra thời hạn của khóa
Đôi khi cấu hình đã hoàn hảo, nhưng bản thân khóa lại bị lỗi. Hãy kiểm tra trạng thái khóa của bạn bằng lệnh này:
gpg --list-secret-keys --keyid-format LONG
Tìm dòng có dạng như sec rsa4096/3AA5C34371567BD2 2022-01-01 [SC] [expired: 2024-01-01]. Nếu bạn thấy "expired" (hết hạn), bạn phải gia hạn nó:
gpg --edit-key 3AA5C34371567BD2
gpg> expire
# Làm theo hướng dẫn để thêm 1 năm (1y) hoặc 2 năm (2y)
gpg> save
4. Sửa lỗi riêng cho Windows (Git Bash)
Trên Windows, Git thường đi kèm với bản GPG riêng, bản này có thể xung đột với Gpg4win. Hãy ép Git sử dụng đúng phiên bản bằng cách trỏ trực tiếp đến tệp thực thi:
git config --global gpg.program "C:\Program Files (x86)\GnuPG\bin\gpg.exe"
Kiểm tra cuối cùng
Kiểm tra quy trình bằng cách ép buộc một commit có chữ ký trên một thay đổi giả:
git commit -S -m "Kiểm tra sửa lỗi GPG"
Kiểm tra kết quả bằng lệnh git log --show-signature -1. Nếu bạn thấy gpg: Good signature, thiết lập của bạn đã chính thức được sửa xong. Giờ đây bạn có thể quay lại công việc mà không còn cơn đau đầu lúc 2 giờ sáng nữa.

