2013-02-01 32 views
8

Tôi đang cố gắng viết kịch bản lệnh git pre-commit hook, nó phải ghi ngày cam kết vào lúc bắt đầu các tệp đã sửa đổi. Vấn đề của tôi là tôi không thể thêm các tập tin đã sửa đổi vào cam kết trước đó. Khi tôi cố gắng gọi git commit một lần nữa nó chạy đệ quy. Làm thế nào tôi có thể viết kịch bản, mà thêm thời gian sửa đổi ở phần cuối của các tập tin sửa đổi?Git hook, sửa đổi các tệp cam kết

Mã của tôi:

#!/bin/bash 

files_modified=`git diff-index --name-only HEAD` 

for f in $files_modified; do 
    if [[ $f == *.groovy ]]; then 
     $line = $(head -1 f) 
     if [[ $line == "/%%*" ]]; 
     then 
      sed -i 1d 
     fi 
     echo "/%% " + $(date +"%m_%d_%Y") + " %%\\" >> f 
     git add f 
    fi 
done 
git commit --amend #recursive 
exit 

Trả lời

2

Bạn không thể sửa đổi một cam kết trong một trước cam kết nối.
Và những gì bạn đang làm tương tự như cơ chế mở rộng từ khóa, đây không phải là phương pháp hay nhất với Git (hoặc bất kỳ DVCS nào), như được giải thích trong "To put the prefix ?<revision-number> to codes by Git/Svn".

cách tiếp cận khác bao gồm:

2

Nhìn vào pre-cam kết nối của bạn, bạn gần như có một cái gì đó phân loại. Dưới đây là các thay đổi tối thiểu mà tôi thấy là bắt buộc:

#!/bin/bash 
    files_modified=`git diff --cache --name-only --diff-filter=ACM` 
      ### fix: use current branch; cached; and only files 
    for f in $files_modified; do ### broken: if space in filename(s) 
     if [[ $f == *.groovy ]]; then 
      line=$(head -1 $f) ### fix: forgot a $ before f 
      if [[ $line == "/%%*" ]]; 
      then 
       sed -i 1d "$f" ### fix: forgot file argument 
      fi 
      echo "/%% " + $(date +"%m_%d_%Y") + " %%\\" >> $f 
        ### fix: forgot a $ before f 
      git add -u $f ### fix: forgot a $ before f 
     fi 
    done 
    ### undesired ### git commit --amend #recursive 
    ### unneeded ### exit 

Tuy nhiên, tôi nhận thấy một số vấn đề với việc triển khai của bạn. Bạn sẽ xóa một dòng khớp với "/ %% *" từ đầu tệp và thêm một dòng mới vào cuối. Mỗi khi bạn chạy ứng dụng này, bạn sẽ mãi mãi thêm một dòng mới /%% mm_dd_YYYY %%\ vào cuối tệp. Đó có thể không phải là những gì bạn muốn (1000 cam kết sau đó, một tệp trước đó trống sẽ có 1000 dòng). Tôi nghĩ những gì bạn muốn làm là thay thế dòng hiện tại. Trong trường hợp đó, một bản dịch sed để thay thế các đường khớp sẽ hoạt động.

Dưới đây là một công thức mà tôi nghĩ được gần gũi hơn với những gì bạn muốn:

#!/bin/sh 
    TMPFILE="/tmp/${0##*/}.$$" 
    for f in $(git diff --cached --name-only --diff-filter=ACM); do 
      # XXX broken: if space in filename(s) 
      case "$f" in 
      *.groovy) : fall through ;; 
      *) continue 
      esac 
      cp "$f" "$TMPFILE" || continue 
      awk -v new="/%% $(date +%m_%d_%Y) %%\\" \ 
        'NR==1{sub("^/%% .* %%\\\\$",new)}1' \ 
        < "$TMPFILE" > "$f" 
      git add -u -- "$f" 
    done 

Nếu dòng đầu tiên của file phù hợp /%% ... %%\ sau đó nó được cập nhật với ngày hiện tại/lần (tại thời điểm trước cam kết).

Tuy nhiên, đó chỉ là minh họa cách nó có thể được thực hiện đơn giản. Đó thực sự không phải là một giải pháp hoàn chỉnh. Đoạn mã trên sẽ không hoạt động với các tệp có chứa dấu cách trong tên, dấu ngoặc kép, dấu gạch chéo ngược, tab, v.v.

Đối với một giải pháp hoàn chỉnh:

  1. Sử dụng sau đây trước khi cam kết nối:

    #!/bin/sh 
    git diff --cached --name-only -z --diff-filter=ACM | 
         xargs -r0 .filters/myfilter 
    
  2. Tạo ".filters/myfilter" với các nội dung sau đây:

    #!/bin/sh 
    TMPFILE="/tmp/${0##*/}.$$" 
    for f in "[email protected]"; do ### the only difference from above recipe 
         case "$f" in 
         *.groovy) : fall through ;; 
         *) continue 
         esac 
         cp "$f" "$TMPFILE" || continue 
         awk -v new="/%% $(date +%m_%d_%Y) %%\\" \ 
           'NR==1{sub("^/%% .* %%\\\\$",new)}1' \ 
           < "$TMPFILE" > "$f" 
         git add -u -- "$f" 
    done 
    

Thông báo trên ntation có thể xử lý bất kỳ tên tập tin bạn ném vào nó.

Các vấn đề liên quan