convert: unify the "auto" handling of CRLF

Before this change,
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes

would have the same effect as
$ echo "* text" >.gitattributes
$ git config core.eol crlf

Since the 'eol' attribute had higher priority than 'text=auto', this may
corrupt binary files and is not what most users expect to happen.

Make the 'eol' attribute to obey 'text=auto' and now
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
behaves the same as
$ echo "* text=auto" >.gitattributes
$ git config core.eol crlf

In other words,
$ echo "* text=auto eol=crlf" >.gitattributes
has the same effect as
$ git config core.autocrlf true

and
$ echo "* text=auto eol=lf" >.gitattributes
has the same effect as
$ git config core.autocrlf input

Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Torsten Bögershausen 2016-06-28 10:01:13 +02:00 коммит произвёл Junio C Hamano
Родитель caa47adc5a
Коммит 6523728499
7 изменённых файлов: 69 добавлений и 59 удалений

Просмотреть файл

@ -389,13 +389,11 @@ file with mixed line endings would be reported by the `core.safecrlf`
mechanism.
core.autocrlf::
Setting this variable to "true" is almost the same as setting
the `text` attribute to "auto" on all files except that text
files are not guaranteed to be normalized: files that contain
`CRLF` in the repository will not be touched. Use this
setting if you want to have `CRLF` line endings in your
working directory even though the repository does not have
normalized line endings. This variable can be set to 'input',
Setting this variable to "true" is the same as setting
the `text` attribute to "auto" on all files and core.eol to "crlf".
Set to true if you want to have `CRLF` line endings in your
working directory and the repository has LF line endings.
This variable can be set to 'input',
in which case no output conversion is performed.
core.symlinks::

Просмотреть файл

@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the
repository. To control what line ending style is used in the working
directory, use the `eol` attribute for a single file and the
`core.eol` configuration variable for all text files.
Note that `core.autocrlf` overrides `core.eol`
Set::
@ -130,8 +131,9 @@ Unset::
Set to string value "auto"::
When `text` is set to "auto", the path is marked for automatic
end-of-line normalization. If Git decides that the content is
text, its line endings are normalized to LF on checkin.
end-of-line conversion. If Git decides that the content is
text, its line endings are converted to LF on checkin.
When the file has been commited with CRLF, no conversion is done.
Unspecified::
@ -146,7 +148,7 @@ unspecified.
^^^^^
This attribute sets a specific line-ending style to be used in the
working directory. It enables end-of-line normalization without any
working directory. It enables end-of-line conversion without any
content checks, effectively setting the `text` attribute.
Set to string value "crlf"::
@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized
regardless of their content.
------------------------
* text=auto
*.txt text
*.vcproj eol=crlf
*.sh eol=lf
*.vcproj text eol=crlf
*.sh text eol=lf
*.jpg -text
------------------------
@ -198,7 +201,7 @@ normalization in Git.
If you simply want to have CRLF line endings in your working directory
regardless of the repository you are working with, you can set the
config variable "core.autocrlf" without changing any attributes.
config variable "core.autocrlf" without using any attributes.
------------------------
[core]

Просмотреть файл

