2012-01-26 10 views
17

Czy można skonfigurować Git, aby używać mojego skonfigurowanego difftool z git add --patch?git add --pakiet z difftoolem

Chciałbym wybrać zmiany, aby dodać do indeksu za pośrednictwem mojego własnego pliku difftool.

+0

Czy Git nawet pokryte na StackOverflow? Myślę, że byłoby to lepsze pytanie dla [SuperUser] (http://superuser.com/). – qJake

+0

Może masz rację. Czy istnieje przycisk migracji, aby go przenieść? – HaxElit

+0

Nie, pozwól modowi to zrobić, lub po prostu zapytaj ponownie, jeśli nie masz ochoty czekać. – qJake

Odpowiedz

9

Nie, niestety.

Przypuszczam, że widzę, że działa - Git generuje plik tymczasowy oparty na tym, co aktualnie znajduje się w indeksie, przekazuje go do difftool wraz z kopią aktualnej wersji drzewa pracy (aby zabezpieczyć się przed wprowadzaniem dalszych zmian), pozwala użyć difftoola do przeniesienia niektórych zmian do wersji indeksu, a następnie po zapisaniu i zamknięciu następuje etapy dowolnej zawartości w zmodyfikowanej wersji indeksu. Zauważ, że wymagałoby to, aby difftool był również edytorem, a nie wszystkie poprawne difftoole; niektóre z nich służą tylko do przeglądania różnic. Zauważ również, że zasadniczo omijasz wszystkie z git add -p. Nie miałbyś normalnego interfejsu do przechodzenia między porcjami, dzielenia bryłek i tak dalej. Difftool byłby całkowicie odpowiedzialny za to wszystko.

Jeśli twój dyftool jest w pełni wyposażony, aby robić tego rodzaju rzeczy, to przypuszczam, że możesz napisać skrypt, aby to zrobić. Zarys, naprawdę bez jakiejkolwiek ochrony błędów, obsługa szczególnych przypadkach i całkowicie niesprawdzone:

#!/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 

Prawdopodobnie wiele sposobów poprawy tego; (pliki binarne?) przepraszam, nie mam czasu, aby być ostrożnym i dokładnym z tym teraz.

+0

Myślę, że może spytałem o to źle. Czy mogę używać mojego difftoola (są dla mnie takie same)? W ten sposób mogę wybrać wszystkie zmiany, które chcę dodać do indeksu. Zaktualizuję pytanie. – HaxElit

+0

To naprawdę świetny pomysł. Mogę zrobić ten skrypt, a następnie dodać alias git 'git diffadd' lub coś podobnego. Spróbuję trochę wyczyścić twój kod i uczynić go nieco bardziej wytrzymałym. Dzięki! – HaxElit

+0

@HaxElit: Jeśli wymyślisz coś solidnego, możesz edytować je w mojej odpowiedzi lub zamieścić własne! – Cascabel

-1

Niestety nie.

Jedynym UI znam w tej chwili jest częścią git-gui przy wywołaniu jako

git gui citool 

The drugiej UI jest interaktywny interfejs konsoli przy wywołaniu jako

git add -i 

git difftool pozwala niektóre różne opcje narzędzi, ale nie interfejs dodawania.

+0

Nie jestem pewien Widzę znaczenie tego; OP pyta o 'git add --patch | -p', które pozwala ci wybiórczo wybrać porcje łatki do etapu. 'git gui citool' zdecydowanie tego nie robi, więc nie ma to znaczenia. I 'git add -i' jest w stanie wywoływać' git add -p', więc jest to okrężny sposób robienia tego, o czym OP już wie, a poza tym nie robi tego, co chce. Tak więc istotą twojej odpowiedzi jest "nie", co, jak sądzę, jestem całkiem dobrze zakryty. – Cascabel

1

Oto my script do tego, który otwiera kdiff3, aby wykonać scalenie 2 plików. Jeśli nie podoba ci się kdiff3, podaj swoje własne wartości dla MERGETOOL i MERGECMD (ale będziesz szalony, aby nie lubić kdiff3).

Aby uniknąć niespodzianek, ten skrypt próbuje naśladować kod git add -p, jeśli chodzi o argumenty i kody błędów. (Obsługuje obie listy plików i katalogów.)

Plus, to właściwie obsługuje różne przypadki narożne, w tym:

  • użytkownik próbuje uruchomić skrypt w katalogu non-git (przerwać z błędem)
  • Użytkownik uderza Ctrl+C przed zakończeniem (rzucić wcześnie)
  • spadki użytkowników, aby zapisać wynik scalania w difftool (wtedy go nie używam, ale przejść do następnego pliku)
  • difftool ma nieoczekiwany błąd (przystanek wcześnie)

Przykład użycia:

$ ## 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]" 
Powiązane problemy