ls-files: Add eol diagnostics
PATCH v8 1/1 ls-files: Add eol diagnostics
When working in a cross-platform environment, a user wants to check if text files are stored normalized in the repository and if .gitattributes are set appropriately.
Make it possible to let Git show the line endings in the index and in the working tree and the effective text/eol attributes.
The end of line ("eolinfo") are shown like this:
"binary" binary file "text-no-eol" text file without any EOL "text-lf" text file with LF "text-crlf" text file with CRLF
"text-crlf-lf" text file with mixed line endings.
The effective text/eol attribute is one of these:
"", "-text", "text", "text=auto", "eol=lf", "eol=crlf"
git ls-files --eol gives an output like this:
i/text-no-eol w/text-no-eol attr/text=auto t/t5100/empty i/binary w/binary attr/-text t/test-binary-2.png i/text-lf w/text-lf attr/eol=lf t/t5100/rfc2047-info-0007 i/text-lf w/text-crlf attr/eol=crlf doit.bat i/text-crlf-lf w/text-crlf-lf attr/ locale/XX.po
Add test cases in t0027, thanks to Junio C Hamano for the optimized grep-less sed expression.
---
Changes since v7:
- Remove the "may change" from commit message.
- Run make doc, improved git-ls-files.txt
Documentation/git-ls-files.txt | 23 +++++++++ builtin/ls-files.c | 19 +++++++ convert.c | 85 +++++++++++++++++++++++++++++++ convert.h | 3 ++ t/t0027-auto-crlf.sh | 112 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 230 insertions(+), 12 deletions(-)
Documentation/git-ls-files.txt +2 -0
@@ -12,6 +12,7 @@ SYNOPSIS 'git ls-files' [-z] [-t] [-v] (--[cached|deleted|others|ignored|stage|unmerged|killed|modified])* (-[c|d|o|i|s|u|k|m])* + [--eol] [-x <pattern>|--exclude=<pattern>] [-X <file>|--exclude-from=<file>] [--exclude-per-directory=<file>]
@@ -147,6 +148,19 @@ a space) at the start of each line: possible for manual inspection; the exact format may change at any time. +--eol:: + Show line endings ("eolinfo") and the text/eol attributes ("texteolattr") of
files.
+ "eolinfo" is the file content identification used by Git when
+ the "text" attribute is "auto", or core.autocrlf != false.
++
+"eolinfo" is either "" (when the the info is not available"), or one of "binary", +"text-no-eol", "text-lf", "text-crlf" or "text-crlf-lf".
++
+The "texteolattr" can be "", "-text", "text", "text=auto", "eol=lf", "eol=crlf". ++
+Both the content in the index ("i/") and the content in the working tree ("w/") +are shown for regular files, followed by the "texteolattr" ("attr/"). +
\--::
Do not interpret any more arguments as options.
@@ -161,6 +175,15 @@ which case it outputs:
[<tag> ]<mode> <object> <stage> <file>
+'git ls-files --eol' will show
+ i/<eolinfo> w/<eolinfo> attr/<eolattr> <file>
+
+'git ls-files --eol -o' will show
+ i/ w/<eolinfo> attr/<eolattr> <file>
+
+'git ls-files --eol -s' will show
+[<tag> ]<mode> <object> <stage> i/<eolinfo> w/<eolinfo> attr/<eolattr> <file> +
'git ls-files --unmerged' and 'git ls-files --stage' can be used to examine detailed information on unmerged paths.
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index b6a7cb0..9eacc64 100644
builtin/ls-files.c +16 -0
@@ -27,6 +27,7 @@ static int show_killed;static int show_valid_bit;static int line_terminator ='\n' ;static int debug_mode; +static int show_eol;static const char *prefix;static int max_prefix_len;
@@ -47,6 +48,21 @@ static const char *tag_modified = "";static const char *tag_skip_worktree ="" ;static const char *tag_resolve_undo ="" ; +static void write_eolinfo(const struct cache_entry *ce, const char *path) +{ +struct stat st; +const char *i_txt ="" ; +const char *w_txt ="" ; +if (!show_eol) +return ; +if (ce &&S_ISREG (ce->ce_mode)) + i_txt =get_cached_convert_stats_ascii (ce->name); +if (!lstat (path, &st) &&S_ISREG (st.st_mode)) + w_txt =get_wt_convert_stats_ascii (path); +printf ("i/%-13s w/%-13s attr/%-9s " , i_txt, w_txt, +get_convert_attr_ascii (path)); +} +static void write_name (const char *name) {/*
@@ -68,6 +84,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)return ;fputs (tag, stdout); +write_eolinfo (NULL , ent->name);write_name (ent->name); } @@ -170,6 +187,7 @@ static void show_ce_entry(const char *tag, const struct
cache_entry *ce)
find_unique_abbrev(ce->sha1,abbrev), ce_stage(ce));
}
+ write_eolinfo(ce, ce->name);
write_name(ce->name);
if (debug_mode) {
const struct stat_data *sd = &ce->ce_stat_data;
@@ -433,6 +451,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
OPT_BIT(0, "directory", &dir.flags,
N_("show 'other' directories' names only"), DIR_SHOW_OTHER_DIRECTORIES),
+ OPT_BOOL(0, "eol", &show_eol, N_("show line endings of files")),
OPT_NEGBIT(0, "empty-directory", &dir.flags,
N_("don't show empty directories"), DIR_HIDE_EMPTY_DIRECTORIES),
convert.c +4 -0
@@ -13,6 +13,11 @@* translation when the "text" attribute or "auto_crlf" option is set. */ +/* Stat bits: When BIN is set, the txt bits are unset */ +#define CONVERT_STAT_BITS_TXT_LF (1) +#define CONVERT_STAT_BITS_TXT_CRLF (2) +#define CONVERT_STAT_BITS_BIN (4) +enum crlf_action {CRLF_GUESS =-1 ,CRLF_BINARY =0 ,
@@ -95,6 +100,62 @@ static int is_binary(unsigned long size, struct text_stat
*stats)
return 0;
}
+static unsigned int gather_convert_stats(const char *data, unsigned long size)
+{
+ struct text_stat stats;
+ if (!data || !size)
+ return 0;
+ gather_stats(data, size, &stats);
+ if (is_binary(size, &stats) || stats.cr != stats.crlf)
+ return CONVERT_STAT_BITS_BIN;
+ else if (stats.crlf && stats.crlf == stats.lf)
+ return CONVERT_STAT_BITS_TXT_CRLF;
+ else if (stats.crlf && stats.lf)
+ return CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_TXT_LF;
+ else if (stats.lf)
+ return CONVERT_STAT_BITS_TXT_LF;
+ else
+ return 0;
+}
+
+static const char *gather_convert_stats_ascii(const char *data, unsigned long size) +{
+ unsigned int convert_stats = gather_convert_stats(data, size);
+
+ if (convert_stats & CONVERT_STAT_BITS_BIN)
+ return "binary";
+ switch (convert_stats) {
+ case CONVERT_STAT_BITS_TXT_LF:
+ return "text-lf";
+ case CONVERT_STAT_BITS_TXT_CRLF:
+ return "text-crlf";
+ case CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF:
+ return "text-crlf-lf";
+ default:
+ return "text-no-eol";
+ }
+}
+
+const char *get_cached_convert_stats_ascii(const char *path)
+{
+ const char *ret;
+ unsigned long sz;
+ void *data = read_blob_data_from_cache(path, &sz);
+ ret = gather_convert_stats_ascii(data, sz);
+ free(data);
+ return ret;
+}
+
+const char *get_wt_convert_stats_ascii(const char *path)
+{
+ const char *ret = "";
+ struct strbuf sb = STRBUF_INIT;
+ if (strbuf_read_file(&sb, path, 0) >= 0)
+ ret = gather_convert_stats_ascii(sb.buf, sb.len);
+ strbuf_release(&sb);
+ return ret;
+}
+
static enum eol output_eol(enum crlf_action crlf_action)
{
switch (crlf_action) {
@@ -777,6 +838,30 @@ int would_convert_to_git_filter_fd(const char *path)
return apply_filter(path, NULL, 0, -1, NULL, ca.drv->clean);
}
+const char *get_convert_attr_ascii(const char *path)
+{
+ struct conv_attrs ca;
+ enum crlf_action crlf_action;
+
+ convert_attrs(&ca, path);
+ crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
+ switch (crlf_action) {
+ case CRLF_GUESS:
+ return "";
+ case CRLF_BINARY:
+ return "-text";
+ case CRLF_TEXT:
+ return "text";
+ case CRLF_INPUT:
+ return "eol=lf";
+ case CRLF_CRLF:
+ return "eol=crlf";
+ case CRLF_AUTO:
+ return "text=auto";
+ }
+ return "";
+}
+
int convert_to_git(const char *path, const char *src, size_t len,
struct strbuf *dst, enum safe_crlf checksafe)
{
convert.h +3 -0
@@ -32,6 +32,9 @@ enum eol { };extern enum eol core_eol; +extern const char *get_cached_convert_stats_ascii (const char *path); +extern const char *get_wt_convert_stats_ascii (const char *path); +extern const char *get_convert_attr_ascii (const char *path);/* returns 1 if *dst was used */ extern int convert_to_git(const char *path, const char *src, size_t len,
t/t0027-auto-crlf.sh +46 -11
82 lines not on this page · raw message
Quoted 1 line
actual &&
+ test_cmp expect actual
+ "
test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf
gitattributes=$attr file=LF" "
compare_ws_file $pfx $lfname ${src}LF.txt
"
@@ -231,7 +270,41 @@ checkout_files () {
"
}
-#######
+# Test control characters
+# NUL SOH CR EOF==^Z
+test_expect_success 'ls-files --eol -o Text/Binary' '
+ test_when_finished "rm e expect actual TeBi_*" &&
+ STRT=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA &&
+ STR=$STRT$STRT$STRT$STRT &&
+ printf "${STR}BBB\001" >TeBi_127_S &&
+ printf "${STR}BBBB\001">TeBi_128_S &&
+ printf "${STR}BBB\032" >TeBi_127_E &&
+ printf "\032${STR}BBB" >TeBi_E_127 &&
+ printf "${STR}BBBB\000">TeBi_128_N &&
+ printf "${STR}BBB\012">TeBi_128_L &&
+ printf "${STR}BBB\015">TeBi_127_C &&
+ printf "${STR}BB\015\012" >TeBi_126_CL &&
+ printf "${STR}BB\015\012\015" >TeBi_126_CLC &&
+ cat >e <<-\EOF &&
+ i/ w/binary TeBi_127_S
+ i/ w/text-no-eol TeBi_128_S
+ i/ w/text-no-eol TeBi_127_E
+ i/ w/binary TeBi_E_127
+ i/ w/binary TeBi_128_N
+ i/ w/text-lf TeBi_128_L
+ i/ w/binary TeBi_127_C
+ i/ w/text-crlf TeBi_126_CL
+ i/ w/binary TeBi_126_CLC
+ EOF
+ sort <e >expect &&
+ git ls-files --eol -o |
+ sed -n -e "/TeBi_/{s!attr/[=a-z-]*!!g
+ s! *! !g
+ p
+ }" | sort >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup master' '
echo >.gitattributes &&
git checkout -b master &&
@@ -480,4 +553,19 @@ checkout_files native true "lf" LF CRLFCRLF_mix_LF LF_mix_CR
checkout_files native false "crlf" CRLF CRLF CRLF CRLF_mix_CR
CRLF_nul
checkout_files native true "crlf" CRLF CRLF CRLF CRLF_mix_CR
CRLF_nul
+# Should be the last test case: remove some files from the worktree
+# This test assumes that "rm" can remove staged files +test_expect_success 'ls-files --eol -d' "
+ rm crlf_false_attr__CRLF.txt crlf_false_attr__CRLF_mix_LF.txt
crlf_false_attr__LF.txt .gitattributes &&
+ cat >expect <<-\EOF &&
+ i/text-crlf w/ crlf_false_attr__CRLF.txt
+ i/text-crlf-lf w/ crlf_false_attr__CRLF_mix_LF.txt
+ i/text-lf w/ .gitattributes
+ i/text-lf w/ crlf_false_attr__LF.txt
+ EOF
+ git ls-files --eol -d | sed -e 's!attr/[=a-z-]*!!g' -e 's/ */ /g' | sort
Quoted 1 line
actual &&
+ test_cmp expect actual &&
+ rm expect actual
+"
+
test_done
Signature · 1 line
2.5.0
Quoted 59 lines · Torsten Bögershausen
When working in a cross-platform environment, a user wants to check if text files are stored normalized in the repository and if .gitattributes are set appropriately.
Make it possible to let Git show the line endings in the index and in the working tree and the effective text/eol attributes.
The end of line ("eolinfo") are shown like this:
"binary" binary file "text-no-eol" text file without any EOL "text-lf" text file with LF "text-crlf" text file with CRLF"text-crlf-lf" text file with mixed line endings.
The effective text/eol attribute is one of these:
"", "-text", "text", "text=auto", "eol=lf", "eol=crlf"git ls-files --eol gives an output like this:
i/text-no-eol w/text-no-eol attr/text=auto t/t5100/empty i/binary w/binary attr/-text t/test-binary-2.png i/text-lf w/text-lf attr/eol=lf t/t5100/rfc2047-info-0007 i/text-lf w/text-crlf attr/eol=crlf doit.bat i/text-crlf-lf w/text-crlf-lf attr/ locale/XX.poAdd test cases in t0027, thanks to Junio C Hamano for the optimized grep-less sed expression.
Helped-By Eric Sunshine <[email protected]>Signed-off-by Torsten Bögershausen <[email protected]>---
Changes since v7:
- Remove the "may change" from commit message.
- Run make doc, improved git-ls-files.txtDocumentation/git-ls-files.txt | 23 +++++++++ builtin/ls-files.c | 19 +++++++ convert.c | 85 +++++++++++++++++++++++++++++++ convert.h | 3 ++ t/t0027-auto-crlf.sh | 112 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 230 insertions(+), 12 deletions(-)Documentation/git-ls-files.txt +2
-0@@ -12,6 +12,7 @@ SYNOPSIS 'git ls-files' [-z] [-t] [-v] (--[cached|deleted|others|ignored|stage|unmerged|killed|modified])* (-[c|d|o|i|s|u|k|m])* + [--eol] [-x <pattern>|--exclude=<pattern>] [-X <file>|--exclude-from=<file>] [--exclude-per-directory=<file>]@@ -147,6 +148,19 @@ a space) at the start of each line: possible for manual inspection; the exact format may change at any time. +--eol:: + Show line endings ("eolinfo") and the text/eol attributes ("texteolattr") offiles.
Documentation/git-ls-files.txt
Quoted 5 lines
Documentation/git-ls-files.txt +5
-0+ "eolinfo" is the file content identification used by Git when + the "text" attribute is "auto", or core.autocrlf != false. ++ +"eolinfo" is either "" (when the the info is not available"), or one of "binary", +"text-no-eol", "text-lf", "text-crlf" or "text-crlf-lf".
<bikeshedding>
Again, I think this list reads better as: binary, none, lf, crlf and mixed.
If you prefer to have 'text' in there somewhere, how about:
binary, text-none, text-lf, text-crlf, text-mixed.
:-D
(I promise not the mention it again!)
</bikeshedding>
ATB,
Ramsay Jones
Quoted 9 lines
Quoted 5 lines
"binary" binary file "text-no-eol" text file without any EOL "text-lf" text file with LF "text-crlf" text file with CRLF"text-crlf-lf" text file with mixed line endings.
If you prefer to have 'text' in there somewhere, how about:
binary, text-none, text-lf, text-crlf, text-mixed.
text-none could be OK.
text-mixed as well, but the you can't run
"git ls-files | grep i/text-crlf"
any more to get an impression if there are un-normalized files, which may, may, need normalization.
Thanks for the reminder,
lets wait a couple of days and see if there are more voices.
Quoted 10 lines · Ramsay Jones
Review
Quoted 7 lines
Documentation/git-ls-files.txt +1
-0+ Show line endings ("eolinfo") and the text/eol attributes ("texteolattr") offiles.
(quoted diff) +5
-0+ "eolinfo" is the file content identification used by Git when + the "text" attribute is "auto", or core.autocrlf != false. ++ +"eolinfo" is either "" (when the the info is not available"), or one of "binary", +"text-no-eol", "text-lf", "text-crlf" or "text-crlf-lf".<bikeshedding>
Quoted 7 lines
Again, I think this list reads better as: binary, none, lf, crlf and mixed.
If you prefer to have 'text' in there somewhere, how about:
binary, text-none, text-lf, text-crlf, text-mixed.
:-D
Yup, these shorter ones, especially without "text-" prefix, read easier to humans; scripts won't mind either way, so I'd prefer that shorter version.
Thanks for reminding the thread.
Quoted 2 lines · Torsten Bögershausen
Add test cases in t0027, thanks to Junio C Hamano for the optimized grep-less sed expression.
Please drop this part; it is embarrassing.
You wouldn't thank all the mentors you have ever had from whom you learned programming in your log messages, either ;-)