Add "core.eol" config variable
Introduce a new configuration variable, "core.eol", that allows the user to set which line endings to use for end-of-line-normalized files in the working directory. It defaults to "native", which means CRLF on Windows and LF everywhere else. Note that "core.autocrlf" overrides core.eol. This means that [core] autocrlf = true puts CRLFs in the working directory even if core.eol is set to "lf". Signed-off-by: Eyvind Bernhardsen <eyvind.bernhardsen@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Eyvind Bernhardsen committed
Jun 4, 2010 at 21:29 UTC
942e7747678ecf5f118ea5b2d0c763166de21f3a
8 files changed
+188
-51
Documentation/config.txt
+21
-14
@@ -191,16 +191,13 @@ core.quotepath::
191
quoted without `-z` regardless of the setting of this
192
variable.
193
194
-core.autocrlf::
195
- If true, makes git convert `CRLF` at the end of lines in text files to
196
- `LF` when reading from the filesystem, and convert in reverse when
197
- writing to the filesystem. The variable can be set to
198
- 'input', in which case the conversion happens only while
199
- reading from the filesystem but files are written out with
200
- `LF` at the end of lines. A file is considered
201
- "text" (i.e. be subjected to the autocrlf mechanism) based on
202
- the file's `text` attribute, or if `text` is unspecified,
203
- based on the file's contents. See linkgit:gitattributes[5].
194
+core.eol::
195
+ Sets the line ending type to use in the working directory for
196
+ files that have the `text` property set. Alternatives are
197
+ 'lf', 'crlf' and 'native', which uses the platform's native
198
+ line ending. The default value is `native`. See
199
+ linkgit:gitattributes[5] for more information on end-of-line
200
+ conversion.
201
202
core.safecrlf::
203
If true, makes git check if converting `CRLF` is reversible when
@@ -214,7 +211,7 @@ core.safecrlf::
211
irreversible conversion but continue the operation.
212
+
213
CRLF conversion bears a slight chance of corrupting data.
217
-autocrlf=true will convert CRLF to LF during commit and LF to
214
+When it is enabled, git will convert CRLF to LF during commit and LF to
215
CRLF during checkout. A file that contains a mixture of LF and
216
CRLF before the commit cannot be recreated by git. For text
217
files this is the right thing to do: it corrects line endings
@@ -238,15 +235,25 @@ converting CRLFs corrupts data.
235
+
236
Note, this safety check does not mean that a checkout will generate a
237
file identical to the original file for a different setting of
241
-`core.autocrlf`, but only for the current one. For example, a text
242
-file with `LF` would be accepted with `core.autocrlf=input` and could
243
-later be checked out with `core.autocrlf=true`, in which case the
238
+`core.eol` and `core.autocrlf`, but only for the current one. For
239
+example, a text file with `LF` would be accepted with `core.eol=lf`
240
+and could later be checked out with `core.eol=crlf`, in which case the
241
resulting file would contain `CRLF`, although the original file
242
contained `LF`. However, in both work trees the line endings would be
243
consistent, that is either all `LF` or all `CRLF`, but never mixed. A
244
file with mixed line endings would be reported by the `core.safecrlf`
245
mechanism.
246
247
+core.autocrlf::
248
+ Setting this variable to "true" is almost the same as setting
249
+ the `text` attribute to "auto" on all files except that text
250
+ files are not guaranteed to be normalized: files that contain
251
+ `CRLF` in the repository will not be touched. Use this
252
+ setting if you want to have `CRLF` line endings in your
253
+ working directory even though the repository does not have
254
+ normalized line endings. This variable can be set to 'input',
255
+ in which case no output conversion is performed.
256
+
257
core.symlinks::
258
If false, symbolic links are checked out as small plain files that
259
contain the link text. linkgit:git-update-index[1] and
Documentation/gitattributes.txt
+15
-13
@@ -99,7 +99,7 @@ This attribute enables and controls end-of-line normalization. When a
99
text file is normalized, its line endings are converted to LF in the
100
repository. To control what line ending style is used in the working
101
directory, use the `eol` attribute for a single file and the
102
-`core.autocrlf` configuration variable for all text files.
102
+`core.eol` configuration variable for all text files.
103
104
Set::
105
@@ -120,9 +120,9 @@ Set to string value "auto"::
120
121
Unspecified::
122
123
- If the `text` attribute is unspecified, git uses the `eol`
124
- attribute and the `core.autocrlf` configuration variable to
125
- determine if the file should be converted.
123
+ If the `text` attribute is unspecified, git uses the
124
+ `core.autocrlf` configuration variable to determine if the
125
+ file should be converted.
126
127
Any other value causes git to act as if `text` has been left
128
unspecified.
@@ -132,19 +132,19 @@ unspecified.
132
133
This attribute sets a specific line-ending style to be used in the
134
working directory. It enables end-of-line normalization without any
135
-content checks, similar to setting the `text` attribute.
135
+content checks, effectively setting the `text` attribute.
136
137
Set to string value "crlf"::
138
139
- This setting forces git to normalize line endings on checkin
140
- and convert them to CRLF when the file is checked out,
141
- regardless of `text` and `core.autocrlf`.
139
+ This setting forces git to normalize line endings for this
140
+ file on checkin and convert them to CRLF when the file is
141
+ checked out.
142
143
Set to string value "lf"::
144
145
This setting forces git to normalize line endings to LF on
146
checkin and prevents conversion to CRLF when the file is
147
- checked out, regardless of `text` and `core.autocrlf`.
147
+ checked out.
148
149
Backwards compatibility with `crlf` attribute
150
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,9 +193,7 @@ config variable "core.autocrlf" without changing any attributes.
193
This does not force normalization of all text files, but does ensure
194
that text files that you introduce to the repository have their line
195
endings normalized to LF when they are added, and that files that are
196
-already normalized in the repository stay normalized. You can also
197
-set `autocrlf` to "input" to have automatic normalization of new text
198
-files without conversion to CRLF in the working directory.
196
+already normalized in the repository stay normalized.
197
198
If you want to interoperate with a source code management system that
199
enforces end-of-line normalization, or you simply want all text files
@@ -207,7 +205,11 @@ attribute to "auto" for _all_ files.
205
------------------------
206
207
This ensures that all files that git considers to be text will have
210
-normalized (LF) line endings in the repository.
208
+normalized (LF) line endings in the repository. The `core.eol`
209
+configuration variable controls which line endings git will use for
210
+normalized files in your working directory; the default is to use the
211
+native line ending for your platform, or CRLF if `core.autocrlf` is
212
+set.
213
214
NOTE: When `text=auto` normalization is enabled in an existing
215
repository, any text files containing CRLFs should be normalized. If
Makefile
+3
@@ -214,6 +214,8 @@ all::
214
# DEFAULT_EDITOR='~/bin/vi',
215
# DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
216
# DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
217
+#
218
+# Define NATIVE_CRLF if your platform uses CRLF for line endings.
219
220
GIT-VERSION-FILE: FORCE
221
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -947,6 +949,7 @@ ifeq ($(uname_S),Windows)
949
NO_CURL = YesPlease
950
NO_PYTHON = YesPlease
951
BLK_SHA1 = YesPlease
952
+ NATIVE_CRLF = YesPlease
953
954
CC = compat/vcbuild/scripts/clink.pl
955
AR = compat/vcbuild/scripts/lib.pl
cache.h
+13
@@ -556,6 +556,19 @@ enum auto_crlf {
556
557
extern enum auto_crlf auto_crlf;
558
559
+enum eol {
560
+ EOL_UNSET,
561
+ EOL_CRLF,
562
+ EOL_LF,
563
+#ifdef NATIVE_CRLF
564
+ EOL_NATIVE = EOL_CRLF
565
+#else
566
+ EOL_NATIVE = EOL_LF
567
+#endif
568
+};
569
+
570
+extern enum eol eol;
571
+
572
enum branch_track {
573
BRANCH_TRACK_UNSPECIFIED = -1,
574
BRANCH_TRACK_NEVER = 0,
config.c
+16
@@ -461,6 +461,8 @@ static int git_default_core_config(const char *var, const char *value)
461
462
if (!strcmp(var, "core.autocrlf")) {
463
if (value && !strcasecmp(value, "input")) {
464
+ if (eol == EOL_CRLF)
465
+ return error("core.autocrlf=input conflicts with core.eol=crlf");
466
auto_crlf = AUTO_CRLF_INPUT;
467
return 0;
468
}
@@ -477,6 +479,20 @@ static int git_default_core_config(const char *var, const char *value)
479
return 0;
480
}
481
482
+ if (!strcmp(var, "core.eol")) {
483
+ if (value && !strcasecmp(value, "lf"))
484
+ eol = EOL_LF;
485
+ else if (value && !strcasecmp(value, "crlf"))
486
+ eol = EOL_CRLF;
487
+ else if (value && !strcasecmp(value, "native"))
488
+ eol = EOL_NATIVE;
489
+ else
490
+ eol = EOL_UNSET;
491
+ if (eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)
492
+ return error("core.autocrlf=input conflicts with core.eol=crlf");
493
+ return 0;
494
+ }
495
+
496
if (!strcmp(var, "core.notesref")) {
497
notes_ref_name = xstrdup(value);
498
return 0;
convert.c
+36
-24
@@ -8,7 +8,7 @@
8
* This should use the pathname to decide on whether it wants to do some
9
* more interesting conversions (automatic gzip/unzip, general format
10
* conversions etc etc), but by default it just does automatic CRLF<->LF
11
- * translation when the "crlf" attribute or "auto_crlf" option is set.
11
+ * translation when the "text" attribute or "auto_crlf" option is set.
12
*/
13
14
enum action {
@@ -20,12 +20,6 @@ enum action {
20
CRLF_AUTO,
21
};
22
23
-enum eol {
24
- EOL_UNSET,
25
- EOL_LF,
26
- EOL_CRLF,
27
-};
28
-
23
struct text_stat {
24
/* NUL, CR, LF and CRLF counts */
25
unsigned nul, cr, lf, crlf;
@@ -99,33 +93,55 @@ static int is_binary(unsigned long size, struct text_stat *stats)
93
return 0;
94
}
95
96
+static enum eol determine_output_conversion(enum action action) {
97
+ switch (action) {
98
+ case CRLF_BINARY:
99
+ return EOL_UNSET;
100
+ case CRLF_CRLF:
101
+ return EOL_CRLF;
102
+ case CRLF_INPUT:
103
+ return EOL_LF;
104
+ case CRLF_GUESS:
105
+ if (!auto_crlf)
106
+ return EOL_UNSET;
107
+ /* fall through */
108
+ case CRLF_TEXT:
109
+ case CRLF_AUTO:
110
+ if (auto_crlf == AUTO_CRLF_TRUE)
111
+ return EOL_CRLF;
112
+ else if (auto_crlf == AUTO_CRLF_INPUT)
113
+ return EOL_LF;
114
+ else if (eol == EOL_UNSET)
115
+ return EOL_NATIVE;
116
+ }
117
+ return eol;
118
+}
119
+
120
static void check_safe_crlf(const char *path, enum action action,
121
struct text_stat *stats, enum safe_crlf checksafe)
122
{
123
if (!checksafe)
124
return;
125
108
- if (action == CRLF_INPUT ||
109
- (action == CRLF_GUESS && auto_crlf == AUTO_CRLF_INPUT)) {
126
+ if (determine_output_conversion(action) == EOL_LF) {
127
/*
128
* CRLFs would not be restored by checkout:
129
* check if we'd remove CRLFs
130
*/
131
if (stats->crlf) {
132
if (checksafe == SAFE_CRLF_WARN)
116
- warning("CRLF will be replaced by LF in %s.", path);
133
+ warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.", path);
134
else /* i.e. SAFE_CRLF_FAIL */
135
die("CRLF would be replaced by LF in %s.", path);
136
}
120
- } else if (action == CRLF_CRLF ||
121
- (action == CRLF_GUESS && auto_crlf == AUTO_CRLF_TRUE)) {
137
+ } else if (determine_output_conversion(action) == EOL_CRLF) {
138
/*
139
* CRLFs would be added by checkout:
140
* check if we have "naked" LFs
141
*/
142
if (stats->lf != stats->crlf) {
143
if (checksafe == SAFE_CRLF_WARN)
128
- warning("LF will be replaced by CRLF in %s", path);
144
+ warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path);
145
else /* i.e. SAFE_CRLF_FAIL */
146
die("LF would be replaced by CRLF in %s", path);
147
}
@@ -244,11 +260,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,
260
char *to_free = NULL;
261
struct text_stat stats;
262
247
- if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
248
- (action != CRLF_CRLF && auto_crlf != AUTO_CRLF_TRUE))
249
- return 0;
250
-
251
- if (!len)
263
+ if (!len || determine_output_conversion(action) != EOL_CRLF)
264
return 0;
265
266
gather_stats(src, len, &stats);
@@ -669,7 +681,7 @@ int convert_to_git(const char *path, const char *src, size_t len,
681
{
682
struct git_attr_check check[5];
683
enum action action = CRLF_GUESS;
672
- enum eol eol = EOL_UNSET;
684
+ enum eol eol_attr = EOL_UNSET;
685
int ident = 0, ret = 0;
686
const char *filter = NULL;
687
@@ -681,7 +693,7 @@ int convert_to_git(const char *path, const char *src, size_t len,
693
action = git_path_check_crlf(path, check + 0);
694
ident = git_path_check_ident(path, check + 1);
695
drv = git_path_check_convert(path, check + 2);
684
- eol = git_path_check_eol(path, check + 3);
696
+ eol_attr = git_path_check_eol(path, check + 3);
697
if (drv && drv->clean)
698
filter = drv->clean;
699
}
@@ -691,7 +703,7 @@ int convert_to_git(const char *path, const char *src, size_t len,
703
src = dst->buf;
704
len = dst->len;
705
}
694
- action = determine_action(action, eol);
706
+ action = determine_action(action, eol_attr);
707
ret |= crlf_to_git(path, src, len, dst, action, checksafe);
708
if (ret) {
709
src = dst->buf;
@@ -704,7 +716,7 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc
716
{
717
struct git_attr_check check[5];
718
enum action action = CRLF_GUESS;
707
- enum eol eol = EOL_UNSET;
719
+ enum eol eol_attr = EOL_UNSET;
720
int ident = 0, ret = 0;
721
const char *filter = NULL;
722
@@ -716,7 +728,7 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc
728
action = git_path_check_crlf(path, check + 0);
729
ident = git_path_check_ident(path, check + 1);
730
drv = git_path_check_convert(path, check + 2);
719
- eol = git_path_check_eol(path, check + 3);
731
+ eol_attr = git_path_check_eol(path, check + 3);
732
if (drv && drv->smudge)
733
filter = drv->smudge;
734
}
@@ -726,7 +738,7 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc
738
src = dst->buf;
739
len = dst->len;
740
}
729
- action = determine_action(action, eol);
741
+ action = determine_action(action, eol_attr);
742
ret |= crlf_to_worktree(path, src, len, dst, action);
743
if (ret) {
744
src = dst->buf;
environment.c
+1
@@ -40,6 +40,7 @@ const char *editor_program;
40
const char *excludes_file;
41
enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
42
int read_replace_refs = 1;
43
+enum eol eol = EOL_UNSET;
44
enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
45
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
46
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
t/t0026-eol-config.sh
new
+83
@@ -0,0 +1,83 @@
1
+#!/bin/sh
2
+
3
+test_description='CRLF conversion'
4
+
5
+. ./test-lib.sh
6
+
7
+has_cr() {
8
+ tr '\015' Q <"$1" | grep Q >/dev/null
9
+}
10
+
11
+test_expect_success setup '
12
+
13
+ git config core.autocrlf false &&
14
+
15
+ echo "one text" > .gitattributes
16
+
17
+ for w in Hello world how are you; do echo $w; done >one &&
18
+ for w in I am very very fine thank you; do echo $w; done >two &&
19
+ git add . &&
20
+
21
+ git commit -m initial &&
22
+
23
+ one=`git rev-parse HEAD:one` &&
24
+ two=`git rev-parse HEAD:two` &&
25
+
26
+ echo happy.
27
+'
28
+
29
+test_expect_success 'eol=lf puts LFs in normalized file' '
30
+
31
+ rm -f .gitattributes tmp one two &&
32
+ git config core.eol lf &&
33
+ git read-tree --reset -u HEAD &&
34
+
35
+ ! has_cr one &&
36
+ ! has_cr two &&
37
+ onediff=`git diff one` &&
38
+ twodiff=`git diff two` &&
39
+ test -z "$onediff" -a -z "$twodiff"
40
+'
41
+
42
+test_expect_success 'eol=crlf puts CRLFs in normalized file' '
43
+
44
+ rm -f .gitattributes tmp one two &&
45
+ git config core.eol crlf &&
46
+ git read-tree --reset -u HEAD &&
47
+
48
+ has_cr one &&
49
+ ! has_cr two &&
50
+ onediff=`git diff one` &&
51
+ twodiff=`git diff two` &&
52
+ test -z "$onediff" -a -z "$twodiff"
53
+'
54
+
55
+test_expect_success 'autocrlf=true overrides eol=lf' '
56
+
57
+ rm -f .gitattributes tmp one two &&
58
+ git config core.eol lf &&
59
+ git config core.autocrlf true &&
60
+ git read-tree --reset -u HEAD &&
61
+
62
+ has_cr one &&
63
+ has_cr two &&
64
+ onediff=`git diff one` &&
65
+ twodiff=`git diff two` &&
66
+ test -z "$onediff" -a -z "$twodiff"
67
+'
68
+
69
+test_expect_success 'autocrlf=true overrides unset eol' '
70
+
71
+ rm -f .gitattributes tmp one two &&
72
+ git config --unset-all core.eol &&
73
+ git config core.autocrlf true &&
74
+ git read-tree --reset -u HEAD &&
75
+
76
+ has_cr one &&
77
+ has_cr two &&
78
+ onediff=`git diff one` &&
79
+ twodiff=`git diff two` &&
80
+ test -z "$onediff" -a -z "$twodiff"
81
+'
82
+
83
+test_done