2012-01-26 27 views
17

Có thể định cấu hình Git để sử dụng difftool được định cấu hình của mình với git add --patch không?git add --patch với difftool

Tôi muốn chọn các thay đổi để thêm vào chỉ mục thông qua difftool của riêng tôi.

+0

là Git thậm chí bao phủ trên StackOverflow? Tôi nghĩ đây sẽ là một câu hỏi hay hơn cho [SuperUser] (http://superuser.com/). – qJake

+0

Bạn có thể đúng. Có nút di chuyển để di chuyển nó không? – HaxElit

+0

Không, hãy để một mod làm điều đó, hoặc chỉ hỏi lại nếu bạn không muốn chờ đợi. – qJake

Trả lời

9

Không, thật không may.

Tôi cho rằng tôi có thể thấy rằng hoạt động - Git tạo tệp tạm thời dựa trên những gì hiện có trong chỉ mục, đưa nó đến difftool cùng với bản sao của phiên bản cây công việc hiện tại (để bảo vệ bạn không thực hiện thêm thay đổi), cho phép bạn sử dụng difftool để di chuyển một số thay đổi cho phiên bản chỉ mục, sau đó khi bạn lưu và thoát, các giai đoạn bất kỳ nội dung nào nằm trong phiên bản chỉ mục đã sửa đổi đó. Lưu ý rằng điều này sẽ yêu cầu difftool cũng là một chút của một trình soạn thảo, và không phải tất cả các difftools hợp lệ là; một số người trong số họ chỉ để xem diffs. Cũng lưu ý rằng điều này về cơ bản là bỏ qua tất cả của git add -p. Bạn sẽ không có bất kỳ giao diện bình thường nào từ nó để di chuyển giữa các khối, tách các khối, v.v. Các difftool sẽ hoàn toàn chịu trách nhiệm cho tất cả điều đó.

Nếu difftool của bạn có đầy đủ tính năng đủ để làm điều này, thì tôi cho rằng bạn có thể viết một kịch bản để làm điều đó. Đường viền, không thực sự có bất kỳ lỗi bảo vệ nào, xử lý các trường hợp đặc biệt (tệp nhị phân?) Và hoàn toàn chưa được kiểm tra:

#!/bin/bash 
tmpdir=$(mktemp -d) 
git diff --name-only | 
while read file; do 
    cp "$file" $tmpdir 
    # this has your changes in it 
    work_tree_version="$tmpdir/$file" 
    # this has the pristine version 
    index_version=$(git checkout-index --temp "$file") 
    # and now you bring changes from the work tree version into the index version, 
    # within the difftool, and save the index version and quit when done 
    my_difftool "$work_tree_version" "$index_version" 

    # swap files around to run git add 
    mv "$file" "$work_tree_version" 
    mv "$index_version" "$file" 
    git add "$file" 
    mv "$work_tree_version" "$file" 
    # you could also do this by calculating the diff and applying it directly to the index 
    # git diff --no-index -- "$file" "$original_index_version" | git apply --cached 

rm -r $tmpdir 

Có thể là nhiều cách để cải thiện điều đó; xin lỗi tôi không có thời gian để cẩn thận và kỹ lưỡng với nó ngay bây giờ.

+0

Tôi nghĩ có lẽ tôi đã hỏi sai. Tôi có thể sử dụng difftool của tôi (Chúng giống nhau đối với tôi) không? Bằng cách này tôi có thể chọn tất cả các thay đổi mà tôi muốn thêm vào chỉ mục. Tôi sẽ cập nhật câu hỏi. – HaxElit

+0

Đó là một ý tưởng thực sự tuyệt vời. Tôi có thể làm điều này một kịch bản và sau đó thêm một bí danh git 'git diffadd' hoặc một cái gì đó. Tôi sẽ thử làm sạch mã của bạn một chút và làm cho nó mạnh mẽ hơn một chút. Cảm ơn! – HaxElit

+0

@ HaxElit: Nếu bạn nghĩ ra một thứ gì đó chắc chắn, vui lòng chỉnh sửa nó vào câu trả lời của tôi hoặc đăng bài của riêng bạn! – Cascabel

-1

Thật không may là không.

Giao diện duy nhất tôi biết tại thời điểm này là một phần của git-gui khi gọi như

git gui citool 

Giao diện khác là giao diện điều khiển giao diện người dùng tương tác khi gọi như

git add -i 

git difftool phép một số tùy chọn công cụ khác, nhưng không phải là giao diện thêm.

+0

Tôi không chắc chắn Tôi thấy sự liên quan của điều này; OP đang hỏi về 'git add --patch | -p', cho phép bạn chọn lọc các khối của miếng vá đến giai đoạn. 'git gui citool' chắc chắn không làm điều đó, vì vậy nó không liên quan. Và 'git add -i' có khả năng gọi' git add -p', do đó, nó là một cách vòng xoay để làm những gì OP đã biết, và ngược lại không làm những gì anh ta muốn. Vì vậy, các chất của câu trả lời của bạn là "không", mà tôi cảm thấy tôi khá tốt được bảo hiểm. – Cascabel

1

Đây là my script cho mục này, mở ra kdiff3 để bạn thực hiện quá trình hợp nhất 2 tệp. Nếu bạn không thích kdiff3, hãy cung cấp các giá trị của riêng bạn cho MERGETOOLMERGECMD (nhưng bạn sẽ bị điên không thích kdiff3).

Để tránh những điều bất ngờ, tập lệnh này cố gắng bắt chước git add -p đến mức đối số và mã lỗi. (Nó xử lý cả hai danh sách các tập tin và thư mục.)

Thêm vào đó, nó đúng cách xử lý các trường hợp góc khác nhau, bao gồm:

  • Người dùng cố gắng để chạy các kịch bản trong một thư mục phi git (hủy bỏ với một lỗi)
  • Người dùng đánh Ctrl+C trước khi kết thúc (bỏ đầu)
  • các giảm sử dụng để lưu các kết quả hợp nhất trong difftool (sau đó không sử dụng nó, nhưng chuyển sang tập tiếp theo)
  • các difftool có lỗi không mong muốn (dừng sớm)

sử dụng Ví dụ:

$ ## With kdiff3 (default): 
$ add-with-mergetool myfile1.txt 
$ add-with-mergetool some-directory 

$ ## ...or with custom mergetool: 
$ export MERGETOOL='opendiff' 
$ export MERGECMD='$LOCAL $REMOTE -merge $MERGED' 
$ add-with-mergetool some-directory/*.py 
#!/bin/bash 
# 
# add-with-mergetool 
# Author: Stuart Berg (http://github.com/stuarteberg) 
# 
# This little script is like 'git add --patch', except that 
# it launches a merge-tool to perform the merge. 

# TODO: For now, this script hard-codes MERGETOOL and MERGECMD for kdiff3. 
#  Modify those variables for your own tool if you wish. 
#  In the future, it would be nice if we could somehow read 
#  MERGETOOL and MERGECMD from the user's git-config. 

# Configure for kdiff3 
# (and hide warnings on about modalSession, from kdiff3 on OSX) 
MERGETOOL=${MERGETOOL-kdiff3} 
MERGECMD=${MERGECMD-'"${MERGETOOL}" "${LOCAL}" "${REMOTE}" -o "${MERGED}"'\ 
        2>&1 | grep -iv modalSession} 

main() { 
    check_for_errors "[email protected]" 
    process_all "[email protected]" 
} 

check_for_errors() { 
    which "${MERGETOOL}" > /dev/null 
    if [[ $? == 1 ]]; then 
     echo "Error: Can't find mergetool: '${MERGETOOL}'" 1>&2 
     exit 1 
    fi 

    if [[ "$1" == "-h" ]]; then 
     echo "Usage: $(basename $0) [<pathspec>...]" 1>&2 
     exit 0 
    fi 

    # Exit early if we're not in a git repo 
    git status > /dev/null || exit $? 
} 

process_all() { 
    repo_toplevel=$(git rev-parse --show-toplevel) 

    # If no args given, add everything (like 'git add -p') 
    if [[ $# == 0 ]]; then 
     set -- "$repo_toplevel" 
    fi 

    # For each given file/directory... 
    args=("[email protected]") 
    for arg in "${args[@]}" 
    do 
     # Find the modified file(s) 
     changed_files=($(git diff --name-only -- "$arg")) 
     (
      # Switch to toplevel, to easily handle 'git diff' output 
      cd "$repo_toplevel" 

      # For each modified file... 
      for f in "${changed_files[@]}" 
      do 
       if [[ $startmsg_shown != "yes" ]]; then 
        echo "Starting $(basename $0). Use Ctrl+C to stop early." 
        echo "To skip a file, quit ${MERGETOOL} without saving." 
        echo 
        startmsg_shown="yes" 
       fi 

       # This is where the magic happens.    
       patch_file_and_add "$f" 
      done 
     ) || exit $? # exit early if loop body failed 
    done 
} 

# This helper function launches the mergetool for a single file, 
# and then adds it to the git index (if the user saved the new file). 
patch_file_and_add() { 
    f="$1" 
    git show :"$f" > "$f.from_index" # Copy from the index 
    (
     set -e 
     trap "echo && exit 130" INT # Ctrl+C should trigger abnormal exit 

     # Execute 2-file merge 
     echo "Launching ${MERGETOOL} for '$f'." 
     LOCAL="$f.from_index" 
     REMOTE="$f" 
     MERGED="$f.to_add" 
     eval "${MERGECMD}" 

     if [[ -e "$f.to_add" ]]; then 
      mv "$f" "$f.from_working" # Backup original from working-tree 
      mv "$f.to_add" "$f"  # Replace with patched version 
      git add "$f"    # Add to the index 
      mv "$f.from_working" "$f" # Restore the working-tree version 
     fi 
    ) 
    status=$? 
    rm "$f.from_index" # Discard the old index version 
    if [ $status == 130 ]; then 
     echo "User interrupted." 1>&2 
     exit $status 
    elif [ $status != 0 ]; then 
     echo "Error: Interactive add-patch stopped early!" 1>&2 
     exit $status 
    fi 
} 

main "[email protected]" 
Các vấn đề liên quan