зеркало из https://github.com/microsoft/git.git
Merge branch 'eb/core-eol'
* eb/core-eol: Add "core.eol" config variable Rename the "crlf" attribute "text" Add per-repository eol normalization Add tests for per-repository eol normalization Conflicts: Documentation/config.txt Makefile
This commit is contained in:
Коммит
d5cff17eda
|
@ -196,20 +196,17 @@ core.quotepath::
|
|||
quoted without `-z` regardless of the setting of this
|
||||
variable.
|
||||
|
||||
core.autocrlf::
|
||||
If true, makes git convert `CRLF` at the end of lines in text files to
|
||||
`LF` when reading from the work tree, and convert in reverse when
|
||||
writing to the work tree. The variable can be set to
|
||||
'input', in which case the conversion happens only while
|
||||
reading from the work tree but files are written out to the work
|
||||
tree with `LF` at the end of lines. A file is considered
|
||||
"text" (i.e. be subjected to the autocrlf mechanism) based on
|
||||
the file's `crlf` attribute, or if `crlf` is unspecified,
|
||||
based on the file's contents. See linkgit:gitattributes[5].
|
||||
core.eol::
|
||||
Sets the line ending type to use in the working directory for
|
||||
files that have the `text` property set. Alternatives are
|
||||
'lf', 'crlf' and 'native', which uses the platform's native
|
||||
line ending. The default value is `native`. See
|
||||
linkgit:gitattributes[5] for more information on end-of-line
|
||||
conversion.
|
||||
|
||||
core.safecrlf::
|
||||
If true, makes git check if converting `CRLF` as controlled by
|
||||
`core.autocrlf` is reversible. Git will verify if a command
|
||||
If true, makes git check if converting `CRLF` is reversible when
|
||||
end-of-line conversion is active. Git will verify if a command
|
||||
modifies a file in the work tree either directly or indirectly.
|
||||
For example, committing a file followed by checking out the
|
||||
same file should yield the original file in the work tree. If
|
||||
|
@ -219,7 +216,7 @@ core.safecrlf::
|
|||
irreversible conversion but continue the operation.
|
||||
+
|
||||
CRLF conversion bears a slight chance of corrupting data.
|
||||
autocrlf=true will convert CRLF to LF during commit and LF to
|
||||
When it is enabled, git will convert CRLF to LF during commit and LF to
|
||||
CRLF during checkout. A file that contains a mixture of LF and
|
||||
CRLF before the commit cannot be recreated by git. For text
|
||||
files this is the right thing to do: it corrects line endings
|
||||
|
@ -243,15 +240,25 @@ converting CRLFs corrupts data.
|
|||
+
|
||||
Note, this safety check does not mean that a checkout will generate a
|
||||
file identical to the original file for a different setting of
|
||||
`core.autocrlf`, but only for the current one. For example, a text
|
||||
file with `LF` would be accepted with `core.autocrlf=input` and could
|
||||
later be checked out with `core.autocrlf=true`, in which case the
|
||||
`core.eol` and `core.autocrlf`, but only for the current one. For
|
||||
example, a text file with `LF` would be accepted with `core.eol=lf`
|
||||
and could later be checked out with `core.eol=crlf`, in which case the
|
||||
resulting file would contain `CRLF`, although the original file
|
||||
contained `LF`. However, in both work trees the line endings would be
|
||||
consistent, that is either all `LF` or all `CRLF`, but never mixed. A
|
||||
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',
|
||||
in which case no output conversion is performed.
|
||||
|
||||
core.symlinks::
|
||||
If false, symbolic links are checked out as small plain files that
|
||||
contain the link text. linkgit:git-update-index[1] and
|
||||
|
@ -979,13 +986,15 @@ gitcvs.logfile::
|
|||
various stuff. See linkgit:git-cvsserver[1].
|
||||
|
||||
gitcvs.usecrlfattr::
|
||||
If true, the server will look up the `crlf` attribute for
|
||||
files to determine the '-k' modes to use. If `crlf` is set,
|
||||
the '-k' mode will be left blank, so cvs clients will
|
||||
treat it as text. If `crlf` is explicitly unset, the file
|
||||
If true, the server will look up the end-of-line conversion
|
||||
attributes for files to determine the '-k' modes to use. If
|
||||
the attributes force git to treat a file as text,
|
||||
the '-k' mode will be left blank so cvs clients will
|
||||
treat it as text. If they suppress text conversion, the file
|
||||
will be set with '-kb' mode, which suppresses any newline munging
|
||||
the client might otherwise do. If `crlf` is not specified,
|
||||
then 'gitcvs.allbinary' is used. See linkgit:gitattributes[5].
|
||||
the client might otherwise do. If the attributes do not allow
|
||||
the file type to be determined, then 'gitcvs.allbinary' is
|
||||
used. See linkgit:gitattributes[5].
|
||||
|
||||
gitcvs.allbinary::
|
||||
This is used if 'gitcvs.usecrlfattr' does not resolve
|
||||
|
|
|
@ -369,16 +369,13 @@ By default the server leaves the '-k' mode blank for all files,
|
|||
which causes the cvs client to treat them as a text files, subject
|
||||
to crlf conversion on some platforms.
|
||||
|
||||
You can make the server use `crlf` attributes to set the '-k' modes
|
||||
for files by setting the `gitcvs.usecrlfattr` config variable.
|
||||
In this case, if `crlf` is explicitly unset ('-crlf'), then the
|
||||
server will set '-kb' mode for binary files. If `crlf` is set,
|
||||
then the '-k' mode will explicitly be left blank. See
|
||||
also linkgit:gitattributes[5] for more information about the `crlf`
|
||||
attribute.
|
||||
You can make the server use the end-of-line conversion attributes to
|
||||
set the '-k' modes for files by setting the `gitcvs.usecrlfattr`
|
||||
config variable. See linkgit:gitattributes[5] for more information
|
||||
about end-of-line conversion.
|
||||
|
||||
Alternatively, if `gitcvs.usecrlfattr` config is not enabled
|
||||
or if the `crlf` attribute is unspecified for a filename, then
|
||||
or the attributes do not allow automatic detection for a filename, then
|
||||
the server uses the `gitcvs.allbinary` config for the default setting.
|
||||
If `gitcvs.allbinary` is set, then file not otherwise
|
||||
specified will default to '-kb' mode. Otherwise the '-k' mode
|
||||
|
|
|
@ -92,53 +92,154 @@ such as 'git checkout' and 'git merge' run. They also affect how
|
|||
git stores the contents you prepare in the working tree in the
|
||||
repository upon 'git add' and 'git commit'.
|
||||
|
||||
`crlf`
|
||||
`text`
|
||||
^^^^^^
|
||||
|
||||
This attribute controls the line-ending convention.
|
||||
This attribute enables and controls end-of-line normalization. When a
|
||||
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.
|
||||
|
||||
Set::
|
||||
|
||||
Setting the `crlf` attribute on a path is meant to mark
|
||||
the path as a "text" file. 'core.autocrlf' conversion
|
||||
takes place without guessing the content type by
|
||||
inspection.
|
||||
Setting the `text` attribute on a path enables end-of-line
|
||||
normalization and marks the path as a text file. End-of-line
|
||||
conversion takes place without guessing the content type.
|
||||
|
||||
Unset::
|
||||
|
||||
Unsetting the `crlf` attribute on a path tells git not to
|
||||
Unsetting the `text` attribute on a path tells git not to
|
||||
attempt any end-of-line conversion upon checkin or checkout.
|
||||
|
||||
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.
|
||||
|
||||
Unspecified::
|
||||
|
||||
Unspecified `crlf` attribute tells git to apply the
|
||||
`core.autocrlf` conversion when the file content looks
|
||||
like text.
|
||||
If the `text` attribute is unspecified, git uses the
|
||||
`core.autocrlf` configuration variable to determine if the
|
||||
file should be converted.
|
||||
|
||||
Set to string value "input"::
|
||||
Any other value causes git to act as if `text` has been left
|
||||
unspecified.
|
||||
|
||||
This is similar to setting the attribute to `true`, but
|
||||
also forces git to act as if `core.autocrlf` is set to
|
||||
`input` for the path.
|
||||
`eol`
|
||||
^^^^^
|
||||
|
||||
Any other value set to `crlf` attribute is ignored and git acts
|
||||
as if the attribute is left unspecified.
|
||||
This attribute sets a specific line-ending style to be used in the
|
||||
working directory. It enables end-of-line normalization without any
|
||||
content checks, effectively setting the `text` attribute.
|
||||
|
||||
Set to string value "crlf"::
|
||||
|
||||
The `core.autocrlf` conversion
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
This setting forces git to normalize line endings for this
|
||||
file on checkin and convert them to CRLF when the file is
|
||||
checked out.
|
||||
|
||||
If the configuration variable `core.autocrlf` is false, no
|
||||
conversion is done.
|
||||
Set to string value "lf"::
|
||||
|
||||
When `core.autocrlf` is true, it means that the platform wants
|
||||
CRLF line endings for files in the working tree, and you want to
|
||||
convert them back to the normal LF line endings when checking
|
||||
in to the repository.
|
||||
This setting forces git to normalize line endings to LF on
|
||||
checkin and prevents conversion to CRLF when the file is
|
||||
checked out.
|
||||
|
||||
When `core.autocrlf` is set to "input", line endings are
|
||||
converted to LF upon checkin, but there is no conversion done
|
||||
upon checkout.
|
||||
Backwards compatibility with `crlf` attribute
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For backwards compatibility, the `crlf` attribute is interpreted as
|
||||
follows:
|
||||
|
||||
------------------------
|
||||
crlf text
|
||||
-crlf -text
|
||||
crlf=input eol=lf
|
||||
------------------------
|
||||
|
||||
End-of-line conversion
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While git normally leaves file contents alone, it can be configured to
|
||||
normalize line endings to LF in the repository and, optionally, to
|
||||
convert them to CRLF when files are checked out.
|
||||
|
||||
Here is an example that will make git normalize .txt, .vcproj and .sh
|
||||
files, ensure that .vcproj files have CRLF and .sh files have LF in
|
||||
the working directory, and prevent .jpg files from being normalized
|
||||
regardless of their content.
|
||||
|
||||
------------------------
|
||||
*.txt text
|
||||
*.vcproj eol=crlf
|
||||
*.sh eol=lf
|
||||
*.jpg -text
|
||||
------------------------
|
||||
|
||||
Other source code management systems normalize all text files in their
|
||||
repositories, and there are two ways to enable similar automatic
|
||||
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.
|
||||
|
||||
------------------------
|
||||
[core]
|
||||
autocrlf = true
|
||||
------------------------
|
||||
|
||||
This does not force normalization of all text files, but does ensure
|
||||
that text files that you introduce to the repository have their line
|
||||
endings normalized to LF when they are added, and that files that are
|
||||
already normalized in the repository stay normalized.
|
||||
|
||||
If you want to interoperate with a source code management system that
|
||||
enforces end-of-line normalization, or you simply want all text files
|
||||
in your repository to be normalized, you should instead set the `text`
|
||||
attribute to "auto" for _all_ files.
|
||||
|
||||
------------------------
|
||||
* text=auto
|
||||
------------------------
|
||||
|
||||
This ensures that all files that git considers to be text will have
|
||||
normalized (LF) line endings in the repository. The `core.eol`
|
||||
configuration variable controls which line endings git will use for
|
||||
normalized files in your working directory; the default is to use the
|
||||
native line ending for your platform, or CRLF if `core.autocrlf` is
|
||||
set.
|
||||
|
||||
NOTE: When `text=auto` normalization is enabled in an existing
|
||||
repository, any text files containing CRLFs should be normalized. If
|
||||
they are not they will be normalized the next time someone tries to
|
||||
change them, causing unfortunate misattribution. From a clean working
|
||||
directory:
|
||||
|
||||
-------------------------------------------------
|
||||
$ echo "* text=auto" >>.gitattributes
|
||||
$ rm .git/index # Remove the index to force git to
|
||||
$ git reset # re-scan the working directory
|
||||
$ git status # Show files that will be normalized
|
||||
$ git add -u
|
||||
$ git add .gitattributes
|
||||
$ git commit -m "Introduce end-of-line normalization"
|
||||
-------------------------------------------------
|
||||
|
||||
If any files that should not be normalized show up in 'git status',
|
||||
unset their `text` attribute before running 'git add -u'.
|
||||
|
||||
------------------------
|
||||
manual.pdf -text
|
||||
------------------------
|
||||
|
||||
Conversely, text files that git does not detect can have normalization
|
||||
enabled manually.
|
||||
|
||||
------------------------
|
||||
weirdchars.txt text
|
||||
------------------------
|
||||
|
||||
If `core.safecrlf` is set to "true" or "warn", git verifies if
|
||||
the conversion is reversible for the current setting of
|
||||
|
@ -223,11 +324,11 @@ Interaction between checkin/checkout attributes
|
|||
In the check-in codepath, the worktree file is first converted
|
||||
with `filter` driver (if specified and corresponding driver
|
||||
defined), then the result is processed with `ident` (if
|
||||
specified), and then finally with `crlf` (again, if specified
|
||||
specified), and then finally with `text` (again, if specified
|
||||
and applicable).
|
||||
|
||||
In the check-out codepath, the blob content is first converted
|
||||
with `crlf`, and then `ident` and fed to `filter`.
|
||||
with `text`, and then `ident` and fed to `filter`.
|
||||
|
||||
|
||||
Generating diff text
|
||||
|
@ -651,7 +752,7 @@ You do not want any end-of-line conversions applied to, nor textual diffs
|
|||
produced for, any binary file you track. You would need to specify e.g.
|
||||
|
||||
------------
|
||||
*.jpg -crlf -diff
|
||||
*.jpg -text -diff
|
||||
------------
|
||||
|
||||
but that may become cumbersome, when you have many attributes. Using
|
||||
|
@ -664,7 +765,7 @@ the same time. The system knows a built-in attribute macro, `binary`:
|
|||
|
||||
which is equivalent to the above. Note that the attribute macros can only
|
||||
be "Set" (see the above example that sets "binary" macro as if it were an
|
||||
ordinary attribute --- setting it in turn unsets "crlf" and "diff").
|
||||
ordinary attribute --- setting it in turn unsets "text" and "diff").
|
||||
|
||||
|
||||
DEFINING ATTRIBUTE MACROS
|
||||
|
@ -675,7 +776,7 @@ at the toplevel (i.e. not in any subdirectory). The built-in attribute
|
|||
macro "binary" is equivalent to:
|
||||
|
||||
------------
|
||||
[attr]binary -diff -crlf
|
||||
[attr]binary -diff -text
|
||||
------------
|
||||
|
||||
|
||||
|
|
3
Makefile
3
Makefile
|
@ -233,6 +233,8 @@ all::
|
|||
#
|
||||
# Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
|
||||
# dependency rules.
|
||||
#
|
||||
# Define NATIVE_CRLF if your platform uses CRLF for line endings.
|
||||
|
||||
GIT-VERSION-FILE: FORCE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
|
@ -1056,6 +1058,7 @@ ifeq ($(uname_S),Windows)
|
|||
NO_CURL = YesPlease
|
||||
NO_PYTHON = YesPlease
|
||||
BLK_SHA1 = YesPlease
|
||||
NATIVE_CRLF = YesPlease
|
||||
|
||||
CC = compat/vcbuild/scripts/clink.pl
|
||||
AR = compat/vcbuild/scripts/lib.pl
|
||||
|
|
2
attr.c
2
attr.c
|
@ -287,7 +287,7 @@ static void free_attr_elem(struct attr_stack *e)
|
|||
}
|
||||
|
||||
static const char *builtin_attr[] = {
|
||||
"[attr]binary -diff -crlf",
|
||||
"[attr]binary -diff -text",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
22
cache.h
22
cache.h
|
@ -547,7 +547,6 @@ extern int core_compression_seen;
|
|||
extern size_t packed_git_window_size;
|
||||
extern size_t packed_git_limit;
|
||||
extern size_t delta_base_cache_limit;
|
||||
extern int auto_crlf;
|
||||
extern int read_replace_refs;
|
||||
extern int fsync_object_files;
|
||||
extern int core_preload_index;
|
||||
|
@ -561,6 +560,27 @@ enum safe_crlf {
|
|||
|
||||
extern enum safe_crlf safe_crlf;
|
||||
|
||||
enum auto_crlf {
|
||||
AUTO_CRLF_FALSE = 0,
|
||||
AUTO_CRLF_TRUE = 1,
|
||||
AUTO_CRLF_INPUT = -1,
|
||||
};
|
||||
|
||||
extern enum auto_crlf auto_crlf;
|
||||
|
||||
enum eol {
|
||||
EOL_UNSET,
|
||||
EOL_CRLF,
|
||||
EOL_LF,
|
||||
#ifdef NATIVE_CRLF
|
||||
EOL_NATIVE = EOL_CRLF
|
||||
#else
|
||||
EOL_NATIVE = EOL_LF
|
||||
#endif
|
||||
};
|
||||
|
||||
extern enum eol eol;
|
||||
|
||||
enum branch_track {
|
||||
BRANCH_TRACK_UNSPECIFIED = -1,
|
||||
BRANCH_TRACK_NEVER = 0,
|
||||
|
|
18
config.c
18
config.c
|
@ -517,7 +517,9 @@ static int git_default_core_config(const char *var, const char *value)
|
|||
|
||||
if (!strcmp(var, "core.autocrlf")) {
|
||||
if (value && !strcasecmp(value, "input")) {
|
||||
auto_crlf = -1;
|
||||
if (eol == EOL_CRLF)
|
||||
return error("core.autocrlf=input conflicts with core.eol=crlf");
|
||||
auto_crlf = AUTO_CRLF_INPUT;
|
||||
return 0;
|
||||
}
|
||||
auto_crlf = git_config_bool(var, value);
|
||||
|
@ -533,6 +535,20 @@ static int git_default_core_config(const char *var, const char *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.eol")) {
|
||||
if (value && !strcasecmp(value, "lf"))
|
||||
eol = EOL_LF;
|
||||
else if (value && !strcasecmp(value, "crlf"))
|
||||
eol = EOL_CRLF;
|
||||
else if (value && !strcasecmp(value, "native"))
|
||||
eol = EOL_NATIVE;
|
||||
else
|
||||
eol = EOL_UNSET;
|
||||
if (eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)
|
||||
return error("core.autocrlf=input conflicts with core.eol=crlf");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.notesref")) {
|
||||
notes_ref_name = xstrdup(value);
|
||||
return 0;
|
||||
|
|
150
convert.c
150
convert.c
|
@ -8,13 +8,17 @@
|
|||
* This should use the pathname to decide on whether it wants to do some
|
||||
* more interesting conversions (automatic gzip/unzip, general format
|
||||
* conversions etc etc), but by default it just does automatic CRLF<->LF
|
||||
* translation when the "auto_crlf" option is set.
|
||||
* translation when the "text" attribute or "auto_crlf" option is set.
|
||||
*/
|
||||
|
||||
#define CRLF_GUESS (-1)
|
||||
#define CRLF_BINARY 0
|
||||
#define CRLF_TEXT 1
|
||||
#define CRLF_INPUT 2
|
||||
enum action {
|
||||
CRLF_GUESS = -1,
|
||||
CRLF_BINARY = 0,
|
||||
CRLF_TEXT,
|
||||
CRLF_INPUT,
|
||||
CRLF_CRLF,
|
||||
CRLF_AUTO,
|
||||
};
|
||||
|
||||
struct text_stat {
|
||||
/* NUL, CR, LF and CRLF counts */
|
||||
|
@ -89,31 +93,55 @@ static int is_binary(unsigned long size, struct text_stat *stats)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void check_safe_crlf(const char *path, int action,
|
||||
static enum eol determine_output_conversion(enum action action) {
|
||||
switch (action) {
|
||||
case CRLF_BINARY:
|
||||
return EOL_UNSET;
|
||||
case CRLF_CRLF:
|
||||
return EOL_CRLF;
|
||||
case CRLF_INPUT:
|
||||
return EOL_LF;
|
||||
case CRLF_GUESS:
|
||||
if (!auto_crlf)
|
||||
return EOL_UNSET;
|
||||
/* fall through */
|
||||
case CRLF_TEXT:
|
||||
case CRLF_AUTO:
|
||||
if (auto_crlf == AUTO_CRLF_TRUE)
|
||||
return EOL_CRLF;
|
||||
else if (auto_crlf == AUTO_CRLF_INPUT)
|
||||
return EOL_LF;
|
||||
else if (eol == EOL_UNSET)
|
||||
return EOL_NATIVE;
|
||||
}
|
||||
return eol;
|
||||
}
|
||||
|
||||
static void check_safe_crlf(const char *path, enum action action,
|
||||
struct text_stat *stats, enum safe_crlf checksafe)
|
||||
{
|
||||
if (!checksafe)
|
||||
return;
|
||||
|
||||
if (action == CRLF_INPUT || auto_crlf <= 0) {
|
||||
if (determine_output_conversion(action) == EOL_LF) {
|
||||
/*
|
||||
* CRLFs would not be restored by checkout:
|
||||
* check if we'd remove CRLFs
|
||||
*/
|
||||
if (stats->crlf) {
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("CRLF will be replaced by LF in %s.", path);
|
||||
warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("CRLF would be replaced by LF in %s.", path);
|
||||
}
|
||||
} else if (auto_crlf > 0) {
|
||||
} else if (determine_output_conversion(action) == EOL_CRLF) {
|
||||
/*
|
||||
* CRLFs would be added by checkout:
|
||||
* check if we have "naked" LFs
|
||||
*/
|
||||
if (stats->lf != stats->crlf) {
|
||||
if (checksafe == SAFE_CRLF_WARN)
|
||||
warning("LF will be replaced by CRLF in %s", path);
|
||||
warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path);
|
||||
else /* i.e. SAFE_CRLF_FAIL */
|
||||
die("LF would be replaced by CRLF in %s", path);
|
||||
}
|
||||
|
@ -158,17 +186,18 @@ static int has_cr_in_index(const char *path)
|
|||
}
|
||||
|
||||
static int crlf_to_git(const char *path, const char *src, size_t len,
|
||||
struct strbuf *buf, int action, enum safe_crlf checksafe)
|
||||
struct strbuf *buf, enum action action, enum safe_crlf checksafe)
|
||||
{
|
||||
struct text_stat stats;
|
||||
char *dst;
|
||||
|
||||
if ((action == CRLF_BINARY) || !auto_crlf || !len)
|
||||
if (action == CRLF_BINARY ||
|
||||
(action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || !len)
|
||||
return 0;
|
||||
|
||||
gather_stats(src, len, &stats);
|
||||
|
||||
if (action == CRLF_GUESS) {
|
||||
if (action == CRLF_AUTO || action == CRLF_GUESS) {
|
||||
/*
|
||||
* We're currently not going to even try to convert stuff
|
||||
* that has bare CR characters. Does anybody do that crazy
|
||||
|
@ -183,12 +212,14 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
|
|||
if (is_binary(len, &stats))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 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 (action == CRLF_GUESS) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
check_safe_crlf(path, action, &stats, checksafe);
|
||||
|
@ -201,7 +232,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
|
|||
if (strbuf_avail(buf) + buf->len < len)
|
||||
strbuf_grow(buf, len - buf->len);
|
||||
dst = buf->buf;
|
||||
if (action == CRLF_GUESS) {
|
||||
if (action == CRLF_AUTO || action == CRLF_GUESS) {
|
||||
/*
|
||||
* If we guessed, we already know we rejected a file with
|
||||
* lone CR, and we can strip a CR without looking at what
|
||||
|
@ -224,16 +255,12 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
|
|||
}
|
||||
|
||||
static int crlf_to_worktree(const char *path, const char *src, size_t len,
|
||||
struct strbuf *buf, int action)
|
||||
struct strbuf *buf, enum action action)
|
||||
{
|
||||
char *to_free = NULL;
|
||||
struct text_stat stats;
|
||||
|
||||
if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
|
||||
auto_crlf <= 0)
|
||||
return 0;
|
||||
|
||||
if (!len)
|
||||
if (!len || determine_output_conversion(action) != EOL_CRLF)
|
||||
return 0;
|
||||
|
||||
gather_stats(src, len, &stats);
|
||||
|
@ -246,11 +273,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,
|
|||
if (stats.lf == stats.crlf)
|
||||
return 0;
|
||||
|
||||
if (action == CRLF_GUESS) {
|
||||
/* If we have any CR or CRLF line endings, we do not touch it */
|
||||
/* This is the new safer autocrlf-handling */
|
||||
if (stats.cr > 0 || stats.crlf > 0)
|
||||
return 0;
|
||||
if (action == CRLF_AUTO || action == CRLF_GUESS) {
|
||||
if (action == CRLF_GUESS) {
|
||||
/* If we have any CR or CRLF line endings, we do not touch it */
|
||||
/* This is the new safer autocrlf-handling */
|
||||
if (stats.cr > 0 || stats.crlf > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we have any bare CR characters, we're not going to touch it */
|
||||
if (stats.cr != stats.crlf)
|
||||
|
@ -425,12 +454,16 @@ static int read_convert_config(const char *var, const char *value, void *cb)
|
|||
|
||||
static void setup_convert_check(struct git_attr_check *check)
|
||||
{
|
||||
static struct git_attr *attr_text;
|
||||
static struct git_attr *attr_crlf;
|
||||
static struct git_attr *attr_eol;
|
||||
static struct git_attr *attr_ident;
|
||||
static struct git_attr *attr_filter;
|
||||
|
||||
if (!attr_crlf) {
|
||||
if (!attr_text) {
|
||||
attr_text = git_attr("text");
|
||||
attr_crlf = git_attr("crlf");
|
||||
attr_eol = git_attr("eol");
|
||||
attr_ident = git_attr("ident");
|
||||
attr_filter = git_attr("filter");
|
||||
user_convert_tail = &user_convert;
|
||||
|
@ -439,6 +472,8 @@ static void setup_convert_check(struct git_attr_check *check)
|
|||
check[0].attr = attr_crlf;
|
||||
check[1].attr = attr_ident;
|
||||
check[2].attr = attr_filter;
|
||||
check[3].attr = attr_eol;
|
||||
check[4].attr = attr_text;
|
||||
}
|
||||
|
||||
static int count_ident(const char *cp, unsigned long size)
|
||||
|
@ -619,9 +654,24 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check)
|
|||
;
|
||||
else if (!strcmp(value, "input"))
|
||||
return CRLF_INPUT;
|
||||
else if (!strcmp(value, "auto"))
|
||||
return CRLF_AUTO;
|
||||
return CRLF_GUESS;
|
||||
}
|
||||
|
||||
static int git_path_check_eol(const char *path, struct git_attr_check *check)
|
||||
{
|
||||
const char *value = check->value;
|
||||
|
||||
if (ATTR_UNSET(value))
|
||||
;
|
||||
else if (!strcmp(value, "lf"))
|
||||
return EOL_LF;
|
||||
else if (!strcmp(value, "crlf"))
|
||||
return EOL_CRLF;
|
||||
return EOL_UNSET;
|
||||
}
|
||||
|
||||
static struct convert_driver *git_path_check_convert(const char *path,
|
||||
struct git_attr_check *check)
|
||||
{
|
||||
|
@ -643,20 +693,34 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
|
|||
return !!ATTR_TRUE(value);
|
||||
}
|
||||
|
||||
enum action determine_action(enum action text_attr, enum eol eol_attr) {
|
||||
if (text_attr == CRLF_BINARY)
|
||||
return CRLF_BINARY;
|
||||
if (eol_attr == EOL_LF)
|
||||
return CRLF_INPUT;
|
||||
if (eol_attr == EOL_CRLF)
|
||||
return CRLF_CRLF;
|
||||
return text_attr;
|
||||
}
|
||||
|
||||
int convert_to_git(const char *path, const char *src, size_t len,
|
||||
struct strbuf *dst, enum safe_crlf checksafe)
|
||||
{
|
||||
struct git_attr_check check[3];
|
||||
int crlf = CRLF_GUESS;
|
||||
struct git_attr_check check[5];
|
||||
enum action action = CRLF_GUESS;
|
||||
enum eol eol_attr = EOL_UNSET;
|
||||
int ident = 0, ret = 0;
|
||||
const char *filter = NULL;
|
||||
|
||||
setup_convert_check(check);
|
||||
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
||||
struct convert_driver *drv;
|
||||
crlf = git_path_check_crlf(path, check + 0);
|
||||
action = git_path_check_crlf(path, check + 4);
|
||||
if (action == CRLF_GUESS)
|
||||
action = git_path_check_crlf(path, check + 0);
|
||||
ident = git_path_check_ident(path, check + 1);
|
||||
drv = git_path_check_convert(path, check + 2);
|
||||
eol_attr = git_path_check_eol(path, check + 3);
|
||||
if (drv && drv->clean)
|
||||
filter = drv->clean;
|
||||
}
|
||||
|
@ -666,7 +730,8 @@ int convert_to_git(const char *path, const char *src, size_t len,
|
|||
src = dst->buf;
|
||||
len = dst->len;
|
||||
}
|
||||
ret |= crlf_to_git(path, src, len, dst, crlf, checksafe);
|
||||
action = determine_action(action, eol_attr);
|
||||
ret |= crlf_to_git(path, src, len, dst, action, checksafe);
|
||||
if (ret) {
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
|
@ -676,17 +741,21 @@ int convert_to_git(const char *path, const char *src, size_t len,
|
|||
|
||||
int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
|
||||
{
|
||||
struct git_attr_check check[3];
|
||||
int crlf = CRLF_GUESS;
|
||||
struct git_attr_check check[5];
|
||||
enum action action = CRLF_GUESS;
|
||||
enum eol eol_attr = EOL_UNSET;
|
||||
int ident = 0, ret = 0;
|
||||
const char *filter = NULL;
|
||||
|
||||
setup_convert_check(check);
|
||||
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
|
||||
struct convert_driver *drv;
|
||||
crlf = git_path_check_crlf(path, check + 0);
|
||||
action = git_path_check_crlf(path, check + 4);
|
||||
if (action == CRLF_GUESS)
|
||||
action = git_path_check_crlf(path, check + 0);
|
||||
ident = git_path_check_ident(path, check + 1);
|
||||
drv = git_path_check_convert(path, check + 2);
|
||||
eol_attr = git_path_check_eol(path, check + 3);
|
||||
if (drv && drv->smudge)
|
||||
filter = drv->smudge;
|
||||
}
|
||||
|
@ -696,7 +765,8 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc
|
|||
src = dst->buf;
|
||||
len = dst->len;
|
||||
}
|
||||
ret |= crlf_to_worktree(path, src, len, dst, crlf);
|
||||
action = determine_action(action, eol_attr);
|
||||
ret |= crlf_to_worktree(path, src, len, dst, action);
|
||||
if (ret) {
|
||||
src = dst->buf;
|
||||
len = dst->len;
|
||||
|
|
|
@ -38,8 +38,9 @@ const char *pager_program;
|
|||
int pager_use_color = 1;
|
||||
const char *editor_program;
|
||||
const char *excludes_file;
|
||||
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||
enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
|
||||
int read_replace_refs = 1;
|
||||
enum eol eol = EOL_UNSET;
|
||||
enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
|
||||
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
|
||||
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
|
||||
|
|
|
@ -2415,15 +2415,20 @@ sub kopts_from_path
|
|||
if ( defined ( $cfg->{gitcvs}{usecrlfattr} ) and
|
||||
$cfg->{gitcvs}{usecrlfattr} =~ /\s*(1|true|yes)\s*$/i )
|
||||
{
|
||||
my ($val) = check_attr( "crlf", $path );
|
||||
if ( $val eq "set" )
|
||||
my ($val) = check_attr( "text", $path );
|
||||
if ( $val eq "unspecified" )
|
||||
{
|
||||
return "";
|
||||
$val = check_attr( "crlf", $path );
|
||||
}
|
||||
elsif ( $val eq "unset" )
|
||||
if ( $val eq "unset" )
|
||||
{
|
||||
return "-kb"
|
||||
}
|
||||
elsif ( check_attr( "eol", $path ) ne "unspecified" ||
|
||||
$val eq "set" || $val eq "input" )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
$log->info("Unrecognized check_attr crlf $path : $val");
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='CRLF conversion'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
has_cr() {
|
||||
tr '\015' Q <"$1" | grep Q >/dev/null
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
git config core.autocrlf false &&
|
||||
|
||||
for w in Hello world how are you; do echo $w; done >one &&
|
||||
for w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >two &&
|
||||
for w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >three &&
|
||||
git add . &&
|
||||
|
||||
git commit -m initial &&
|
||||
|
||||
one=`git rev-parse HEAD:one` &&
|
||||
two=`git rev-parse HEAD:two` &&
|
||||
three=`git rev-parse HEAD:three` &&
|
||||
|
||||
echo happy.
|
||||
'
|
||||
|
||||
test_expect_success 'default settings cause no changes' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
! has_cr one &&
|
||||
has_cr two &&
|
||||
onediff=`git diff one` &&
|
||||
twodiff=`git diff two` &&
|
||||
threediff=`git diff three` &&
|
||||
test -z "$onediff" -a -z "$twodiff" -a -z "$threediff"
|
||||
'
|
||||
|
||||
test_expect_success 'crlf=true causes a CRLF file to be normalized' '
|
||||
|
||||
# Backwards compatibility check
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
echo "two crlf" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
# Note, "normalized" means that git will normalize it if added
|
||||
has_cr two &&
|
||||
twodiff=`git diff two` &&
|
||||
test -n "$twodiff"
|
||||
'
|
||||
|
||||
test_expect_success 'text=true causes a CRLF file to be normalized' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
echo "two text" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
# Note, "normalized" means that git will normalize it if added
|
||||
has_cr two &&
|
||||
twodiff=`git diff two` &&
|
||||
test -n "$twodiff"
|
||||
'
|
||||
|
||||
test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
git config core.autocrlf false &&
|
||||
echo "one eol=crlf" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr one &&
|
||||
onediff=`git diff one` &&
|
||||
test -z "$onediff"
|
||||
'
|
||||
|
||||
test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=input' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
git config core.autocrlf input &&
|
||||
echo "one eol=crlf" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr one &&
|
||||
onediff=`git diff one` &&
|
||||
test -z "$onediff"
|
||||
'
|
||||
|
||||
test_expect_success 'eol=lf gives a normalized file LFs with autocrlf=true' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
git config core.autocrlf true &&
|
||||
echo "one eol=lf" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
! has_cr one &&
|
||||
onediff=`git diff one` &&
|
||||
test -z "$onediff"
|
||||
'
|
||||
|
||||
test_expect_success 'autocrlf=true does not normalize CRLF files' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
git config core.autocrlf true &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr one &&
|
||||
has_cr two &&
|
||||
onediff=`git diff one` &&
|
||||
twodiff=`git diff two` &&
|
||||
threediff=`git diff three` &&
|
||||
test -z "$onediff" -a -z "$twodiff" -a -z "$threediff"
|
||||
'
|
||||
|
||||
test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
git config core.autocrlf true &&
|
||||
echo "* text=auto" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr one &&
|
||||
has_cr two &&
|
||||
onediff=`git diff one` &&
|
||||
twodiff=`git diff two` &&
|
||||
threediff=`git diff three` &&
|
||||
test -z "$onediff" -a -n "$twodiff" -a -z "$threediff"
|
||||
'
|
||||
|
||||
test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
git config core.autocrlf true &&
|
||||
echo "* text=auto" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
! has_cr three &&
|
||||
threediff=`git diff three` &&
|
||||
test -z "$threediff"
|
||||
'
|
||||
|
||||
test_expect_success 'eol=crlf _does_ normalize binary files' '
|
||||
|
||||
rm -f .gitattributes tmp one two three &&
|
||||
echo "three eol=crlf" > .gitattributes &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr three &&
|
||||
threediff=`git diff three` &&
|
||||
test -z "$threediff"
|
||||
'
|
||||
|
||||
test_done
|
|
@ -0,0 +1,83 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='CRLF conversion'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
has_cr() {
|
||||
tr '\015' Q <"$1" | grep Q >/dev/null
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
git config core.autocrlf false &&
|
||||
|
||||
echo "one text" > .gitattributes
|
||||
|
||||
for w in Hello world how are you; do echo $w; done >one &&
|
||||
for w in I am very very fine thank you; do echo $w; done >two &&
|
||||
git add . &&
|
||||
|
||||
git commit -m initial &&
|
||||
|
||||
one=`git rev-parse HEAD:one` &&
|
||||
two=`git rev-parse HEAD:two` &&
|
||||
|
||||
echo happy.
|
||||
'
|
||||
|
||||
test_expect_success 'eol=lf puts LFs in normalized file' '
|
||||
|
||||
rm -f .gitattributes tmp one two &&
|
||||
git config core.eol lf &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
! has_cr one &&
|
||||
! has_cr two &&
|
||||
onediff=`git diff one` &&
|
||||
twodiff=`git diff two` &&
|
||||
test -z "$onediff" -a -z "$twodiff"
|
||||
'
|
||||
|
||||
test_expect_success 'eol=crlf puts CRLFs in normalized file' '
|
||||
|
||||
rm -f .gitattributes tmp one two &&
|
||||
git config core.eol crlf &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr one &&
|
||||
! has_cr two &&
|
||||
onediff=`git diff one` &&
|
||||
twodiff=`git diff two` &&
|
||||
test -z "$onediff" -a -z "$twodiff"
|
||||
'
|
||||
|
||||
test_expect_success 'autocrlf=true overrides eol=lf' '
|
||||
|
||||
rm -f .gitattributes tmp one two &&
|
||||
git config core.eol lf &&
|
||||
git config core.autocrlf true &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr one &&
|
||||
has_cr two &&
|
||||
onediff=`git diff one` &&
|
||||
twodiff=`git diff two` &&
|
||||
test -z "$onediff" -a -z "$twodiff"
|
||||
'
|
||||
|
||||
test_expect_success 'autocrlf=true overrides unset eol' '
|
||||
|
||||
rm -f .gitattributes tmp one two &&
|
||||
git config --unset-all core.eol &&
|
||||
git config core.autocrlf true &&
|
||||
git read-tree --reset -u HEAD &&
|
||||
|
||||
has_cr one &&
|
||||
has_cr two &&
|
||||
onediff=`git diff one` &&
|
||||
twodiff=`git diff two` &&
|
||||
test -z "$onediff" -a -z "$twodiff"
|
||||
'
|
||||
|
||||
test_done
|
Загрузка…
Ссылка в новой задаче