Vấn đề: Nỗi ám ảnh mang tên “Upload thủ công”
Bạn vừa fix xong một bug “chí mạng” lúc 2 giờ sáng. Thay vì đi ngủ, bạn lại phải mở FileZilla, tìm đúng folder để kéo thả file, hoặc SSH vào server để gõ git pull và restart service. Những thao tác lặp đi lặp lại này không chỉ gây nhàm chán mà còn rất dễ dẫn đến sai sót như ghi đè nhầm file hoặc quên restart server.
Thời mình còn làm freelance, mỗi lần deploy một landing page hay con bot Telegram nhỏ, việc setup GitHub Actions hay Jenkins thường tốn thời gian hơn cả viết code. Mình cần một giải pháp: Push code là xong. Đó là lúc mình nhận ra Git Push-to-Deploy với Bare Repository là cứu cánh hoàn hảo.
Tại sao phải dùng Bare Repository?
Khi bạn git init một project thông thường, Git tạo ra thư mục ẩn .git đi kèm với Working Directory (nơi chứa code để bạn sửa). Tuy nhiên, Git sẽ chặn lệnh push trực tiếp vào một Working Directory đang active để tránh xung đột dữ liệu.
Bare Repository giải quyết vấn đề này bằng cách loại bỏ hoàn toàn Working Directory. Nó chỉ đóng vai trò là một “kho chứa” lịch sử và các object. Chúng ta sẽ dùng kho chứa này làm trạm trung chuyển, sau đó dùng Hook để tự động đẩy code ra thư mục chạy ứng dụng thực tế.
Bước 1: Thiết lập môi trường trên Server
Giả sử bạn có một VPS Ubuntu và muốn triển khai ứng dụng Node.js tại /var/www/my-app. Đầu tiên, hãy tạo thư mục chứa code và thư mục chứa Repo.
# Tạo thư mục chạy ứng dụng
sudo mkdir -p /var/www/my-app
sudo chown $USER:$USER /var/www/my-app
# Tạo Bare Repository
mkdir -p ~/repos/my-app.git
cd ~/repos/my-app.git
git init --bare
Sau khi chạy lệnh trên, trong thư mục my-app.git sẽ chỉ có các file cấu hình như hooks, info… Bạn sẽ không thấy source code ở đây, đừng lo lắng vì đó là đặc tính của Bare Repo.
Bước 2: Kích hoạt Post-receive Hook
Hook là các script tự động chạy khi có sự kiện Git. Script post-receive sẽ được kích hoạt ngay sau khi server nhận đủ dữ liệu từ lệnh push của bạn.
Hãy tạo file script:
nano ~/repos/my-app.git/hooks/post-receive
Dán nội dung script dưới đây vào:
#!/bin/bash
TARGET="/var/www/my-app"
GIT_DIR="$HOME/repos/my-app.git"
while read oldrev newrev ref
do
# Chỉ deploy khi push vào branch main
if [[ $ref =~ .*/main$ ]];
then
echo "Đã nhận nhánh main. Đang triển khai..."
git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f main
# Thực hiện các tác vụ bổ sung
cd $TARGET
npm install --production
pm2 restart my-app || pm2 start app.js --name my-app
echo "Triển khai hoàn tất!"
else
echo "Nhánh $ref không được hỗ trợ deploy tự động."
fi
done
Cấp quyền thực thi để script có thể chạy:
chmod +x ~/repos/my-app.git/hooks/post-receive
Bước 3: Kết nối từ máy cá nhân
Tại máy tính cá nhân, bạn thêm một “remote” mới trỏ về địa chỉ VPS. Việc này chỉ cần thực hiện một lần duy nhất cho mỗi dự án.
# Thay 'user' và 'ip' bằng thông tin VPS của bạn
git remote add deploy [email protected]:/home/user/repos/my-app.git
Bước 4: Tận hưởng quy trình mới
Bây giờ, mỗi khi cập nhật code, bạn chỉ cần gõ:
git push deploy main
Toàn bộ quá trình diễn ra trong chưa đầy 5 giây. Terminal sẽ hiển thị log từ server, cho bạn biết chính xác npm install đã chạy hay pm2 đã restart chưa. Bạn tiết kiệm được ít nhất 15-20 phút mỗi ngày so với cách làm thủ công.
Kinh nghiệm thực tế và lưu ý
Qua nhiều dự án triển khai cho khách hàng, mình rút ra 3 lưu ý quan trọng để tránh lỗi “ngớ ngẩn”:
- Quyền ghi (Permissions): User SSH của bạn phải có quyền ghi vào
/var/www/my-app. Nếu xảy ra lỗiPermission denied, hãy kiểm tra lại lệnhchownở Bước 1. - Dọn dẹp file rác: Lệnh
checkout -fsẽ ghi đè file cũ nhưng không xóa các file bạn đã xóa trong Git. Để server luôn sạch sẽ, hãy thêmgit --work-tree=$TARGET --git-dir=$GIT_DIR clean -fdvào script hook. - Bảo mật với SSH Key: Hãy dùng SSH Key thay vì gõ mật khẩu mỗi lần push. Nó vừa nhanh vừa an toàn hơn hẳn.
Kết luận
Phương pháp này cực kỳ phù hợp cho freelance hoặc các team nhỏ cần sự nhanh gọn. Nó không thay thế được các hệ thống CI/CD đồ sộ như GitHub Actions trong các dự án lớn, nhưng lại thắng tuyệt đối về độ đơn giản và hiệu quả tài nguyên. Thay vì tốn cả buổi chiều viết file YAML phức tạp, bạn chỉ mất đúng 5 phút để giải phóng bản thân khỏi những công việc nhàm chán.

