Xây dựng Trợ lý Git Commit nội bộ với LLM và Git Hooks

AI tutorial - IT technology blog
AI tutorial - IT technology blog

Đừng viết ‘Update code’ trong các Commit của bạn nữa

Việc viết các thông điệp commit có ý nghĩa thường giống như một công việc tẻ nhạt, đặc biệt là khi bạn đang tập trung cao độ và chỉ muốn đẩy các thay đổi của mình lên. Tôi đã thấy nhiều lập trình viên (và chính tôi cũng từng như vậy) sử dụng các tin nhắn như “fix bugs,” “wip,” hoặc kiểu kinh điển “update.” Thói quen này khiến việc truy vết lịch sử lỗi trở thành một cơn ác mộng cho những người còn lại trong nhóm.

Theo kinh nghiệm thực tế của tôi, đây là một trong những kỹ năng thiết yếu cần nắm vững: duy trì một lịch sử git sạch sẽ, mô tả rõ ràng và chuyên nghiệp. Nó giúp tiết kiệm hàng giờ đồng hồ khi code review và hỗ trợ đắc lực khi bạn cần hoàn tác một thay đổi cụ thể sau nhiều tháng. Để giải quyết vấn đề này mà không tốn công sức thủ công, tôi đã xây dựng một Trợ lý Git Commit nội bộ bằng cách sử dụng Mô hình Ngôn ngữ Lớn (LLM) và Git Hooks. Phần hay nhất là gì? Nó chạy hoàn toàn trên máy của bạn, vì vậy mã nguồn độc quyền của bạn không bao giờ rời khỏi môi trường local.

Bắt đầu nhanh (5 phút)

Bạn có thể chạy một phiên bản cơ bản chỉ trong vài phút bằng cách sử dụng Ollama và một đoạn shell script đơn giản.

1. Cài đặt Ollama và một Model

Tải xuống Ollama từ trang web chính thức của họ và tải về một model nhẹ như Mistral hoặc Llama 3. Đối với các thông điệp commit, một model nhỏ là quá đủ.

# Cài đặt model
ollama pull mistral

2. Tạo Git Hook

Di chuyển đến thư mục gốc của dự án và tạo một tệp trong thư mục hooks. Chúng ta sẽ sử dụng hook prepare-commit-msg, hook này sẽ kích hoạt trước khi trình chỉnh sửa thông điệp commit mở ra.

# Tạo tệp hook
touch .git/hooks/prepare-commit-msg
chmod +x .git/hooks/prepare-commit-msg

3. Thêm script tự động hóa đơn giản

Dán đoạn mã này vào .git/hooks/prepare-commit-msg:

#!/bin/bash

# Lấy các thay đổi đã staged
DIFF=$(git diff --cached)

if [ -z "$DIFF" ]; then
  exit 0
fi

# Yêu cầu Ollama tạo một thông điệp
RESPONSE=$(curl -s -X POST http://localhost:11434/api/generate -d '{
  "model": "mistral",
  "prompt": "Viết một thông điệp git commit ngắn gọn, chuyên nghiệp cho các thay đổi này. Sử dụng định dạng conventional commits (feat:, fix:, v.v.). Chỉ trả về văn bản thông điệp: '"$DIFF"'',
  "stream": false
}' | jq -r '.response')

echo "$RESPONSE" > "$1"

Giờ đây, bất cứ khi nào bạn chạy git commit, trợ lý sẽ tự động điền thông điệp dựa trên các thay đổi đã được staged của bạn.

Đi sâu vào chi tiết: Cách thức hoạt động

Giải pháp này dựa trên sự kết hợp giữa vòng đời nội bộ của Git và các lệnh gọi API local. Git Hooks là các script tự động chạy mỗi khi một sự kiện cụ thể xảy ra trong kho lưu trữ Git. Để xây dựng một trợ lý mạnh mẽ, chúng ta cần xử lý luồng dữ liệu một cách cẩn thận.

Quy trình của Git Hook

Tôi thích sử dụng Python cho phần logic vì việc xử lý các chuỗi nhiều dòng và phản hồi JSON từ LLM sẽ gọn gàng hơn nhiều so với Bash. Dưới đây là cấu trúc nâng cao hơn cho hook prepare-commit-msg:

