Soru git add - difftool ile birlikte


Yapılandırılmış difftool'umu kullanmak için Git'i yapılandırmak mümkün mü? git add --patch?

Kendi difftool'umla indekse eklemek için değişiklikleri seçerim.


20
2018-01-26 19:19


Menşei


Git StackOverflow'ta bile kapalı mı? Bunun daha iyi bir soru olacağını düşünürdüm Süper Kullanıcı. - qJake
Haklı olabilirsin. Taşınacak bir göç düğmesi var mı? - HaxElit
Hayır, bir mod yapmasına izin vermeli ya da beklemek istemiyorsan tekrar sor. - qJake
@SpikeX: Programlama araçları hakkındaki sorular Yığın Taşması için uygundur. - mipadi
@SpikeX: bakın SSS; kapsam, "programcılar tarafından yaygın olarak kullanılan yazılım araçlarını" içerir. Tıkla git Orada etiketleyin ve önceki binlerce soruyu göreceksiniz. (Diğer VCS / SCM'ler, programlama editörleri, hata ayıklayıcılar, profilleyiciler, derleyicilerle ilgili soruları da göreceksiniz ...) Soruların güncelliği hakkında kararlar vermeden önce lütfen en azından SSS bölümünü okuyunuz. - Cascabel


Cevaplar:


Hayır maalesef.

Sanırım bu çalışmayı görebiliyorum - Git şu anda dizinde olana göre geçici bir dosya oluşturuyor, şimdiki çalışma ağacı versiyonunun bir kopyasının yanı sıra (daha fazla değişiklik yapmanıza engel olmak için) difftool'a uzatıyor. Bazı değişikliklerin indeks sürümüne taşınması için difftool, sonra kaydettikten ve çıktıktan sonra, bu değiştirilmiş dizin sürümünde hangi içeriğin olduğunu aşamalandırır. Bunun, difftool'un bir editörün biraz olması gerekeceğini ve tüm geçerli difftools'ların değil; bazıları sadece diffs'i görmek içindir. Ayrıca bu temelde bypass olduğunu unutmayın herşey arasında git add -p. Topaçlar arasında dolaşmak, topaçları ayırmak vb. İçin normal arayüzlerden hiçbirine sahip olamazdınız. Tüm bunlar için difftool tamamen sorumlu olacaktır.

Eğer diftoolünüz bu tür bir şeyi yapacak kadar özellikli ise, o zaman bunu yapmak için bir senaryo yazabilirsiniz. Bir hata, gerçekten herhangi bir hata koruması olmadan, özel durumların (ikili dosyalar?) Kullanımı ve tamamen test edilmemiş:

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

Muhtemelen bunu geliştirmek için birçok yol var; Üzgünüm şu an dikkatli ve eksiksiz olmak için zamanım yok.


9
2018-01-26 19:46



Sanırım yanlış sormuş olabilirim. Difftool'u kullanabilir miyim (onlar benim için aynıdır)? Bu sayede dizine eklemek istediğim tüm değişiklikleri seçebilirim. Soruyu güncelleyeceğim. - HaxElit
Bu gerçekten harika bir fikir. Bunu bir komut dosyası haline getirebilir ve sonra bir adet diğer ad ekleyebilirim git diffadd ya da başka birşey. Kodunuzu biraz temizlemeyi ve biraz daha sağlamlaştırmayı deneyeceğim. Teşekkürler! - HaxElit
@HaxElit: Eğer sağlam bir şeyle gelirseniz, lütfen cevabımı düzenlemek için çekinmeyin, ya da kendi mesajınızı gönderin! - Cascabel
Kodu kullandığım sürümle güncelledim. Oldukça iyi çalışıyor. Şimdi kullanarak bir taahhüt yapmayı hayal bile edemiyorum. - HaxElit
While döngüsü eksik done. Ayrıca git checkout-index geçici dosya adı, TAB char, sonra orijinal dosya adı döndürür ben kullandım index_version=$(git checkout-index --temp "$file" | cut -f1) - RazerM


İşte senaryon Bunun için hangi açılır kdiff3 2 dosya birleştirme gerçekleştirmek için. Beğenmediyseniz kdiff3, kendi değerlerinizi belirtin MERGETOOL ve MERGECMD (ama sevmemeye deli olmalısın kdiff3).

Sürprizlerden kaçınmak için, bu betik taklit etmeye çalışır git add -p argümanlar ve hata kodları kadar. (Her iki dosya ve dizin listesini de işler.)

Ayrıca, aşağıdakiler de dahil olmak üzere çeşitli köşe durumlarını düzgün bir şekilde ele alır:

  • Kullanıcı betiği gitmeyen bir dizinde çalıştırmayı dener (hatayla iptal edilir)
  • Kullanıcı vurur Ctrl+C bitirmeden önce (erken çık)
  • Kullanıcı, birleştirme sonucunu difftool içinde kaydetmeyi reddeder (sonra kullanmayın, ancak sonraki dosyaya geçin)
  • Difftool beklenmeyen bir hataya sahiptir (erken dur)

Örnek kullanım:

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

$ ## ...or with custom mergetool:
$ export MERGETOOL='opendiff'
$ export MERGECMD='$MERGETOOL $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 "$@"
    process_all "$@"
}

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=( "$@" )
    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 "$@"

2
2017-10-16 21:20





Ne yazık ki değil.

Şu anda bildiğim tek UI, şu şekilde çağrıldığında git-gui'nin bir parçasıdır

git gui citool

Diğer UI, kullanıcı arabirimi olarak çağrıldığında etkileşimli konsol kullanıcı arayüzüdür.

git add -i

git difftool, bazı farklı araç seçeneklerine izin verir, ancak eklenti arayüzünü kullanmaz.


-1
2018-01-26 21:27



Bunun alaka düzeyini gördüğümden emin değilim; OP soruyor git add --patch|-pBu, seçmeli olarak yamadaki hunks'i sahneye koymanızı sağlar. git gui citool kesinlikle bunu yapmaz, bu yüzden alakasız. Ve git add -i çağırmak yeteneğine sahiptir git add -pBu yüzden OP'nin zaten bildiği şeyi yapmak için bir dolambaçlı yoldur ve aksi takdirde istediğini yapmaz. Yani cevabınızın özü "hayır", ki ben oldukça iyi kaplanmış hissediyorum. - Cascabel