From c9e1f2c7f2acca17c629255b96761a4a1047a28a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 25 Mar 2015 16:11:39 -0700 Subject: diff-no-index: DWIM "diff D F" into "diff D/F F" "git diff --no-index" was supposed to be a poor-man's approach to allow using Git diff goodies outside of a Git repository, without having to patch mainstream diff implementations. Unlike a POSIX diff that treats "diff D F" (or "diff F D") as a request to compare D/F and F (or F and D/F) when D is a directory and F is a file, however, we did not accept such a command line and instead barfed with "file/directory conflict". Imitate what POSIX diff does and append the basename of the file after the name of the directory before comparing. Signed-off-by: Junio C Hamano diff --git a/diff-no-index.c b/diff-no-index.c index 265709b..49c4536 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -182,12 +182,50 @@ static int queue_diff(struct diff_options *o, } } +/* append basename of F to D */ +static void append_basename(struct strbuf *path, const char *dir, const char *file) +{ + const char *tail = strrchr(file, '/'); + + strbuf_addstr(path, dir); + while (path->len && path->buf[path->len - 1] == '/') + path->len--; + strbuf_addch(path, '/'); + strbuf_addstr(path, tail ? tail + 1 : file); +} + +/* + * DWIM "diff D F" into "diff D/F F" and "diff F D" into "diff F D/F" + * Note that we append the basename of F to D/, so "diff a/b/file D" + * becomes "diff a/b/file D/file", not "diff a/b/file D/a/b/file". + */ +static void fixup_paths(const char **path, struct strbuf *replacement) +{ + unsigned int isdir0, isdir1; + + if (path[0] == file_from_standard_input || + path[1] == file_from_standard_input) + return; + isdir0 = is_directory(path[0]); + isdir1 = is_directory(path[1]); + if (isdir0 == isdir1) + return; + if (isdir0) { + append_basename(replacement, path[0], path[1]); + path[0] = replacement->buf; + } else { + append_basename(replacement, path[1], path[0]); + path[1] = replacement->buf; + } +} + void diff_no_index(struct rev_info *revs, int argc, const char **argv, const char *prefix) { int i, prefixlen; const char *paths[2]; + struct strbuf replacement = STRBUF_INIT; diff_setup(&revs->diffopt); for (i = 1; i < argc - 2; ) { @@ -217,6 +255,9 @@ void diff_no_index(struct rev_info *revs, p = xstrdup(prefix_filename(prefix, prefixlen, p)); paths[i] = p; } + + fixup_paths(paths, &replacement); + revs->diffopt.skip_stat_unmatch = 1; if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; @@ -235,6 +276,8 @@ void diff_no_index(struct rev_info *revs, diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); + strbuf_release(&replacement); + /* * The return code for --no-index imitates diff(1): * 0 = no changes, 1 = changes, else error diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 2ab3c48..01eca4c 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -55,4 +55,26 @@ test_expect_success 'git diff --no-index executed outside repo gives correct err ) ' +test_expect_success 'diff D F and diff F D' ' + ( + cd repo && + echo in-repo >a && + echo non-repo >../non/git/a && + mkdir sub && + echo sub-repo >sub/a && + + test_must_fail git diff --no-index sub/a ../non/git/a >expect && + test_must_fail git diff --no-index sub/a ../non/git/ >actual && + test_cmp expect actual && + + test_must_fail git diff --no-index a ../non/git/a >expect && + test_must_fail git diff --no-index a ../non/git/ >actual && + test_cmp expect actual && + + test_must_fail git diff --no-index ../non/git/a a >expect && + test_must_fail git diff --no-index ../non/git a >actual && + test_cmp expect actual + ) +' + test_done -- cgit v0.10.2-6-g49f6 From 06151739988601b0fe6179c6c67a0031b85b536f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 21 Mar 2015 22:11:27 -0700 Subject: diff-no-index: align D/F handling with that of normal Git When a commit changes a path P that used to be a file to a directory and creates a new path P/X in it, "git show" would say that file P was removed and file P/X was created for such a commit. However, if we compare two directories, D1 and D2, where D1 has a file D1/P in it and D2 has a directory D2/P under which there is a file D2/P/X, and ask "git diff --no-index D1 D2" to show their differences, we simply get a refusal "file/directory conflict". Surely, that may be what GNU diff does, but we can do better and it is easy to do so. Signed-off-by: Junio C Hamano diff --git a/diff-no-index.c b/diff-no-index.c index 49c4536..0320605 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -97,8 +97,27 @@ static int queue_diff(struct diff_options *o, if (get_mode(name1, &mode1) || get_mode(name2, &mode2)) return -1; - if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) - return error("file/directory conflict: %s, %s", name1, name2); + if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) { + struct diff_filespec *d1, *d2; + + if (S_ISDIR(mode1)) { + /* 2 is file that is created */ + d1 = noindex_filespec(NULL, 0); + d2 = noindex_filespec(name2, mode2); + name2 = NULL; + mode2 = 0; + } else { + /* 1 is file that is deleted */ + d1 = noindex_filespec(name1, mode1); + d2 = noindex_filespec(NULL, 0); + name1 = NULL; + mode1 = 0; + } + /* emit that file */ + diff_queue(&diff_queued_diff, d1, d2); + + /* and then let the entire directory be created or deleted */ + } if (S_ISDIR(mode1) || S_ISDIR(mode2)) { struct strbuf buffer1 = STRBUF_INIT; diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 01eca4c..596dfe7 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -77,4 +77,16 @@ test_expect_success 'diff D F and diff F D' ' ) ' +test_expect_success 'turning a file into a directory' ' + ( + cd non/git && + mkdir d e e/sub && + echo 1 >d/sub && + echo 2 >e/sub/file && + printf "D\td/sub\nA\te/sub/file\n" >expect && + test_must_fail git diff --no-index --name-status d e >actual && + test_cmp expect actual + ) +' + test_done -- cgit v0.10.2-6-g49f6 From 7fcec48da90f95dc64268ebd4b3073ae9487fe4e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 15 Apr 2015 08:43:58 -0700 Subject: parse_date_basic(): return early when given a bogus timestamp When the input does not have GMT timezone offset, the code computes it by computing the local and GMT time for the given timestamp. But there is no point doing so if the given timestamp is known to be a bogus one. Signed-off-by: Junio C Hamano diff --git a/date.c b/date.c index 782de95..76fb475 100644 --- a/date.c +++ b/date.c @@ -696,6 +696,9 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) /* mktime uses local timezone */ *timestamp = tm_to_time_t(&tm); + if (*timestamp == -1) + return -1; + if (*offset == -1) { time_t temp_time = mktime(&tm); if ((time_t)*timestamp > temp_time) { @@ -705,9 +708,6 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) } } - if (*timestamp == -1) - return -1; - if (!tm_gmt) *timestamp -= *offset * 60; return 0; /* success */ -- cgit v0.10.2-6-g49f6 From f6e6362107a1e7a798dc1c28ef439a3157813467 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 15 Apr 2015 08:47:48 -0700 Subject: parse_date_basic(): let the system handle DST conversion The function parses the input to compute the broken-down time in "struct tm", and the GMT timezone offset. If the timezone offset does not exist in the input, the broken-down time is turned into the number of seconds since epoch both in the current timezone and in GMT and the offset is computed as their difference. However, we forgot to make sure tm.tm_isdst is set to -1 (i.e. let the system figure out if DST is in effect in the current timezone when turning the broken-down time to the number of seconds since epoch); it is done so at the beginning of the function, but a call to match_digit() in the function can lead to a call to gmtime_r() to clobber the field. Reported-by: Linus Torvalds Diagnosed-by: Eric Sunshine Signed-off-by: Junio C Hamano diff --git a/date.c b/date.c index 76fb475..52a9944 100644 --- a/date.c +++ b/date.c @@ -694,13 +694,17 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset) date += match; } - /* mktime uses local timezone */ + /* do not use mktime(), which uses local timezone, here */ *timestamp = tm_to_time_t(&tm); if (*timestamp == -1) return -1; if (*offset == -1) { - time_t temp_time = mktime(&tm); + time_t temp_time; + + /* gmtime_r() in match_digit() may have clobbered it */ + tm.tm_isdst = -1; + temp_time = mktime(&tm); if ((time_t)*timestamp > temp_time) { *offset = ((time_t)*timestamp - temp_time) / 60; } else { -- cgit v0.10.2-6-g49f6 From 7e1105244202d01ddf1de990f215418b01281bcf Mon Sep 17 00:00:00 2001 From: Ossi Herrala Date: Fri, 17 Apr 2015 17:50:10 +0300 Subject: config: fix settings in default_user_config template The name (not user) and email setting should be in config section "user" and not in "core" as documented in Documentation/config.txt. Signed-off-by: Ossi Herrala Reviewed-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/config.c b/builtin/config.c index 9346894..05cf691 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -463,9 +463,9 @@ static char *default_user_config(void) struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, _("# This is Git's per-user configuration file.\n" - "[core]\n" + "[user]\n" "# Please adapt and uncomment the following lines:\n" - "# user = %s\n" + "# name = %s\n" "# email = %s\n"), ident_default_name(), ident_default_email()); -- cgit v0.10.2-6-g49f6 From d349e0ee60e1bad1cf49245e402ca086ddb5ff80 Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Mon, 20 Apr 2015 14:09:06 +0200 Subject: Documentation: change -L: to -L: The old wording was somehow implying that and were not regular expressions. Also, the common case is to use a plain function name here so makes sense (the fact that it is a regular expression is documented in line-range-format.txt). Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 0cebc4f..23b8ff8 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -10,7 +10,7 @@ Include additional statistics at the end of blame output. -L ,:: --L ::: +-L ::: Annotate only the given line range. May be specified multiple times. Overlapping ranges are allowed. + diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index 1f7bc67..6e65c5a 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -62,9 +62,9 @@ produced by `--stat`, etc. output by allowing them to allocate space in advance. -L ,::: --L :::: +-L :::: Trace the evolution of the line range given by "," - (or the funcname regex ) within the . You may + (or the function name regex ) within the . You may not give any pathspec limiters. This is currently limited to a walk starting from a single revision, i.e., you may only give zero or one positive revision arguments. diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt index 7ae50aa..6ade002 100644 --- a/Documentation/gitk.txt +++ b/Documentation/gitk.txt @@ -99,10 +99,10 @@ linkgit:git-rev-list[1] for a complete list. detailed explanation.) -L,::: --L:::: +-L:::: Trace the evolution of the line range given by "," - (or the funcname regex ) within the . You may + (or the function name regex ) within the . You may not give any pathspec limiters. This is currently limited to a walk starting from a single revision, i.e., you may only give zero or one positive revision arguments. diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.txt index d7f2603..829676f 100644 --- a/Documentation/line-range-format.txt +++ b/Documentation/line-range-format.txt @@ -22,8 +22,9 @@ This is only valid for and will specify a number of lines before or after the line given by . + -If ``:'' is given in place of and , it denotes the range -from the first funcname line that matches , up to the next -funcname line. ``:'' searches from the end of the previous `-L` range, -if any, otherwise from the start of file. -``^:'' searches from the start of file. +If ``:'' is given in place of and , it is a +regular expression that denotes the range from the first funcname line +that matches , up to the next funcname line. ``:'' +searches from the end of the previous `-L` range, if any, otherwise +from the start of file. ``^:'' searches from the start of +file. -- cgit v0.10.2-6-g49f6 From 0269f968b7effea8a4f61f1fb0ac7e9386a9d90c Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Mon, 20 Apr 2015 14:09:07 +0200 Subject: log -L: improve error message on malformed argument The old message did not mention the :regex:file form. To avoid overly long lines, split the message into two lines (in case item->string is long, it will be the only part truncated in a narrow terminal). Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano diff --git a/line-log.c b/line-log.c index b7864ad..1a6bc59 100644 --- a/line-log.c +++ b/line-log.c @@ -575,7 +575,7 @@ parse_lines(struct commit *commit, const char *prefix, struct string_list *args) name_part = skip_range_arg(item->string); if (!name_part || *name_part != ':' || !name_part[1]) - die("-L argument '%s' not of the form start,end:file", + die("-L argument not 'start,end:file' or ':funcname:file': %s", item->string); range_part = xstrndup(item->string, name_part - item->string); name_part++; diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index 0901b30..4451127 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -54,14 +54,14 @@ canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset test_bad_opts "-L" "switch.*requires a value" -test_bad_opts "-L b.c" "argument.*not of the form" -test_bad_opts "-L 1:" "argument.*not of the form" +test_bad_opts "-L b.c" "argument not .start,end:file" +test_bad_opts "-L 1:" "argument not .start,end:file" test_bad_opts "-L 1:nonexistent" "There is no path" test_bad_opts "-L 1:simple" "There is no path" -test_bad_opts "-L '/foo:b.c'" "argument.*not of the form" +test_bad_opts "-L '/foo:b.c'" "argument not .start,end:file" test_bad_opts "-L 1000:b.c" "has only.*lines" test_bad_opts "-L 1,1000:b.c" "has only.*lines" -test_bad_opts "-L :b.c" "argument.*not of the form" +test_bad_opts "-L :b.c" "argument not .start,end:file" test_bad_opts "-L :foo:b.c" "no match" test_expect_success '-L X (X == nlines)' ' -- cgit v0.10.2-6-g49f6 From 9a3d637541a5b6fcd84b6f5fa057e597d1696460 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 11 May 2015 14:36:31 -0700 Subject: Git 2.3.8 Signed-off-by: Junio C Hamano diff --git a/Documentation/RelNotes/2.3.8.txt b/Documentation/RelNotes/2.3.8.txt new file mode 100644 index 0000000..0b67268 --- /dev/null +++ b/Documentation/RelNotes/2.3.8.txt @@ -0,0 +1,22 @@ +Git v2.3.8 Release Notes +======================== + +Fixes since v2.3.7 +------------------ + + * The usual "git diff" when seeing a file turning into a directory + showed a patchset to remove the file and create all files in the + directory, but "git diff --no-index" simply refused to work. Also, + when asked to compare a file and a directory, imitate POSIX "diff" + and compare the file with the file with the same name in the + directory, instead of refusing to run. + + * The default $HOME/.gitconfig file created upon "git config --global" + that edits it had incorrectly spelled user.name and user.email + entries in it. + + * "git commit --date=now" or anything that relies on approxidate lost + the daylight-saving-time offset. + +Also contains typofixes, documentation updates and trivial code +clean-ups. diff --git a/Documentation/git.txt b/Documentation/git.txt index 8704ffd..adff610 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.3.7/git.html[documentation for release 2.3.7] +* link:v2.3.8/git.html[documentation for release 2.3.8] * release notes for + link:RelNotes/2.3.8.txt[2.3.8], link:RelNotes/2.3.7.txt[2.3.7], link:RelNotes/2.3.6.txt[2.3.6], link:RelNotes/2.3.5.txt[2.3.5], diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 0c1ee67..a2fe57a 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.3.7 +DEF_VER=v2.3.8 LF=' ' diff --git a/RelNotes b/RelNotes index 8f376a9..159d09e 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.3.7.txt \ No newline at end of file +Documentation/RelNotes/2.3.8.txt \ No newline at end of file -- cgit v0.10.2-6-g49f6