import subprocess
 import requests
 import sys

 def get_git_diff():
     # Chỉ lấy các thay đổi đã staged
     return subprocess.check_output(["git", "diff", "--cached"]).decode("utf-8")

 def generate_message(diff):
     url = "http://localhost:11434/api/generate"
     prompt = f"""Phân tích git diff sau đây và viết một thông điệp commit ngắn gọn tuân theo tiêu chuẩn Conventional Commits.
    
    Diff:
    {diff}
    
    Định dạng phản hồi: <type>(<scope>): <description>"""
    
    payload = {"model": "mistral", "prompt": prompt, "stream": False}
    response = requests.post(url, json=payload)
    return response.json()["response"].strip()

 if __name__ == "__main__":
    commit_msg_filepath = sys.argv[1]
    diff = get_git_diff()
    
    if diff:
        message = generate_message(diff)
        with open(commit_msg_filepath, "w") as f:
            f.write(message)

Tại sao nên dùng LLM nội bộ?

Quyền riêng tư là lý do hàng đầu. Nếu bạn đang làm việc trong một dự án của công ty, việc gửi các đoạn mã nguồn đến một API bên ngoài (như OpenAI) có thể vi phạm chính sách bảo mật. Bằng cách sử dụng Ollama hoặc LocalAI, dữ liệu vẫn nằm trong RAM của bạn. Hơn nữa, nó hoạt động offline, rất tuyệt vời nếu bạn đang làm việc trên máy bay hoặc ở một quán cà phê có kết nối mạng chập chờn.

Sử dụng nâng cao: Thêm kiểm tra chất lượng

Một trợ lý thực thụ không chỉ viết tin nhắn; nó còn ngăn chặn mã nguồn kém chất lượng được commit. Chúng ta có thể sử dụng hook pre-commit để thực hiện kiểm tra chất lượng bằng LLM trước khi commit được phép tiến hành.

Kiểm tra Secret hoặc Debug Log

Tôi thường thêm một bước kiểm tra để đảm bảo mình không để lại bất kỳ lệnh console.log, print() hoặc API key nào được ghi cứng trong mã nguồn. Bạn có thể yêu cầu LLM tìm kiếm cụ thể những thứ này.

def check_code_quality(diff):
    prompt = f"""Quét diff này để tìm các rủi ro bảo mật như mật khẩu được ghi cứng hoặc các câu lệnh debug bị bỏ quên (console.log, print). 
    Nếu tìm thấy, hãy xuất ra 'REJECT: <lý do>'. Nếu mọi thứ ổn, hãy xuất ra 'PASS'.
    
    Diff:
    {diff}"""
    # ... logic để gọi LLM ...
    if "REJECT" in response:
        print(f"Commit bị chặn: {response}")
        sys.exit(1) # Lệnh này dừng quá trình commit

Xử lý các Diff lớn

LLM có giới hạn về ngữ cảnh. Nếu bạn stage 50 tệp cùng lúc, diff sẽ quá lớn để mô hình có thể xử lý. Tôi thường triển khai giới hạn ký tự hoặc tóm tắt diff theo từng tệp. Một nguyên tắc nhỏ là chỉ gửi 2000 từ đầu tiên của diff tới LLM để giữ cho thời gian phản hồi nhanh chóng.

Mẹo thực tế cho việc sử dụng hàng ngày

  • Chọn đúng model: Đối với các thông điệp commit, Mistral-7B hoặc Llama-3-8B là những lựa chọn tuyệt vời. Nếu máy tính của bạn đời cũ hơn, hãy thử Phi-3 Mini của Microsoft; nó cực kỳ nhanh và thông minh đến ngạc nhiên so với kích thước của mình.
  • Tinh chỉnh prompt: Nếu model quá dài dòng, hãy bảo nó: “Hãy cực kỳ ngắn gọn. Sử dụng tối đa 10 từ.”
  • Quy trình ‘Chỉnh sửa’: Hook prepare-commit-msg vẫn mở trình chỉnh sửa của bạn (như Vim hoặc VS Code). Điều này thật hoàn hảo vì LLM cung cấp một bản nháp, và bạn có thể nhanh chóng tinh chỉnh nó trước khi lưu. Đừng bao giờ tin tưởng AI 100%.
  • Hook toàn cục: Nếu bạn muốn trợ lý này có mặt trong mọi dự án, bạn có thể cấu hình một thư mục git hooks toàn cục bằng lệnh git config --global core.hooksPath /path/to/your/global/hooks.

Việc thiết lập này mất khoảng 15 phút nhưng mang lại hiệu quả mỗi ngày. Nó buộc bạn phải nhìn lại các thay đổi của mình và đảm bảo lịch sử dự án trông như được viết bởi một kỹ sư dày dạn kinh nghiệm, ngay cả vào những ngày thứ Hai mệt mỏi nhất.

Share: