diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-03-03 15:14:49 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-03-03 15:14:49 +0900 |
commit | 1d03f0dffab250aeffd10eba0368b88cf61c6e6b (patch) | |
tree | f955c3a5d03f61094de522958a6402dd212924b4 | |
parent | d7c5b0cd38a97a874f055ac72d163eb51a67c296 (diff) | |
download | git-1d03f0dffab250aeffd10eba0368b88cf61c6e6b.tar.gz git-1d03f0dffab250aeffd10eba0368b88cf61c6e6b.tar.bz2 git-1d03f0dffab250aeffd10eba0368b88cf61c6e6b.zip |
Imported Upstream version 2.2.2upstream/2.2.2
-rw-r--r-- | Documentation/RelNotes/2.2.2.txt | 63 | ||||
-rw-r--r-- | Documentation/config.txt | 4 | ||||
-rw-r--r-- | Documentation/git-am.txt | 1 | ||||
-rw-r--r-- | Documentation/git-push.txt | 2 | ||||
-rw-r--r-- | Documentation/git.txt | 3 | ||||
-rwxr-xr-x | GIT-VERSION-GEN | 2 | ||||
-rw-r--r-- | Makefile | 14 | ||||
l--------- | RelNotes | 2 | ||||
-rw-r--r-- | builtin/add.c | 2 | ||||
-rw-r--r-- | builtin/checkout.c | 18 | ||||
-rw-r--r-- | builtin/clean.c | 2 | ||||
-rw-r--r-- | builtin/config.c | 27 | ||||
-rw-r--r-- | builtin/init-db.c | 3 | ||||
-rw-r--r-- | builtin/push.c | 8 | ||||
-rw-r--r-- | builtin/receive-pack.c | 2 | ||||
-rw-r--r-- | compat/mingw.c | 2 | ||||
-rw-r--r-- | config.c | 4 | ||||
-rw-r--r-- | date.c | 21 | ||||
-rwxr-xr-x | gitweb/gitweb.perl | 6 | ||||
-rw-r--r-- | refs.c | 95 | ||||
-rw-r--r-- | sha1_name.c | 2 | ||||
-rwxr-xr-x | t/t0001-init.sh | 7 | ||||
-rwxr-xr-x | t/t0006-date.sh | 3 | ||||
-rwxr-xr-x | t/t0090-cache-tree.sh | 2 | ||||
-rwxr-xr-x | t/t1410-reflog.sh | 30 | ||||
-rwxr-xr-x | t/t1450-fsck.sh | 15 | ||||
-rwxr-xr-x | t/t2022-checkout-paths.sh | 17 | ||||
-rwxr-xr-x | t/t3700-add.sh | 8 | ||||
-rwxr-xr-x | t/t4026-color.sh | 8 | ||||
-rwxr-xr-x | t/t5528-push-default.sh | 32 | ||||
-rwxr-xr-x | t/t9603-cvsimport-patchsets.sh | 2 | ||||
-rwxr-xr-x | t/t9604-cvsimport-timestamps.sh | 4 | ||||
-rw-r--r-- | utf8.c | 32 |
33 files changed, 346 insertions, 97 deletions
diff --git a/Documentation/RelNotes/2.2.2.txt b/Documentation/RelNotes/2.2.2.txt new file mode 100644 index 00000000..b19a35d9 --- /dev/null +++ b/Documentation/RelNotes/2.2.2.txt @@ -0,0 +1,63 @@ +Git v2.2.2 Release Notes +======================== + +Fixes since v2.2.1 +------------------ + + * "git checkout $treeish $path", when $path in the index and the + working tree already matched what is in $treeish at the $path, + still overwrote the $path unnecessarily. + + * "git config --get-color" did not parse its command line arguments + carefully. + + * open() emulated on Windows platforms did not give EISDIR upon + an attempt to open a directory for writing. + + * A few code paths used abs() when they should have used labs() on + long integers. + + * "gitweb" used to depend on a behaviour recent CGI.pm deprecated. + + * "git init" (hence "git clone") initialized the per-repository + configuration file .git/config with x-bit by mistake. + + * Git 2.0 was supposed to make the "simple" mode for the default of + "git push", but it didn't. + + * "Everyday" document had a broken link. + + * The build procedure did not bother fixing perl and python scripts + when NO_PERL and NO_PYTHON build-time configuration changed. + + * The code that reads the reflog from the newer to the older entries + did not handle an entry that crosses a boundary of block it uses to + read them correctly. + + * "git apply" was described in the documentation to take --ignore-date + option, which it does not. + + * Traditionally we tried to avoid interpreting date strings given by + the user as future dates, e.g. GIT_COMMITTER_DATE=2014-12-10 when + used early November 2014 was taken as "October 12, 2014" because it + is likely that a date in the future, December 10, is a mistake. + This heuristics has been loosened to allow people to express future + dates (most notably, --until=<date> may want to be far in the + future) and we no longer tiebreak by future-ness of the date when + + (1) ISO-like format is used, and + (2) the string can make sense interpreted as both y-m-d and y-d-m. + + Git may still have to use the heuristics to tiebreak between dd/mm/yy + and mm/dd/yy, though. + + * The code to abbreviate an object name to its short unique prefix + has been optimized when no abbreviation was requested. + + * "git add --ignore-errors ..." did not ignore an error to + give a file that did not exist. + + * Git did not correctly read an overlong refname from a packed refs + file. + +Also contains typofixes, documentation updates and trivial code clean-ups. diff --git a/Documentation/config.txt b/Documentation/config.txt index 302d61e7..9335ff2a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -850,6 +850,10 @@ accepted are `normal`, `black`, `red`, `green`, `yellow`, `blue`, `blink` and `reverse`. The first color given is the foreground; the second is the background. The position of the attribute, if any, doesn't matter. ++ +Colors (foreground and background) may also be given as numbers between +0 and 255; these use ANSI 256-color mode (but note that not all +terminals may support this). color.diff:: Whether to use ANSI escape sequences to add color to patches. diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 9adce372..d4ef16c1 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -83,7 +83,6 @@ default. You can use `--no-utf8` to override this. it is supposed to apply to and we have those blobs available locally. ---ignore-date:: --ignore-space-change:: --ignore-whitespace:: --whitespace=<option>:: diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 21b3f29c..b17283ab 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -34,7 +34,7 @@ When the command line does not specify what to push with `<refspec>...` arguments or `--all`, `--mirror`, `--tags` options, the command finds the default `<refspec>` by consulting `remote.*.push` configuration, and if it is not found, honors `push.default` configuration to decide -what to push (See gitlink:git-config[1] for the meaning of `push.default`). +what to push (See linkgit:git-config[1] for the meaning of `push.default`). OPTIONS[[OPTIONS]] diff --git a/Documentation/git.txt b/Documentation/git.txt index db4e407b..edceb508 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.2.1/git.html[documentation for release 2.2.1] +* link:v2.2.2/git.html[documentation for release 2.2.2] * release notes for + link:RelNotes/2.2.2.txt[2.2.2], link:RelNotes/2.2.1.txt[2.2.1], link:RelNotes/2.2.0.txt[2.2]. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 495ddb7d..f9f8f327 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.2.1 +DEF_VER=v2.2.2 LF=' ' @@ -1662,7 +1662,7 @@ GIT-SCRIPT-DEFINES: FORCE fi -$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh GIT-SCRIPT-DEFINES +$(SCRIPT_SH_GEN) : % : %.sh GIT-SCRIPT-DEFINES $(QUIET_GEN)$(cmd_munge_script) && \ chmod +x $@+ && \ mv $@+ $@ @@ -1676,8 +1676,11 @@ git.res: git.rc GIT-VERSION-FILE $(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \ -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" $< -o $@ +# This makes sure we depend on the NO_PERL setting itself. +$(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS + ifndef NO_PERL -$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak +$(SCRIPT_PERL_GEN): perl/perl.mak perl/perl.mak: perl/PM.stamp @@ -1690,7 +1693,7 @@ perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F) PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ) -$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE +$(SCRIPT_PERL_GEN): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE $(QUIET_GEN)$(RM) $@ $@+ && \ INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \ INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \ @@ -1724,7 +1727,7 @@ git-instaweb: git-instaweb.sh gitweb GIT-SCRIPT-DEFINES chmod +x $@+ && \ mv $@+ $@ else # NO_PERL -$(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh +$(SCRIPT_PERL_GEN) git-instaweb: % : unimplemented.sh $(QUIET_GEN)$(RM) $@ $@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@@REASON@@|NO_PERL=$(NO_PERL)|g' \ @@ -1733,6 +1736,9 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh mv $@+ $@ endif # NO_PERL +# This makes sure we depend on the NO_PYTHON setting itself. +$(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS + ifndef NO_PYTHON $(SCRIPT_PYTHON_GEN): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS $(SCRIPT_PYTHON_GEN): % : %.py @@ -1 +1 @@ -Documentation/RelNotes/2.2.1.txt
\ No newline at end of file +Documentation/RelNotes/2.2.2.txt
\ No newline at end of file diff --git a/builtin/add.c b/builtin/add.c index ae6d3e26..1074e323 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -284,7 +284,7 @@ static int add_files(struct dir_struct *dir, int flags) for (i = 0; i < dir->ignored_nr; i++) fprintf(stderr, "%s\n", dir->ignored[i]->name); fprintf(stderr, _("Use -f if you really want to add them.\n")); - die(_("no files added")); + exit_status = 1; } for (i = 0; i < dir->nr; i++) diff --git a/builtin/checkout.c b/builtin/checkout.c index 5410dace..5a787580 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -67,6 +67,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen, { int len; struct cache_entry *ce; + int pos; if (S_ISDIR(mode)) return READ_TREE_RECURSIVE; @@ -79,6 +80,23 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen, ce->ce_flags = create_ce_flags(0) | CE_UPDATE; ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); + + /* + * If the entry is the same as the current index, we can leave the old + * entry in place. Whether it is UPTODATE or not, checkout_entry will + * do the right thing. + */ + pos = cache_name_pos(ce->name, ce->ce_namelen); + if (pos >= 0) { + struct cache_entry *old = active_cache[pos]; + if (ce->ce_mode == old->ce_mode && + !hashcmp(ce->sha1, old->sha1)) { + old->ce_flags |= CE_UPDATE; + free(ce); + return 0; + } + } + add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); return 0; } diff --git a/builtin/clean.c b/builtin/clean.c index 77846762..7e7fdcfe 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -321,7 +321,7 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen) switch (stuff->type) { default: - die("Bad type of menu_staff when print menu"); + die("Bad type of menu_stuff when print menu"); case MENU_STUFF_TYPE_MENU_ITEM: menu_item = (struct menu_item *)stuff->stuff; for (i = 0; i < stuff->nr; i++, menu_item++) { diff --git a/builtin/config.c b/builtin/config.c index 8cc26040..fddafbba 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -69,8 +69,8 @@ static struct option builtin_config_options[] = { OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST), OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), - OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")), - OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")), + OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR), + OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL), OPT_GROUP(N_("Type")), OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL), OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT), @@ -303,8 +303,9 @@ static int git_get_color_config(const char *var, const char *value, void *cb) return 0; } -static void get_color(const char *def_color) +static void get_color(const char *var, const char *def_color) { + get_color_slot = var; get_color_found = 0; parsed_color[0] = '\0'; git_config_with_options(git_get_color_config, NULL, @@ -333,8 +334,9 @@ static int git_get_colorbool_config(const char *var, const char *value, return 0; } -static int get_colorbool(int print) +static int get_colorbool(const char *var, int print) { + get_colorbool_slot = var; get_colorbool_found = -1; get_diff_color_found = -1; get_color_ui_found = -1; @@ -532,12 +534,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_with_options(builtin_config_usage, builtin_config_options); } - if (get_color_slot) - actions |= ACTION_GET_COLOR; - if (get_colorbool_slot) - actions |= ACTION_GET_COLORBOOL; - - if ((get_color_slot || get_colorbool_slot) && types) { + if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && types) { error("--get-color and variable type are incoherent"); usage_with_options(builtin_config_usage, builtin_config_options); } @@ -683,12 +680,14 @@ int cmd_config(int argc, const char **argv, const char *prefix) die("No such section!"); } else if (actions == ACTION_GET_COLOR) { - get_color(argv[0]); + check_argc(argc, 1, 2); + get_color(argv[0], argv[1]); } else if (actions == ACTION_GET_COLORBOOL) { - if (argc == 1) - color_stdout_is_tty = git_config_bool("command line", argv[0]); - return get_colorbool(argc != 0); + check_argc(argc, 1, 2); + if (argc == 2) + color_stdout_is_tty = git_config_bool("command line", argv[1]); + return get_colorbool(argv[0], argc == 2); } return 0; diff --git a/builtin/init-db.c b/builtin/init-db.c index 587a5055..aab44d2e 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -254,7 +254,8 @@ static int create_default_files(const char *template_path) struct stat st2; filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && !lstat(path, &st2) && - st1.st_mode != st2.st_mode); + st1.st_mode != st2.st_mode && + !chmod(path, st1.st_mode)); } git_config_set("core.filemode", filemode ? "true" : "false"); diff --git a/builtin/push.c b/builtin/push.c index a076b196..7aedf6f5 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -161,7 +161,7 @@ static const char message_detached_head_die[] = " git push %s HEAD:<name-of-remote-branch>\n"); static void setup_push_upstream(struct remote *remote, struct branch *branch, - int triangular) + int triangular, int simple) { struct strbuf refspec = STRBUF_INIT; @@ -184,7 +184,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch, "to update which remote branch."), remote->name, branch->name); - if (push_default == PUSH_DEFAULT_SIMPLE) { + if (simple) { /* Additional safety */ if (strcmp(branch->refname, branch->merge[0]->src)) die_push_simple(branch, remote); @@ -257,11 +257,11 @@ static void setup_default_push_refspecs(struct remote *remote) if (triangular) setup_push_current(remote, branch); else - setup_push_upstream(remote, branch, triangular); + setup_push_upstream(remote, branch, triangular, 1); break; case PUSH_DEFAULT_UPSTREAM: - setup_push_upstream(remote, branch, triangular); + setup_push_upstream(remote, branch, triangular, 0); break; case PUSH_DEFAULT_CURRENT: diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 32fc540e..e908d079 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -431,7 +431,7 @@ static const char *check_nonce(const char *buf, size_t len) nonce_stamp_slop = (long)ostamp - (long)stamp; if (nonce_stamp_slop_limit && - abs(nonce_stamp_slop) <= nonce_stamp_slop_limit) { + labs(nonce_stamp_slop) <= nonce_stamp_slop_limit) { /* * Pretend as if the received nonce (which passes the * HMAC check, so it is not a forged by third-party) diff --git a/compat/mingw.c b/compat/mingw.c index c5c37e53..70f3191a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -312,7 +312,7 @@ int mingw_open (const char *filename, int oflags, ...) return -1; fd = _wopen(wfilename, oflags, mode); - if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { + if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) { DWORD attrs = GetFileAttributesW(wfilename); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; @@ -506,9 +506,9 @@ static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max) errno = EINVAL; return 0; } - uval = abs(val); + uval = labs(val); uval *= factor; - if (uval > max || abs(val) > uval) { + if (uval > max || labs(val) > uval) { errno = ERANGE; return 0; } @@ -405,9 +405,9 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, return 0; } -static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm) +static int match_multi_number(unsigned long num, char c, const char *date, + char *end, struct tm *tm, time_t now) { - time_t now; struct tm now_tm; struct tm *refuse_future; long num2, num3; @@ -433,17 +433,18 @@ static int match_multi_number(unsigned long num, char c, const char *date, char case '-': case '/': case '.': - now = time(NULL); + if (!now) + now = time(NULL); refuse_future = NULL; if (gmtime_r(&now, &now_tm)) refuse_future = &now_tm; if (num > 70) { /* yyyy-mm-dd? */ - if (is_date(num, num2, num3, refuse_future, now, tm)) + if (is_date(num, num2, num3, NULL, now, tm)) break; /* yyyy-dd-mm? */ - if (is_date(num, num3, num2, refuse_future, now, tm)) + if (is_date(num, num3, num2, NULL, now, tm)) break; } /* Our eastern European friends say dd.mm.yy[yy] @@ -513,7 +514,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt case '/': case '-': if (isdigit(end[1])) { - int match = match_multi_number(num, *end, date, end, tm); + int match = match_multi_number(num, *end, date, end, tm, 0); if (match) return match; } @@ -1013,7 +1014,8 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm return end; } -static const char *approxidate_digit(const char *date, struct tm *tm, int *num) +static const char *approxidate_digit(const char *date, struct tm *tm, int *num, + time_t now) { char *end; unsigned long number = strtoul(date, &end, 10); @@ -1024,7 +1026,8 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num) case '/': case '-': if (isdigit(end[1])) { - int match = match_multi_number(number, *end, date, end, tm); + int match = match_multi_number(number, *end, date, end, + tm, now); if (match) return date + match; } @@ -1087,7 +1090,7 @@ static unsigned long approxidate_str(const char *date, date++; if (isdigit(c)) { pending_number(&tm, &number); - date = approxidate_digit(date-1, &tm, &number); + date = approxidate_digit(date-1, &tm, &number, time_sec); touched = 1; continue; } diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ccf75169..7a5b23ac 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -20,6 +20,10 @@ use File::Basename qw(basename); use Time::HiRes qw(gettimeofday tv_interval); binmode STDOUT, ':utf8'; +if (!defined($CGI::VERSION) || $CGI::VERSION < 4.08) { + eval 'sub CGI::multi_param { CGI::param(@_) }' +} + our $t0 = [ gettimeofday() ]; our $number_of_git_cmds = 0; @@ -871,7 +875,7 @@ sub evaluate_query_params { while (my ($name, $symbol) = each %cgi_param_mapping) { if ($symbol eq 'opt') { - $input_params{$name} = [ map { decode_utf8($_) } $cgi->param($symbol) ]; + $input_params{$name} = [ map { decode_utf8($_) } $cgi->multi_param($symbol) ]; } else { $input_params{$name} = decode_utf8($cgi->param($symbol)); } @@ -1068,8 +1068,10 @@ static const char PACKED_REFS_HEADER[] = * Return a pointer to the refname within the line (null-terminated), * or NULL if there was a problem. */ -static const char *parse_ref_line(char *line, unsigned char *sha1) +static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1) { + const char *ref; + /* * 42: the answer to everything. * @@ -1078,22 +1080,23 @@ static const char *parse_ref_line(char *line, unsigned char *sha1) * +1 (space in between hex and name) * +1 (newline at the end of the line) */ - int len = strlen(line) - 42; - - if (len <= 0) + if (line->len <= 42) return NULL; - if (get_sha1_hex(line, sha1) < 0) + + if (get_sha1_hex(line->buf, sha1) < 0) return NULL; - if (!isspace(line[40])) + if (!isspace(line->buf[40])) return NULL; - line += 41; - if (isspace(*line)) + + ref = line->buf + 41; + if (isspace(*ref)) return NULL; - if (line[len] != '\n') + + if (line->buf[line->len - 1] != '\n') return NULL; - line[len] = 0; + line->buf[--line->len] = 0; - return line; + return ref; } /* @@ -1126,16 +1129,15 @@ static const char *parse_ref_line(char *line, unsigned char *sha1) static void read_packed_refs(FILE *f, struct ref_dir *dir) { struct ref_entry *last = NULL; - char refline[PATH_MAX]; + struct strbuf line = STRBUF_INIT; enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE; - while (fgets(refline, sizeof(refline), f)) { + while (strbuf_getwholeline(&line, f, '\n') != EOF) { unsigned char sha1[20]; const char *refname; - static const char header[] = "# pack-refs with:"; + const char *traits; - if (!strncmp(refline, header, sizeof(header)-1)) { - const char *traits = refline + sizeof(header) - 1; + if (skip_prefix(line.buf, "# pack-refs with:", &traits)) { if (strstr(traits, " fully-peeled ")) peeled = PEELED_FULLY; else if (strstr(traits, " peeled ")) @@ -1144,7 +1146,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir) continue; } - refname = parse_ref_line(refline, sha1); + refname = parse_ref_line(&line, sha1); if (refname) { int flag = REF_ISPACKED; @@ -1160,10 +1162,10 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir) continue; } if (last && - refline[0] == '^' && - strlen(refline) == PEELED_LINE_LENGTH && - refline[PEELED_LINE_LENGTH - 1] == '\n' && - !get_sha1_hex(refline + 1, sha1)) { + line.buf[0] == '^' && + line.len == PEELED_LINE_LENGTH && + line.buf[PEELED_LINE_LENGTH - 1] == '\n' && + !get_sha1_hex(line.buf + 1, sha1)) { hashcpy(last->u.value.peeled, sha1); /* * Regardless of what the file header said, @@ -1173,6 +1175,8 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir) last->flag |= REF_KNOWS_PEELED; } } + + strbuf_release(&line); } /* @@ -3404,29 +3408,54 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void bp = find_beginning_of_line(buf, scanp); - if (*bp != '\n') { - strbuf_splice(&sb, 0, 0, buf, endp - buf); - if (pos) - break; /* need to fill another block */ - scanp = buf - 1; /* leave loop */ - } else { + if (*bp == '\n') { /* - * (bp + 1) thru endp is the beginning of the - * current line we have in sb + * The newline is the end of the previous line, + * so we know we have complete line starting + * at (bp + 1). Prefix it onto any prior data + * we collected for the line and process it. */ strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1)); scanp = bp; endp = bp + 1; + ret = show_one_reflog_ent(&sb, fn, cb_data); + strbuf_reset(&sb); + if (ret) + break; + } else if (!pos) { + /* + * We are at the start of the buffer, and the + * start of the file; there is no previous + * line, and we have everything for this one. + * Process it, and we can end the loop. + */ + strbuf_splice(&sb, 0, 0, buf, endp - buf); + ret = show_one_reflog_ent(&sb, fn, cb_data); + strbuf_reset(&sb); + break; } - ret = show_one_reflog_ent(&sb, fn, cb_data); - strbuf_reset(&sb); - if (ret) + + if (bp == buf) { + /* + * We are at the start of the buffer, and there + * is more file to read backwards. Which means + * we are in the middle of a line. Note that we + * may get here even if *bp was a newline; that + * just means we are at the exact end of the + * previous line, rather than some spot in the + * middle. + * + * Save away what we have to be combined with + * the data from the next read. + */ + strbuf_splice(&sb, 0, 0, buf, endp - buf); break; + } } } if (!ret && sb.len) - ret = show_one_reflog_ent(&sb, fn, cb_data); + die("BUG: reverse reflog parser had leftover data"); fclose(logfp); strbuf_release(&sb); diff --git a/sha1_name.c b/sha1_name.c index 5b004f51..cb881702 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -372,10 +372,10 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len) int status, exists; static char hex[41]; - exists = has_sha1_file(sha1); memcpy(hex, sha1_to_hex(sha1), 40); if (len == 40 || !len) return hex; + exists = has_sha1_file(sha1); while (len < 40) { unsigned char sha1_ret[20]; status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY); diff --git a/t/t0001-init.sh b/t/t0001-init.sh index e62c0ffb..7de8d85e 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -12,6 +12,13 @@ check_config () { echo "expected a directory $1, a file $1/config and $1/refs" return 1 fi + + if test_have_prereq POSIXPERM && test -x "$1/config" + then + echo "$1/config is executable?" + return 1 + fi + bare=$(cd "$1" && git config --bool core.bare) worktree=$(cd "$1" && git config core.worktree) || worktree=unset diff --git a/t/t0006-date.sh b/t/t0006-date.sh index e53cf6d3..fac09861 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -82,4 +82,7 @@ check_approxidate 'Jun 6, 5AM' '2009-06-06 05:00:00' check_approxidate '5AM Jun 6' '2009-06-06 05:00:00' check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00' +check_approxidate '2008-12-01' '2008-12-01 19:20:00' +check_approxidate '2009-12-01' '2009-12-01 19:20:00' + test_done diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh index 158cf4f0..067f4c6e 100755 --- a/t/t0090-cache-tree.sh +++ b/t/t0090-cache-tree.sh @@ -131,7 +131,7 @@ test_expect_success 'second commit has cache-tree' ' test_cache_tree ' -test_expect_success 'commit --interactive gives cache-tree on partial commit' ' +test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' ' cat <<-\EOT >foo.c && int foo() { diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 8cf44616..779d4e38 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -287,4 +287,34 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' ' test_cmp expect actual ' +# Triggering the bug detected by this test requires a newline to fall +# exactly BUFSIZ-1 bytes from the end of the file. We don't know +# what that value is, since it's platform dependent. However, if +# we choose some value N, we also catch any D which divides N evenly +# (since we will read backwards in chunks of D). So we choose 8K, +# which catches glibc (with an 8K BUFSIZ) and *BSD (1K). +# +# Each line is 114 characters, so we need 75 to still have a few before the +# last 8K. The 89-character padding on the final entry lines up our +# newline exactly. +test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' ' + git checkout -b reflogskip && + z38=00000000000000000000000000000000000000 && + ident="abc <xyz> 0000000001 +0000" && + for i in $(test_seq 1 75); do + printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" && + if test $i = 75; then + for j in $(test_seq 1 89); do + printf X + done + else + printf X + fi && + printf "\n" + done >.git/logs/refs/heads/reflogskip && + git rev-parse reflogskip@{73} >actual && + echo ${z38}03 >expect && + test_cmp expect actual +' + test_done diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index d00b70f9..793aee9f 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -345,6 +345,21 @@ dot-backslash-case .\\\\.GIT\\\\foobar dotgit-case-backslash .git\\\\foobar EOF +test_expect_success 'fsck allows .Ňit' ' + ( + git init not-dotgit && + cd not-dotgit && + echo content >file && + git add file && + git commit -m base && + blob=$(git rev-parse :file) && + printf "100644 blob $blob\t.\\305\\207it" >tree && + tree=$(git mktree <tree) && + git fsck 2>err && + test_line_count = 0 err + ) +' + # create a static test repo which is broken by omitting # one particular object ($1, which is looked up via rev-parse # in the new repository). diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh index 8e3545d8..f46d0499 100755 --- a/t/t2022-checkout-paths.sh +++ b/t/t2022-checkout-paths.sh @@ -61,4 +61,21 @@ test_expect_success 'do not touch unmerged entries matching $path but not in $tr test_cmp expect.next0 actual.next0 ' +test_expect_success 'do not touch files that are already up-to-date' ' + git reset --hard && + echo one >file1 && + echo two >file2 && + git add file1 file2 && + git commit -m base && + echo modified >file1 && + test-chmtime =1000000000 file2 && + git update-index -q --refresh && + git checkout HEAD -- file1 file2 && + echo one >expect && + test_cmp expect file1 && + echo "1000000000 file2" >expect && + test-chmtime -v +0 file2 >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3700-add.sh b/t/t3700-add.sh index fe274e2f..f7ff1f55 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -91,6 +91,13 @@ test_expect_success 'error out when attempting to add ignored ones without -f' ' ! (git ls-files | grep "\\.ig") ' +test_expect_success 'error out when attempting to add ignored ones but add others' ' + touch a.if && + test_must_fail git add a.?? && + ! (git ls-files | grep "\\.ig") && + (git ls-files | grep a.if) +' + test_expect_success 'add ignored ones with -f' ' git add -f a.?? && git ls-files --error-unmatch a.ig @@ -311,7 +318,6 @@ cat >expect.err <<\EOF The following paths are ignored by one of your .gitignore files: ignored-file Use -f if you really want to add them. -fatal: no files added EOF cat >expect.out <<\EOF add 'track-this' diff --git a/t/t4026-color.sh b/t/t4026-color.sh index 3726a0e2..63e42383 100755 --- a/t/t4026-color.sh +++ b/t/t4026-color.sh @@ -53,6 +53,14 @@ test_expect_success '256 colors' ' color "254 bold 255" "[1;38;5;254;48;5;255m" ' +test_expect_success '"normal" yields no color at all"' ' + color "normal black" "[40m" +' + +test_expect_success '-1 is a synonym for "normal"' ' + color "-1 black" "[40m" +' + test_expect_success 'color too small' ' invalid_color "-2" ' diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh index 6a5ac3ad..cc745190 100755 --- a/t/t5528-push-default.sh +++ b/t/t5528-push-default.sh @@ -26,7 +26,7 @@ check_pushed_commit () { # $2 = expected target branch for the push # $3 = [optional] repo to check for actual output (repo1 by default) test_push_success () { - git -c push.default="$1" push && + git ${1:+-c push.default="$1"} push && check_pushed_commit HEAD "$2" "$3" } @@ -34,7 +34,7 @@ test_push_success () { # check that push fails and does not modify any remote branch test_push_failure () { git --git-dir=repo1 log --no-walk --format='%h %s' --all >expect && - test_must_fail git -c push.default="$1" push && + test_must_fail git ${1:+-c push.default="$1"} push && git --git-dir=repo1 log --no-walk --format='%h %s' --all >actual && test_cmp expect actual } @@ -172,4 +172,32 @@ test_pushdefault_workflow success simple master triangular # master is updated (parent2 does not have foo) test_pushdefault_workflow success matching master triangular +# default tests, when no push-default is specified. This +# should behave the same as "simple" in non-triangular +# settings, and as "current" otherwise. + +test_expect_success 'default behavior allows "simple" push' ' + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/master && + test_config remote.pushdefault parent1 && + test_commit default-master-master && + test_push_success "" master +' + +test_expect_success 'default behavior rejects non-simple push' ' + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/foo && + test_config remote.pushdefault parent1 && + test_commit default-master-foo && + test_push_failure "" +' + +test_expect_success 'default triangular behavior acts like "current"' ' + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/foo && + test_config remote.pushdefault parent2 && + test_commit default-triangular && + test_push_success "" master repo2 +' + test_done diff --git a/t/t9603-cvsimport-patchsets.sh b/t/t9603-cvsimport-patchsets.sh index 52034c8f..c4c3c495 100755 --- a/t/t9603-cvsimport-patchsets.sh +++ b/t/t9603-cvsimport-patchsets.sh @@ -16,7 +16,7 @@ test_description='git cvsimport testing for correct patchset estimation' setup_cvs_test_repository t9603 -test_expect_failure 'import with criss cross times on revisions' ' +test_expect_failure PERL 'import with criss cross times on revisions' ' git cvsimport -p"-x" -C module-git module && (cd module-git && diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh index 1fd51423..a4b3db24 100755 --- a/t/t9604-cvsimport-timestamps.sh +++ b/t/t9604-cvsimport-timestamps.sh @@ -5,7 +5,7 @@ test_description='git cvsimport timestamps' setup_cvs_test_repository t9604 -test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' ' +test_expect_success PERL 'check timestamps are UTC (TZ=CST6CDT)' ' TZ=CST6CDT git cvsimport -p"-x" -C module-1 module && git cvsimport -p"-x" -C module-1 module && @@ -34,7 +34,7 @@ test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' ' test_cmp actual-1 expect-1 ' -test_expect_success 'check timestamps with author-specific timezones' ' +test_expect_success PERL 'check timestamps with author-specific timezones' ' cat >cvs-authors <<-EOF && user1=User One <user1@domain.org> @@ -563,8 +563,8 @@ int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding) } /* - * Pick the next char from the stream, folding as an HFS+ filename comparison - * would. Note that this is _not_ complete by any means. It's just enough + * Pick the next char from the stream, ignoring codepoints an HFS+ would. + * Note that this is _not_ complete by any means. It's just enough * to make is_hfs_dotgit() work, and should not be used otherwise. */ static ucs_char_t next_hfs_char(const char **in) @@ -601,12 +601,7 @@ static ucs_char_t next_hfs_char(const char **in) continue; } - /* - * there's a great deal of other case-folding that occurs, - * but this is enough to catch anything that will convert - * to ".git" - */ - return tolower(out); + return out; } } @@ -614,10 +609,23 @@ int is_hfs_dotgit(const char *path) { ucs_char_t c; - if (next_hfs_char(&path) != '.' || - next_hfs_char(&path) != 'g' || - next_hfs_char(&path) != 'i' || - next_hfs_char(&path) != 't') + c = next_hfs_char(&path); + if (c != '.') + return 0; + c = next_hfs_char(&path); + + /* + * there's a great deal of other case-folding that occurs + * in HFS+, but this is enough to catch anything that will + * convert to ".git" + */ + if (c != 'g' && c != 'G') + return 0; + c = next_hfs_char(&path); + if (c != 'i' && c != 'I') + return 0; + c = next_hfs_char(&path); + if (c != 't' && c != 'T') return 0; c = next_hfs_char(&path); if (c && !is_dir_sep(c)) |