0
0
Lập trình
Admin Team
Admin Teamtechmely

Ngừng Lộn Xộn Mã: Sử Dụng Git Stash Với Claude Code

Đăng vào 6 giờ trước

• 8 phút đọc

Chủ đề:

#claude

Giới thiệu

Trong thời đại phát triển phần mềm hiện nay, Claude Code đã mở ra một kỷ nguyên mới cho các lập trình viên. Claude Code cho phép chỉnh sửa nhiều phần của dự án cùng một lúc để đáp ứng các truy vấn phức tạp, đồng thời xem xét toàn bộ mã nguồn. Tuy nhiên, tính năng này cũng có thể dẫn đến những thay đổi không mong muốn, khiến dự án bị hỏng. Trong tình huống này, người dùng thường không có cách nào rõ ràng để phục hồi. Thay vì thực hiện nhiều commit cho từng tác vụ, điều này sẽ làm lộn xộn lịch sử Git của bạn. Một giải pháp tốt hơn là sử dụng hệ thống checkpoint tự động với git stash và Hooks của Claude.

1. Hiểu Về Hooks

Hooks là những trình theo dõi sự kiện cho Claude Code, cho phép bạn chạy một lệnh hoặc script khi một sự kiện nhất định xảy ra (chẳng hạn như khi Claude bắt đầu hoặc dừng). Để tìm hiểu thêm, hãy xem tài liệu chính thức tại đây.

2. Thiết lập Cấu trúc Dự án

Trước khi bắt đầu, bạn cần thiết lập cấu trúc dự án như sau:

Copy
├── .claude/
│   ├── settings.local.json
│   └── logs/
├── ...
└── checkpoint.sh

3. Cấu hình Tập tin settings.local.json

Đảm bảo thay thế YOUR_PROJECT_DIR bằng đường dẫn thực tế đến dự án của bạn.

json Copy
{
    "permissions": {
      "deny": [
      ]
    },
    "hooks": {
      "Stop": [
        {
          "hooks": [
            {
              "type": "command",
              "command": "YOUR_PROJECT_DIR/checkpoint.sh",
              "timeout": 30000
            }
          ]
        }
      ]
    }
  }

4. Thiết lập Tập tin checkpoint.sh

Bạn có thể tùy chỉnh các quy tắc checkpoint (số lượng stash tối đa hoặc hành vi ghi log). Nếu gặp phải vấn đề về quyền truy cập, bạn có thể cần chạy chmod +x checkpoint.sh để làm cho tập tin có thể thực thi.

bash Copy
#!/bin/bash
# Claude Code stop hook: checkpoint manager

# Thư mục và tập tin log
LOG_DIR=".claude/logs"
LOG_FILE="$LOG_DIR/checkpoint.log"
mkdir -p "$LOG_DIR"

# Mức độ ghi log qua biến môi trường
CHECKPOINT_DEBUG=${CHECKPOINT_DEBUG:-false}
CHECKPOINT_VERBOSE=${CHECKPOINT_VERBOSE:-true}

# Xoay vòng log: >50KB, giữ lại hiện tại + .old
rotate_logs() {
    if [ -f "$LOG_FILE" ] && [ $(wc -c < "$LOG_FILE" 2>/dev/null || echo 0) -gt 51200 ]; then
        # Xóa tệp cũ, di chuyển tệp hiện tại đến .old
        [ -f "$LOG_FILE.old" ] && rm -f "$LOG_FILE.old"
        mv "$LOG_FILE" "$LOG_FILE.old"
    fi
}

# Hàm hỗ trợ ghi log (có điều kiện)
log_debug() {
    [ "$CHECKPOINT_DEBUG" = "true" ] && echo "[$(date '+%H:%M:%S')] DEBUG: $1" >> "$LOG_FILE"
}

log_info() {
    [ "$CHECKPOINT_VERBOSE" = "true" ] && echo "[$(date '+%H:%M:%S')] INFO: $1" >> "$LOG_FILE"
}

