Skip to content

Commit 1d5f62e

Browse files
committed
Merge branch 'jc/whitespace-incomplete-line' into next
It does not make much sense to apply the "incomplete-line" whitespace rule to symbolic links, whose contents almost always lack the final newline. "git apply" and "git diff" are now taught to exclude them for a change to symbolic links. * jc/whitespace-incomplete-line: whitespace: symbolic links usually lack LF at the end
2 parents a386d47 + 6a41481 commit 1d5f62e

4 files changed

Lines changed: 152 additions & 2 deletions

File tree

apply.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,26 @@ static int parse_fragment(struct apply_state *state,
17251725
unsigned long oldlines, newlines;
17261726
unsigned long leading, trailing;
17271727

1728+
/* do not complain a symbolic link being an incomplete line */
1729+
if (patch->ws_rule & WS_INCOMPLETE_LINE) {
1730+
/*
1731+
* We want to figure out if the postimage is a
1732+
* symbolic link when applying the patch normally, or
1733+
* if the preimage is a symbolic link when applying
1734+
* the patch in reverse. A normal patch only has
1735+
* old_mode without new_mode. If it changes the
1736+
* filemode, new_mode has value, which is different
1737+
* from old_mode.
1738+
*/
1739+
unsigned mode = (state->apply_in_reverse
1740+
? patch->old_mode
1741+
: patch->new_mode
1742+
? patch->new_mode
1743+
: patch->old_mode);
1744+
if (mode && S_ISLNK(mode))
1745+
patch->ws_rule &= ~WS_INCOMPLETE_LINE;
1746+
}
1747+
17281748
offset = parse_fragment_header(line, len, fragment);
17291749
if (offset < 0)
17301750
return -1;

diff.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,6 +1837,7 @@ static void emit_rewrite_diff(const char *name_a,
18371837
const char *a_prefix, *b_prefix;
18381838
char *data_one, *data_two;
18391839
size_t size_one, size_two;
1840+
unsigned ws_rule;
18401841
struct emit_callback ecbdata;
18411842
struct strbuf out = STRBUF_INIT;
18421843

@@ -1859,9 +1860,15 @@ static void emit_rewrite_diff(const char *name_a,
18591860
size_one = fill_textconv(o->repo, textconv_one, one, &data_one);
18601861
size_two = fill_textconv(o->repo, textconv_two, two, &data_two);
18611862

1863+
ws_rule = whitespace_rule(o->repo->index, name_b);
1864+
1865+
/* symlink being an incomplete line is not a news */
1866+
if (DIFF_FILE_VALID(two) && S_ISLNK(two->mode))
1867+
ws_rule &= ~WS_INCOMPLETE_LINE;
1868+
18621869
memset(&ecbdata, 0, sizeof(ecbdata));
18631870
ecbdata.color_diff = o->use_color;
1864-
ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b);
1871+
ecbdata.ws_rule = ws_rule;
18651872
ecbdata.opt = o;
18661873
if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
18671874
mmfile_t mf1, mf2;
@@ -3759,6 +3766,7 @@ static void builtin_diff(const char *name_a,
37593766
xpparam_t xpp;
37603767
xdemitconf_t xecfg;
37613768
struct emit_callback ecbdata;
3769+
unsigned ws_rule;
37623770
const struct userdiff_funcname *pe;
37633771

37643772
if (must_show_header) {
@@ -3770,6 +3778,12 @@ static void builtin_diff(const char *name_a,
37703778
mf1.size = fill_textconv(o->repo, textconv_one, one, &mf1.ptr);
37713779
mf2.size = fill_textconv(o->repo, textconv_two, two, &mf2.ptr);
37723780

3781+
ws_rule = whitespace_rule(o->repo->index, name_b);
3782+
3783+
/* symlink being an incomplete line is not a news */
3784+
if (DIFF_FILE_VALID(two) && S_ISLNK(two->mode))
3785+
ws_rule &= ~WS_INCOMPLETE_LINE;
3786+
37733787
pe = diff_funcname_pattern(o, one);
37743788
if (!pe)
37753789
pe = diff_funcname_pattern(o, two);
@@ -3781,7 +3795,7 @@ static void builtin_diff(const char *name_a,
37813795
lbl[0] = NULL;
37823796
ecbdata.label_path = lbl;
37833797
ecbdata.color_diff = o->use_color;
3784-
ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b);
3798+
ecbdata.ws_rule = ws_rule;
37853799
if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
37863800
check_blank_at_eof(&mf1, &mf2, &ecbdata);
37873801
ecbdata.opt = o;
@@ -3988,6 +4002,10 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
39884002
data.ws_rule = whitespace_rule(o->repo->index, attr_path);
39894003
data.conflict_marker_size = ll_merge_marker_size(o->repo->index, attr_path);
39904004

4005+
/* symlink being an incomplete line is not a news */
4006+
if (DIFF_FILE_VALID(two) && S_ISLNK(two->mode))
4007+
data.ws_rule &= ~WS_INCOMPLETE_LINE;
4008+
39914009
if (fill_mmfile(o->repo, &mf1, one) < 0 ||
39924010
fill_mmfile(o->repo, &mf2, two) < 0)
39934011
die("unable to read files to diff");

t/t4015-diff-whitespace.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,32 @@ test_expect_success "new incomplete line in post-image" '
9090
git -c core.whitespace=incomplete diff -R --check x
9191
'
9292

93+
test_expect_success SYMLINKS "incomplete-line error is disabled for symlinks" '
94+
test_when_finished "git reset --hard" &&
95+
test_when_finished "rm -f mylink" &&
96+
97+
# a regular file with an incomplete line
98+
printf "%s" one >mylink &&
99+
git add mylink &&
100+
101+
# a symbolic link
102+
rm mylink &&
103+
ln -s two mylink &&
104+
105+
git -c diff.color=always -c core.whitespace=incomplete \
106+
diff mylink >forward.raw &&
107+
test_decode_color >forward <forward.raw &&
108+
test_grep ! "<BRED>\\\\ No newline at end of file<RESET>" forward &&
109+
110+
git -c diff.color=always -c core.whitespace=incomplete \
111+
diff -R mylink >reverse.raw &&
112+
test_decode_color >reverse <reverse.raw &&
113+
test_grep "<BRED>\\\\ No newline at end of file<RESET>" reverse &&
114+
115+
git -c core.whitespace=incomplete diff --check mylink &&
116+
test_must_fail git -c core.whitespace=incomplete diff --check -R mylink
117+
'
118+
93119
test_expect_success "Ray Lehtiniemi's example" '
94120
cat <<-\EOF >x &&
95121
do {

t/t4124-apply-ws-rule.sh

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,4 +743,90 @@ test_expect_success 'incomplete line modified at the end (error)' '
743743
test_cmp sample target
744744
'
745745

746+
test_expect_success "incomplete-line error is disabled for symlinks" '
747+
test_when_finished "git reset" &&
748+
test_when_finished "rm -f patch.txt" &&
749+
oneblob=$(printf "one" | git hash-object --stdin -w -t blob) &&
750+
twoblob=$(printf "two" | git hash-object --stdin -w -t blob) &&
751+
752+
oneshort=$(git rev-parse --short $oneblob) &&
753+
twoshort=$(git rev-parse --short $twoblob) &&
754+
755+
cat >patch0.txt <<-EOF &&
756+
diff --git a/mylink b/mylink
757+
index $oneshort..$twoshort 120000
758+
--- a/mylink
759+
+++ b/mylink
760+
@@ -1 +1 @@
761+
-one
762+
\ No newline at end of file
763+
+two
764+
\ No newline at end of file
765+
EOF
766+
767+
# the index has the preimage symlink
768+
git update-index --add --cacheinfo "120000,$oneblob,mylink" &&
769+
770+
# check the patch going forward and reverse
771+
git -c core.whitespace=incomplete apply --cached --check \
772+
--whitespace=error patch0.txt &&
773+
774+
git update-index --add --cacheinfo "120000,$twoblob,mylink" &&
775+
git -c core.whitespace=incomplete apply --cached --check \
776+
--whitespace=error -R patch0.txt &&
777+
778+
# the patch turns it into the postimage symlink
779+
git update-index --add --cacheinfo "120000,$oneblob,mylink" &&
780+
git -c core.whitespace=incomplete apply --cached --whitespace=error \
781+
patch0.txt &&
782+
783+
# and then back.
784+
git -c core.whitespace=incomplete apply --cached -R --whitespace=error \
785+
patch0.txt &&
786+
787+
# a text file turns into a symlink
788+
cat >patch1.txt <<-EOF &&
789+
diff --git a/mylink b/mylink
790+
deleted file mode 100644
791+
index $oneshort..0000000
792+
--- a/mylink
793+
+++ /dev/null
794+
@@ -1 +0,0 @@
795+
-one
796+
\ No newline at end of file
797+
diff --git a/mylink b/mylink
798+
new file mode 120000
799+
index 0000000..$twoshort
800+
--- /dev/null
801+
+++ b/mylink
802+
@@ -0,0 +1 @@
803+
+two
804+
\ No newline at end of file
805+
EOF
806+
807+
# the index has the preimage text
808+
git update-index --cacheinfo "100644,$oneblob,mylink" &&
809+
810+
# check
811+
git -c core.whitespace=incomplete apply --cached \
812+
--check --whitespace=error patch1.txt &&
813+
814+
# reverse, leaving an incomplete text file, should error
815+
git update-index --cacheinfo "120000,$twoblob,mylink" &&
816+
test_must_fail git -c core.whitespace=incomplete \
817+
apply --cached --check --whitespace=error -R patch1.txt &&
818+
819+
# apply to create a symbolic link
820+
git update-index --cacheinfo "100644,$oneblob,mylink" &&
821+
git -c core.whitespace=incomplete apply --cached --whitespace=error \
822+
patch1.txt &&
823+
824+
# turning it back into an incomplete text file is an error
825+
test_must_fail git -c core.whitespace=incomplete \
826+
apply --cached --whitespace=error -R patch1.txt
827+
828+
829+
830+
'
831+
746832
test_done

0 commit comments

Comments
 (0)