Merge branch 'jc/renormalize-merge-kill-safer-crlf' into maint

"git merge" with renormalization did not work well with
merge-recursive, due to "safer crlf" conversion kicking in when it
shouldn't.

* jc/renormalize-merge-kill-safer-crlf:
  merge: avoid "safer crlf" during recording of merge results
  convert: unify the "auto" handling of CRLF
This commit is contained in:
Junio C Hamano 2016-09-08 21:35:51 -07:00
commit 7f5885ad2a
10 changed files with 112 additions and 90 deletions

View File

@ -405,13 +405,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::

View File

@ -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]

View File

@ -632,6 +632,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */
#define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */
extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
extern void update_index_if_able(struct index_state *, struct lock_file *);

View File

@ -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);
}
/*****************************************************************

View File

@ -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;

View File

@ -202,12 +202,21 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
const char *path, int stage, int refresh, int options)
{
struct cache_entry *ce;
ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage,
(refresh ? (CE_MATCH_REFRESH |
CE_MATCH_IGNORE_MISSING) : 0 ));
int ret;
ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, 0);
if (!ce)
return error(_("addinfo_cache failed for path '%s'"), path);
return add_cache_entry(ce, options);
ret = add_cache_entry(ce, options);
if (refresh) {
struct cache_entry *nce;
nce = refresh_cache_entry(ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
if (nce != ce)
ret = add_cache_entry(nce, options);
}
return ret;
}
static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)

View File

@ -19,9 +19,6 @@
#include "split-index.h"
#include "utf8.h"
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
unsigned int options);
/* Mask for the name length in ce_flags in the on-disk index */
#define CE_NAMEMASK (0x0fff)
@ -1257,7 +1254,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
return has_errors;
}
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
unsigned int options)
{
return refresh_cache_ent(&the_index, ce, options, NULL, NULL);

View File

@ -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' '

View File

@ -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

View File

@ -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,38 +88,49 @@ 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' '
test_expect_success 'Merge addition of text=auto eol=LF' '
git config core.eol lf &&
cat <<-\EOF >expected &&
first line
same line
EOF
if test_have_prereq NATIVE_CRLF; then
append_cr <expected >expected.temp &&
mv expected.temp expected
fi &&
git config merge.renormalize true &&
git rm -fr . &&
rm -f .gitattributes &&
git reset --hard b &&
git merge a &&
test_cmp expected file
compare_files expected file
'
test_expect_success 'Merge addition of text=auto eol=CRLF' '
git config core.eol crlf &&
cat <<-\EOF >expected &&
first line
same line
EOF
append_cr <expected >expected.temp &&
mv expected.temp expected &&
git config merge.renormalize true &&
git rm -fr . &&
rm -f .gitattributes &&
git reset --hard b &&
echo >&2 "After git reset --hard b" &&
git ls-files -s --eol >&2 &&
git merge a &&
compare_files expected file
'
test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '
git config core.eol native &&
echo "<<<<<<<" >expected &&
if test_have_prereq NATIVE_CRLF; then
echo first line | append_cr >>expected &&
echo same line | append_cr >>expected &&
echo ======= | append_cr >>expected
else
echo first line >>expected &&
echo same line >>expected &&
echo ======= >>expected
fi &&
echo first line >>expected &&
echo same line >>expected &&
echo ======= >>expected &&
echo first line | append_cr >>expected &&
echo same line | append_cr >>expected &&
echo ">>>>>>>" >>expected &&
@ -121,29 +139,23 @@ 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' '
echo "<<<<<<<" >expected &&
echo first line | append_cr >>expected &&
echo same line | append_cr >>expected &&
if test_have_prereq NATIVE_CRLF; then
echo ======= | append_cr >>expected &&
echo first line | append_cr >>expected &&
echo same line | append_cr >>expected
else
echo ======= >>expected &&
echo first line >>expected &&
echo same line >>expected
fi &&
echo ======= >>expected &&
echo first line >>expected &&
echo same line >>expected &&
echo ">>>>>>>" >>expected &&
git config merge.renormalize false &&
rm -f .gitattributes &&
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 +170,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 +185,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 +199,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' '