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

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

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

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

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

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

Спасибо

1 Ответ

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

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

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

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

  • 3 / Это будет небольшая цена, но если вы не нажимаете каждые 30 секунд, это не должно быть проблемой.
    Плюс фактическое преобразование не происходит: если файл неверен, push отклоняется.
    Это ставит проблему конвертации обратно туда, где она должна быть: на стороне разработчика.

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