5

在当前版本和下一个版本中,有很多关于 core.autocrlf 和 core.safecrlf 特性的讨论。我在这里遇到的问题与开发人员从裸存储库克隆的环境有关。

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

  1. 我们可以在 .gitattributes 文件中指定二进制文件以外的文件,但是 GIT 是否有其他方法自动确定文件是文本文件还是二进制文件?

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

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

谢谢

4

1 回答 1

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

  • 2/ gergap weblog最近(2010 年 5 月)也有同样的想法。
    请在此处查看他的更新挂钩(在此答案的末尾转载),但诀窍是:如果检测到(假定)具有不正确 eol 样式的非二进制文件,挂钩将简单地拒绝推送
    ,而不是尝试转换。

LF->CRLF在 Windows 上签出时Git 会进行转换。
如果文件已经包含CRLF,Git 足够聪明地检测到它并且不会将其扩展CRCRLF为错误的地方。它保留. CRLF_ 这就是 GIT 必须将这些文件标记为已修改的原因。CRLFLF

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

  • 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
于 2010-08-11T06:57:47.770 回答