@ -176,7 +176,9 @@ static enum eol output_eol(enum crlf_action crlf_action)
return EOL_LF;
case CRLF_UNDEFINED:
case CRLF_AUTO_CRLF:
return EOL_CRLF;
case CRLF_AUTO_INPUT:
return EOL_LF;
case CRLF_TEXT:
case CRLF_AUTO:
/* fall through */
@ -254,17 +256,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
if (convert_is_binary(len, &stats))
return 0;
if (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
/*
* If the file in the index has any CR in it, do not convert.
* This is the new safer autocrlf handling.
*/
if (has_cr_in_index(path))
return 0;
}
/*
* If the file in the index has any CR in it, do not convert.
* This is the new safer autocrlf handling.
*/
if (checksafe == SAFE_CRLF_RENORMALIZE)
checksafe = SAFE_CRLF_FALSE;
else if (has_cr_in_index(path))
return 0;
}
check_safe_crlf(path, crlf_action, &stats, checksafe);
/* Optimization: No CRLF? Nothing to convert, regardless. */
@ -320,12 +320,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,
return 0;
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
if (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
/* If we have any CR or CRLF line endings, we do not touch it */
/* This is the new safer autocrlf-handling */
if (stats.lonecr || stats.crlf )
return 0;
}
/* If we have any CR or CRLF line endings, we do not touch it */
/* This is the new safer autocrlf-handling */
if (stats.lonecr || stats.crlf )
return 0;
if (convert_is_binary(len, &stats))
return 0;
@ -786,7 +784,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)
ca->drv = git_path_check_convert(ccheck + 2);
if (ca->crlf_action != CRLF_BINARY) {
enum eol eol_attr = git_path_check_eol(ccheck + 3);
if (eol_attr == EOL_LF)
if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)
ca->crlf_action = CRLF_AUTO_INPUT;
else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)
ca->crlf_action = CRLF_AUTO_CRLF;
else if (eol_attr == EOL_LF)
ca->crlf_action = CRLF_TEXT_INPUT;
else if (eol_attr == EOL_CRLF)
ca->crlf_action = CRLF_TEXT_CRLF;
@ -845,9 +847,9 @@ const char *get_convert_attr_ascii(const char *path)
case CRLF_AUTO:
return "text=auto";
case CRLF_AUTO_CRLF:
return "text=auto eol=crlf"; /* This is not supported yet */
return "text=auto eol=crlf";
case CRLF_AUTO_INPUT:
return "text=auto eol=lf"; /* This is not supported yet */
return "text=auto eol=lf";
}
return "";
}
@ -949,7 +951,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str
src = dst->buf;
len = dst->len;
}
return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);
return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);
}
/*****************************************************************

Просмотреть файл

@ -7,7 +7,8 @@
enum safe_crlf {
SAFE_CRLF_FALSE = 0,
SAFE_CRLF_FAIL = 1,
SAFE_CRLF_WARN = 2
SAFE_CRLF_WARN = 2,
SAFE_CRLF_RENORMALIZE = 3
};
extern enum safe_crlf safe_crlf;

Просмотреть файл

@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '
test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff"
'
test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '
test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '
rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&
git config core.autocrlf true &&
@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '
LFonlydiff=$(git diff LFonly) &&
CRLFonlydiff=$(git diff CRLFonly) &&
LFwithNULdiff=$(git diff LFwithNUL) &&
test -z "$LFonlydiff" -a -n "$CRLFonlydiff" -a -z "$LFwithNULdiff"
test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff"
'
test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '

Просмотреть файл

@ -175,8 +175,8 @@ attr_ascii () {
text,lf) echo "text eol=lf" ;;
text,crlf) echo "text eol=crlf" ;;
auto,) echo "text=auto" ;;
auto,lf) echo "text eol=lf" ;;
auto,crlf) echo "text eol=crlf" ;;
auto,lf) echo "text=auto eol=lf" ;;
auto,crlf) echo "text=auto eol=crlf" ;;
lf,) echo "text eol=lf" ;;
crlf,) echo "text eol=crlf" ;;
,) echo "" ;;
@ -397,10 +397,9 @@ commit_chk_wrnNNO "" "" false "" "" "" ""
commit_chk_wrnNNO "" "" true LF_CRLF "" "" "" ""
commit_chk_wrnNNO "" "" input "" "" "" "" ""
commit_chk_wrnNNO "auto" "" false "$WILC" "$WICL" "$WAMIX" "" ""
commit_chk_wrnNNO "auto" "" true LF_CRLF "" LF_CRLF "" ""
commit_chk_wrnNNO "auto" "" input "" CRLF_LF CRLF_LF "" ""
commit_chk_wrnNNO "auto" "" false "$WILC" "" "" "" ""
commit_chk_wrnNNO "auto" "" true LF_CRLF "" "" "" ""
commit_chk_wrnNNO "auto" "" input "" "" "" "" ""
for crlf in true false input
do
commit_chk_wrnNNO -text "" $crlf "" "" "" "" ""
@ -408,8 +407,8 @@ do
commit_chk_wrnNNO -text crlf $crlf "" "" "" "" ""
commit_chk_wrnNNO "" lf $crlf "" CRLF_LF CRLF_LF "" CRLF_LF
commit_chk_wrnNNO "" crlf $crlf LF_CRLF "" LF_CRLF LF_CRLF ""
commit_chk_wrnNNO auto lf $crlf "" CRLF_LF CRLF_LF "" CRLF_LF
commit_chk_wrnNNO auto crlf $crlf LF_CRLF "" LF_CRLF LF_CRLF ""
commit_chk_wrnNNO auto lf $crlf "" "" "" "" ""
commit_chk_wrnNNO auto crlf $crlf LF_CRLF "" "" "" ""
commit_chk_wrnNNO text lf $crlf "" CRLF_LF CRLF_LF "" CRLF_LF
commit_chk_wrnNNO text crlf $crlf LF_CRLF "" LF_CRLF LF_CRLF ""
done
@ -454,9 +453,9 @@ do
check_in_repo_NNO -text "" $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
check_in_repo_NNO -text lf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
check_in_repo_NNO -text crlf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
check_in_repo_NNO auto "" $crlf LF LF LF LF_mix_CR CRLF_nul
check_in_repo_NNO auto lf $crlf LF LF LF LF_mix_CR LF_nul
check_in_repo_NNO auto crlf $crlf LF LF LF LF_mix_CR LF_nul
check_in_repo_NNO auto "" $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
check_in_repo_NNO auto lf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
check_in_repo_NNO auto crlf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
check_in_repo_NNO text "" $crlf LF LF LF LF_mix_CR LF_nul
check_in_repo_NNO text lf $crlf LF LF LF LF_mix_CR LF_nul
check_in_repo_NNO text crlf $crlf LF LF LF LF_mix_CR LF_nul
@ -509,7 +508,7 @@ do
checkout_files text "$id" "crlf" "$crlf" "$ceol" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul
# currently the same as text, eol=XXX
checkout_files auto "$id" "lf" "$crlf" "$ceol" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul
checkout_files auto "$id" "crlf" "$crlf" "$ceol" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul
checkout_files auto "$id" "crlf" "$crlf" "$ceol" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul
done
# core.autocrlf false, different core.eol
@ -517,7 +516,7 @@ do
# core.autocrlf true
checkout_files "" "$id" "" true "$ceol" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul
# text: core.autocrlf = true overrides core.eol
checkout_files auto "$id" "" true "$ceol" CRLF CRLF CRLF LF_mix_CR LF_nul
checkout_files auto "$id" "" true "$ceol" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul
checkout_files text "$id" "" true "$ceol" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul
# text: core.autocrlf = input overrides core.eol
checkout_files text "$id" "" input "$ceol" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul
@ -531,8 +530,8 @@ do
checkout_files text "$id" "" false "" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL
checkout_files text "$id" "" false native $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL
# auto: core.autocrlf=false and core.eol unset(or native) uses native eol
checkout_files auto "$id" "" false "" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul
checkout_files auto "$id" "" false native $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul
checkout_files auto "$id" "" false "" $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul
checkout_files auto "$id" "" false native $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul
done
# Should be the last test case: remove some files from the worktree

Просмотреть файл

@ -16,6 +16,13 @@ test_description='CRLF merge conflict across text=auto change
test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
compare_files () {
tr '\015\000' QN <"$1" >"$1".expect &&
tr '\015\000' QN <"$2" >"$2".actual &&
test_cmp "$1".expect "$2".actual &&
rm "$1".expect "$2".actual
}
test_expect_success setup '
git config core.autocrlf false &&
@ -30,7 +37,7 @@ test_expect_success setup '
git branch side &&
echo "* text=auto" >.gitattributes &&
touch file &&
echo first line >file &&
git add .gitattributes file &&
test_tick &&
git commit -m "normalize file" &&
@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' '
rm -f .gitattributes &&
git reset --hard a &&
git merge b &&
test_cmp expected file
compare_files expected file
'
test_expect_success 'Merge addition of text=auto' '
@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' '
rm -f .gitattributes &&
git reset --hard b &&
git merge a &&
test_cmp expected file
compare_files expected file
'
test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '
@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '
git reset --hard a &&
test_must_fail git merge b &&
fuzz_conflict file >file.fuzzy &&
test_cmp expected file.fuzzy
compare_files expected file.fuzzy
'
test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '
@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '
git reset --hard b &&
test_must_fail git merge a &&
fuzz_conflict file >file.fuzzy &&
test_cmp expected file.fuzzy
compare_files expected file.fuzzy
'
test_expect_failure 'checkout -m after setting text=auto' '
@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' '
git reset --hard initial &&
git checkout a -- . &&
git checkout -m b &&
test_cmp expected file
compare_files expected file
'
test_expect_failure 'checkout -m addition of text=auto' '
@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' '
git reset --hard initial &&
git checkout b -- . &&
git checkout -m a &&
test_cmp expected file
compare_files expected file
'
test_expect_failure 'cherry-pick patch from after text=auto was added' '
@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' '
git reset --hard b &&
test_must_fail git cherry-pick a >err 2>&1 &&
grep "[Nn]othing added" err &&
test_cmp expected file
compare_files expected file
'
test_expect_success 'Test delete/normalize conflict' '