log_error() {
    echo "[$(date '+%H:%M:%S')] ERROR: $1" >> "$LOG_FILE"
}

# Xoay vòng log
rotate_logs

# Bắt đầu ghi debug
log_debug "Stop hook started with args: $*"

# Đọc dữ liệu JSON đầu vào của Claude Code
HOOK_DATA=""
if [ -t 0 ]; then
    log_debug "No stdin data detected (terminal mode)"
else
    log_debug "Reading JSON data from stdin"
    HOOK_DATA=$(cat)
    log_debug "Received JSON: $HOOK_DATA"
fi

# Guard: stop_hook_active true => exit (ngăn chặn vòng lặp)
if echo "$HOOK_DATA" | grep -q '"stop_hook_active":\s*true'; then
    log_info "Stop hook already active, exiting to prevent loop"
    exit 0
fi

# Xác minh repo git
if ! git rev-parse --git-dir >/dev/null 2>&1; then
    log_debug "Not a git repository, exiting"
    exit 1
fi

# Kiểm tra thay đổi trong cây làm việc
GIT_STATUS=$(git status --porcelain 2>/dev/null)
if [ -z "$GIT_STATUS" ]; then
    log_debug "No changes detected, exiting"
    exit 0
fi

log_info "Changes detected: $(echo "$GIT_STATUS" | wc -l) files"

# Xây dựng thông điệp stash (arg hoặc trạng thái git)
if [ -n "$1" ]; then
    MESSAGE="$1"
    log_debug "Using command line message: $MESSAGE"
else
    # Từ trạng thái, lấy tên tệp được sắp xếp theo thời gian sửa đổi (tối đa 3)
    FILES_WITH_TIME=""
    while IFS= read -r line; do
        if [ -n "$line" ]; then
            FILE_PATH=$(echo "$line" | cut -c4-)
            if [ -f "$FILE_PATH" ]; then
                # Lưu với thời gian sửa đổi tính bằng giây
                MOD_TIME=$(stat -f "%m" "$FILE_PATH" 2>/dev/null || echo "0")
                FILES_WITH_TIME="$FILES_WITH_TIME$MOD_TIME:$FILE_PATH\n"
            fi
        fi
    done <<< "$GIT_STATUS"

    # Sắp xếp theo thời gian sửa đổi desc, giữ lại tên
    SORTED_FILES=$(echo -e "$FILES_WITH_TIME" | grep -v "^$" | sort -rn -t: -k1 | cut -d: -f2- | head -3)

    # Soạn thảo thông điệp
    CHANGED_FILES=$(echo "$SORTED_FILES" | tr '\n' ' ' | sed 's/ $//')
    TOTAL_COUNT=$(echo "$GIT_STATUS" | wc -l)
    if [ $TOTAL_COUNT -gt 3 ]; then
        MESSAGE="$CHANGED_FILES (and $(($TOTAL_COUNT - 3)) more)"
    else
        MESSAGE="$CHANGED_FILES"
    fi
    log_debug "Generated message from git status (sorted by modification time): $MESSAGE"
fi

# Tạo nhãn checkpoint
TIMESTAMP=$(date '+%y%m%d:%H:%M:%S')
STASH_MESSAGE="agent: $TIMESTAMP $MESSAGE"

log_info "Creating checkpoint: $STASH_MESSAGE"

# Thực hiện git stash
if git stash push --include-untracked -m "$STASH_MESSAGE" >/dev/null 2>&1; then
    log_info "Stash created successfully"

    # Áp dụng lại stash
    if git stash apply stash@{0} >/dev/null 2>&1; then
        log_info "Stash reapplied successfully"
    else
        log_debug "Warning: Failed to reapply stash"
    fi
else
    log_debug "Error: Failed to create stash"
    exit 1
fi

