убедитесь, что файлы преобразованы CRLF в LF в хуке обновления - есть ли снижение производительности?

Было много дискуссий о функциях core.autocrlf и core.safecrlf в текущем и следующем выпусках. Вопрос, который у меня есть здесь, относится к среде, в которой разработчики клонируют из голого репозитория.

Во время клонирования включены настройки autocrlf. Но поскольку разработчики имеют полный контроль над своим клоном, они могут удалить эту настройку autocrlf и продолжить.

  1. Мы можем указать файлы, отличные от двоичных, в файле .gitattributes, но есть ли другой способ, которым GIT автоматически определяет, является ли файл текстовым или двоичным файлом?

  2. Есть ли способ, например, хук обновления (хук фиксации невозможен, поскольку разработчики все еще могут его удалить), который можно разместить, чтобы убедиться, что файлы (с CRLF) передаются из среды Windows на машину UNIX, на которой размещен голый репо, конвертируется в формат UNIX EOL (LF)?

  3. Повлияют ли такие обработчики обновлений, сканирующие каждый файл на наличие CRLF, на производительность операции push?

Спасибо


person Senthil A Kumar    schedule 11.08.2010    source источник


Ответы (1)


  • 1/ Сам Git имеет эвристику для определения того, является ли файл двоичным или текстовым (аналогично istext)

  • 2/ блог gergap недавно (май 2010 г.) идея.
    См. его обновление здесь (воспроизведено в конце этого ответа), но хитрость заключается в следующем:
    Вместо того, чтобы пытаться конвертировать, хук просто отклонит отправку, если обнаружит (предположительно) небинарный файл с неподходящим стилем eol.

Git преобразует LF->CRLF при извлечении в Windows.
Если файл уже содержит CRLF, Git достаточно умен, чтобы обнаружить это, и не расширяет его до CRCRLF, что было бы неправильно. Он сохраняет CRLF, что означает, что файл был неявно изменен локально во время проверки, потому что при повторной фиксации неправильный CRLF будет исправлен на LF. Вот почему GIT должен помечать эти файлы как измененные.

Хорошо, что мы поняли проблему, но нам нужно решение, которое предотвратит отправку неправильных концов строк в центральный репозиторий.
Решение состоит в том, чтобы установить перехватчик обновлений на центральном сервере.

  • 3/ Будет небольшая плата, но если вы не будете отправлять каждые 30 секунд, это не должно быть проблемой.
    Кроме того, фактического преобразования не происходит: если файл неверен, отправка будет отклонена.< br> Это возвращает проблему конверсии туда, где она должна быть: на стороне разработчика.

#!/bin/sh
#
# Author: Gerhard Gappmeier, ascolab GmbH
# This script is based on the update.sample in git/contrib/hooks.
# You are free to use this script for whatever you want.
#
# To enable this hook, rename this file to "update".
#

# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
#echo "COMMANDLINE: $*"

# --- Safety check
if [ -z "$GIT_DIR" ]; then
    echo "Don't run this script from the command line." >&2
    echo " (if you want, you could supply GIT_DIR then run" >&2
    echo "  $0 <ref> <oldrev> <newrev>)" >&2
    exit 1
fi

if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
    echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
    exit 1
fi

BINARAY_EXT="pdb dll exe png gif jpg"

# returns 1 if the given filename is a binary file
function IsBinary() 
{
    result=0
    for ext in $BINARAY_EXT; do
        if [ "$ext" = "${1#*.}" ]; then
            result=1
            break
        fi
    done

    return $result
}

# make temp paths
tmp=$(mktemp /tmp/git.update.XXXXXX)
log=$(mktemp /tmp/git.update.log.XXXXXX)    
tree=$(mktemp /tmp/git.diff-tree.XXXXXX)
ret=0

git diff-tree -r "$oldrev" "$newrev" > $tree
#echo
#echo diff-tree:
#cat $tree

# read $tree using the file descriptors
exec 3<&0
exec 0<$tree
while read old_mode new_mode old_sha1 new_sha1 status name
do
    # debug output
    #echo "old_mode=$old_mode new_mode=$new_mode old_sha1=$old_sha1 new_sha1=$new_sha1 status=$status name=$name"
    # skip lines showing parent commit
    test -z "$new_sha1" && continue
    # skip deletions
    [ "$new_sha1" = "0000000000000000000000000000000000000000" ] && continue

    # don't do a CRLF check for binary files
    IsBinary $tmp
    if [ $? -eq 1 ]; then
        continue # skip binary files
    fi

    # check for CRLF
    git cat-file blob $new_sha1 > $tmp
    RESULT=`grep -Pl '\r\n' $tmp`
    echo $RESULT
    if [ "$RESULT" = "$tmp" ]; then
        echo "###################################################################################################"
        echo "# '$name' contains CRLF! Dear Windows developer, please activate the GIT core.autocrlf feature,"
        echo "# or change the line endings to LF before trying to push."
        echo "# Use 'git config core.autocrlf true' to activate CRLF conversion."
        echo "# OR use 'git reset HEAD~1' to undo your last commit and fix the line endings."
        echo "###################################################################################################"
        ret=1
    fi
done
exec 0<&3
# --- Finished
exit $ret
person VonC    schedule 11.08.2010
comment
Спасибо, Вон, этот хук обновлений очень помогает. Итак, этот скрипт пропускает бинарные файлы или тоже пытается читать бинарные файлы? У меня все еще есть сомнения относительно того, как GIT различает двоичный и текстовый файлы. Должны ли мы указывать, какие файлы имеют LF в файле .gitattributes? (например, ваше предложение в этой статье stackoverflow.com/questions/2517190/) или GIT имеет другие механизмы для различения файлов? - person Senthil A Kumar; 11.08.2010
comment
@Senthil: лучше указать, что является двоичным, а что нет, иначе Git использует простую эвристику - person VonC; 11.08.2010
comment
есть ли у GIT возможность находить CRLF (или атрибут git) во время фиксации? Можно ли использовать этот триггер в качестве хука перед фиксацией вместо хука обновления? - person Senthil A Kumar; 20.08.2010
comment
@Senthil: было бы интересно попробовать, но с некоторыми изменениями, поскольку при предварительной фиксации git diff-tree может не иметь той же информации, что и при обновлении (где все уже зафиксировано) - person VonC; 20.08.2010
comment
Это все еще работает в наши дни? Я попробовал это с git версии 1.9.1 и понял, что двоичные файлы больше не игнорируются, потому что $1 внутри IsBinary будет чем-то вроде /tmp/git.update.K76hFg, поэтому он не содержит никакого расширения файла. - person digory doo; 23.07.2015
comment
@digorydoo Я не знаю, я проверял это годами. К тому же 1.9.1 звучит древнее. Даже в Windows у вас есть Git 2.4.6 (github.com/git-for-windows /git/релизы) - person VonC; 23.07.2015
comment
Конечно, это более старая версия, но, вероятно, не такая старая, как 2010 год, откуда был этот пост. И это текущая версия, которую я получаю, когда запускаю apt-get install git на своей машине с Debian. - person digory doo; 24.07.2015
comment
На самом деле я думаю, что в этом сценарии есть ошибка. $tmp является результатом mktemp, который никогда не будет содержать суффикс файла. IsBinary следует вызывать с $name в качестве аргумента, а не с $tmp... - person digory doo; 27.07.2015
comment
@digorydoo хорошо, не стесняйтесь редактировать этот ответ, чтобы исправить сценарий. - person VonC; 27.07.2015