确保文件在更新挂钩中将CRLF转换为LF - 是否有性能损失?

Sen*_*mar 5 git hook newline core.autocrlf

关于当前版本和下一版本中的core.autocrlf和core.safecrlf功能,已经有很多讨论.我在这里的问题涉及开发人员从裸存储库克隆的环境.

在克隆期间,启用autocrlf设置.但由于开发人员可以完全控制他们的克隆,他们可以删除此autocrlf设置并继续.

  1. 我们可以在.gitattributes文件中指定二进制文件,但是GIT会自动确定文件是文本文件还是二进制文件?

  2. 有没有像更新挂钩(提交钩子是不可能的,因为开发人员仍然可以删除它)的方法,可以放置,以确保,文件(与CRLF)从Windows环境推送到托管裸机库的UNIX机器,转换为UNIX EOL格式(LF)?

  3. 是否有这样的更新挂钩扫描每个文件的CRLF会影响推送操作的性能?

谢谢

Von*_*onC 5

  • 1/Git本身有一个启发式方法来确定文件是二进制还是文本(类似于istext)

  • 2/gergap博客最近(2010年5月)也有同样的想法.在这里
    看到他的更新钩子(在这个答案的最后重现),但诀窍是:如果它检测到一个(假定的)具有不正确的eol风格的非二进制文件
    ,那么钩子将简单地拒绝推送.

LF->CRLF在Windows上签出时Git会转换.
如果文件已经包含CRLF,Git足够聪明地检测到它并且不会将其扩展到CRCRLF错误的位置.它保留了CRLF,这意味着文件在结账时在本地隐式更改,因为再次提交时,错误CRLF将被更正为LF.这就是GIT必须将这些文件标记为已修改的原因.

理解这个问题很好,但我们需要一个解决方案来防止将错误的行结束推送到中央仓库.
解决方案是在中央服务器上安装更新挂钩.

  • 3 /这将是一个很小的成本,但除非你每30秒推一次,这应该不是问题.
    此外,没有实际的转换:文件不正确,推送被拒绝.
    这将转换问题放回原来的位置:在开发人员方面.

#!/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
Run Code Online (Sandbox Code Playgroud)