# Vòng đời stash của agent (tối đa 10)
AGENT_STASH_COUNT=$(git stash list 2>/dev/null | grep "agent:" | wc -l)
log_debug "Current agent stash count: $AGENT_STASH_COUNT"

while [ $AGENT_STASH_COUNT -gt 10 ]; do
    OLDEST_AGENT_STASH=$(git stash list 2>/dev/null | grep "agent:" | tail -1 | cut -d: -f1)
    if [ -n "$OLDEST_AGENT_STASH" ]; then
        log_info "Removing oldest agent stash: $OLDEST_AGENT_STASH"
        git stash drop "$OLDEST_AGENT_STASH" >/dev/null 2>&1
        AGENT_STASH_COUNT=$((AGENT_STASH_COUNT - 1))
    else
        break
    fi
done

# Thông điệp thành công
FINAL_MESSAGE="Checkpoint saved: stash@{0} - $STASH_MESSAGE"
echo "$FINAL_MESSAGE"
log_info "$FINAL_MESSAGE"

5. Khôi phục từ một stash

Để xem danh sách các checkpoint:

Copy
git stash list

Ví dụ:
Khôi phục một stash:

Copy
git stash apply stash@{0}

Thực hành tốt nhất

  • Thực hiện kiểm tra thường xuyên: Đảm bảo rằng bạn kiểm tra các checkpoint thường xuyên để không bỏ lỡ các thay đổi quan trọng.
  • Ghi chú lại lý do cho mỗi stash: Điều này giúp bạn dễ dàng tìm ra lý do cho việc lưu trữ khi cần khôi phục.

Những cạm bẫy thường gặp

  • Quá nhiều stash: Nếu bạn không kiểm soát số lượng stash, bạn có thể gặp khó khăn trong việc tìm kiếm và khôi phục các thay đổi quan trọng.
  • Không kiểm tra trước khi áp dụng stash: Đảm bảo rằng bạn đã kiểm tra các thay đổi trước khi áp dụng lại stash để tránh xung đột.

Mẹo Hiệu suất

  • Tối ưu hóa kích thước stash: Chỉ lưu trữ những thay đổi cần thiết, tránh lưu trữ các tệp không quan trọng.
  • Sử dụng các hook để tự động hóa: Tận dụng các hook để tự động hóa quy trình lưu trữ và khôi phục, tiết kiệm thời gian cho bạn.

Kết luận

Việc sử dụng git stash kết hợp với Claude Code giúp bạn duy trì một lịch sử mã sạch sẽ và hiệu quả. Hệ thống checkpoint tự động giúp bạn dễ dàng phục hồi các thay đổi mà không làm lộn xộn lịch sử Git. Hãy bắt đầu áp dụng ngay hôm nay để nâng cao hiệu suất làm việc của bạn! Nếu bạn có bất kỳ câu hỏi nào, hãy để lại câu hỏi dưới đây.

Câu hỏi thường gặp (FAQ)

1. Tôi nên sử dụng git stash khi nào?

Trả lời: Nên sử dụng khi bạn cần tạm thời lưu trữ các thay đổi mà không muốn commit ngay lập tức.

2. Có cách nào để xem các thay đổi trong stash không?

Trả lời: Có, bạn có thể sử dụng lệnh git stash show -p stash@{0} để xem chi tiết các thay đổi.

3. Làm thế nào để xóa một stash?

Trả lời: Sử dụng lệnh git stash drop stash@{0} để xóa stash cụ thể.

4. Có giới hạn nào cho số lượng stash không?

Trả lời: Mặc định, Git không giới hạn số lượng stash, nhưng bạn nên quản lý chúng để tránh lộn xộn.

5. Tôi có thể khôi phục nhiều stash cùng một lúc không?

Trả lời: Không, bạn cần khôi phục từng stash một.

Hãy thử áp dụng những kiến thức trên vào dự án của bạn và cảm nhận sự khác biệt!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào