diff options
58 files changed, 803 insertions, 207 deletions
diff --git a/Documentation/RelNotes-1.6.0.2.txt b/Documentation/RelNotes-1.6.0.2.txt index 6c5446bc07..7a9646fc4f 100644 --- a/Documentation/RelNotes-1.6.0.2.txt +++ b/Documentation/RelNotes-1.6.0.2.txt @@ -17,6 +17,10 @@ Fixes since v1.6.0.1 * Many commands did not use the correct working tree location when used with GIT_WORK_TREE environment settings. +* Some systems needs to use compatibility fnmach and regex libraries + independent from each other; the compat/ area has been reorganized to + allow this. + * "git apply --unidiff-zero" incorrectly applied a -U0 patch that inserts a new line before the second line. @@ -24,9 +28,15 @@ Fixes since v1.6.0.1 * "git blame -c" did not exactly work like "git annotate" when range boundaries are involved. +* "git checkout file" when file is still unmerged checked out contents from + a random high order stage, which was confusing. + * "git clone $there $here/" with extra trailing slashes after explicit local directory name $here did not work as expected. +* "git diff" on tracked contents with CRLF line endings did not drive "less" + intelligently when showing added or removed lines. + * "git diff --dirstat -M" did not add changes in subdirectories up correctly for renamed paths. @@ -42,18 +52,29 @@ Fixes since v1.6.0.1 * "git gui" translation updates and i18n fixes. +* "git index-pack" is more careful against disk corruption while completing + a thin pack. + * "git log -i --grep=pattern" did not ignore case; neither "git log -E --grep=pattern" triggered extended regexp. * "git log --pretty="%ad" --date=short" did not use short format when showing the timestamp. +* "git log --author=author" match incorrectly matched with the + timestamp part of "author " line in commit objects. + +* "git log -F --author=author" did not work at all. + * Build procedure for "git shell" that used stub versions of some functions and globals was not understood by linkers on some platforms. * "git stash" was fooled by a stat-dirty but otherwise unmodified paths and refused to work until the user refreshed the index. +* "git svn" was broken on Perl before 5.8 with recent fixes to reduce + use of temporary files. + * "git verify-pack -v" did not work correctly when given more than one packfile. @@ -61,7 +82,6 @@ Also contains many documentation updates. -- exec >/var/tmp/1 -O=v1.6.0.1-61-g1eff26c +O=v1.6.0.1-78-g3632cfc echo O=$(git describe maint) git shortlog --no-merges $O..maint - diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt index 36afad8d4e..7f7a45b2ea 100644 --- a/Documentation/git-web--browse.txt +++ b/Documentation/git-web--browse.txt @@ -77,7 +77,7 @@ the URLs passed as arguments. Note about konqueror -------------------- -When 'konqueror' is specified by the a command line option or a +When 'konqueror' is specified by a command line option or a configuration variable, we launch 'kfmclient' to try to open the HTML man page on an already opened konqueror in a new tab if possible. diff --git a/Documentation/git.txt b/Documentation/git.txt index 363a785452..df420aeb33 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,11 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.0/git.html[documentation for release 1.6.0] +* link:v1.6.0.2/git.html[documentation for release 1.6.0.2] * release notes for + link:RelNotes-1.6.0.2.txt[1.6.0.2], + link:RelNotes-1.6.0.1.txt[1.6.0.1], link:RelNotes-1.6.0.txt[1.6.0]. * link:v1.5.6.5/git.html[documentation for release 1.5.6.5] diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 49a167f241..89627688b8 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -270,27 +270,27 @@ See linkgit:git[1] for details. Defining a custom hunk-header ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Each group of changes (called "hunk") in the textual diff output +Each group of changes (called a "hunk") in the textual diff output is prefixed with a line of the form: @@ -k,l +n,m @@ TEXT -The text is called 'hunk header', and by default a line that -begins with an alphabet, an underscore or a dollar sign is used, -which matches what GNU 'diff -p' output uses. This default -selection however is not suited for some contents, and you can -use customized pattern to make a selection. +This is called a 'hunk header'. The "TEXT" portion is by default a line +that begins with an alphabet, an underscore or a dollar sign; this +matches what GNU 'diff -p' output uses. This default selection however +is not suited for some contents, and you can use a customized pattern +to make a selection. -First in .gitattributes, you would assign the `diff` attribute +First, in .gitattributes, you would assign the `diff` attribute for paths. ------------------------ *.tex diff=tex ------------------------ -Then, you would define "diff.tex.funcname" configuration to +Then, you would define a "diff.tex.funcname" configuration to specify a regular expression that matches a line that you would -want to appear as the hunk header, like this: +want to appear as the hunk header "TEXT", like this: ------------------------ [diff "tex"] @@ -311,7 +311,7 @@ patterns are available: - `bibtex` suitable for files with BibTeX coded references. -- `java` suitable for source code in the Java lanugage. +- `java` suitable for source code in the Java language. - `pascal` suitable for source code in the Pascal/Delphi language. diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 00277e0613..c735788b0f 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -1,5 +1,5 @@ merge.stat:: - Whether to print the diffstat between ORIG_HEAD and merge result + Whether to print the diffstat between ORIG_HEAD and the merge result at the end of the merge. True by default. merge.log:: diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 156dc13733..6c7465c758 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.0.GIT +DEF_VER=v1.6.0.2.GIT LF=' ' @@ -626,6 +626,8 @@ ifeq ($(uname_S),Darwin) endif NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease @@ -675,6 +677,8 @@ ifeq ($(uname_S),FreeBSD) BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease @@ -700,6 +704,8 @@ ifeq ($(uname_S),AIX) INTERNAL_QSORT = UnfortunatelyYes NEEDS_LIBICONV=YesPlease BASIC_CFLAGS += -D_LARGE_FILES + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),GNU) # GNU/Hurd @@ -750,10 +756,10 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease - COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe gitexecdir = ../libexec/git-core diff --git a/builtin-archive.c b/builtin-archive.c index 5ceec433fd..432ce2acc6 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -111,6 +111,8 @@ int cmd_archive(int argc, const char **argv, const char *prefix) { const char *remote = NULL; + git_config(git_default_config, NULL); + remote = extract_remote_arg(&argc, argv); if (remote) return run_remote_archiver(remote, argc, argv); diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 90f8523eb5..55b7aafe06 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -5,26 +5,26 @@ * * Careful: order of argument flags does matter. For example, * - * git-checkout-index -a -f file.c + * git checkout-index -a -f file.c * * Will first check out all files listed in the cache (but not * overwrite any old ones), and then force-checkout "file.c" a * second time (ie that one _will_ overwrite any old contents * with the same filename). * - * Also, just doing "git-checkout-index" does nothing. You probably - * meant "git-checkout-index -a". And if you want to force it, you - * want "git-checkout-index -f -a". + * Also, just doing "git checkout-index" does nothing. You probably + * meant "git checkout-index -a". And if you want to force it, you + * want "git checkout-index -f -a". * * Intuitiveness is not the goal here. Repeatability is. The * reason for the "no arguments means no work" thing is that * from scripts you are supposed to be able to do things like * - * find . -name '*.h' -print0 | xargs -0 git-checkout-index -f -- + * find . -name '*.h' -print0 | xargs -0 git checkout-index -f -- * * or: * - * find . -name '*.h' -print0 | git-checkout-index -f -z --stdin + * find . -name '*.h' -print0 | git checkout-index -f -z --stdin * * which will force all existing *.h files to be replaced with * their cached copies. If an empty command line implied "all", @@ -107,7 +107,7 @@ static int checkout_file(const char *name, int prefix_length) } if (!state.quiet) { - fprintf(stderr, "git-checkout-index: %s ", name); + fprintf(stderr, "git checkout-index: %s ", name); if (!has_same_name) fprintf(stderr, "is not in the cache"); else if (checkout_stage) diff --git a/builtin-checkout.c b/builtin-checkout.c index 774f29992a..08c6d8614a 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -76,6 +76,15 @@ static int read_tree_some(struct tree *tree, const char **pathspec) return 0; } +static int skip_same_name(struct cache_entry *ce, int pos) +{ + while (++pos < active_nr && + !strcmp(active_cache[pos]->name, ce->name)) + ; /* skip */ + return pos; +} + + static int checkout_paths(struct tree *source_tree, const char **pathspec) { int pos; @@ -107,6 +116,20 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) if (report_path_error(ps_matched, pathspec, 0)) return 1; + /* Any unmerged paths? */ + for (pos = 0; pos < active_nr; pos++) { + struct cache_entry *ce = active_cache[pos]; + if (pathspec_match(pathspec, NULL, ce->name, 0)) { + if (!ce_stage(ce)) + continue; + errs = 1; + error("path '%s' is unmerged", ce->name); + pos = skip_same_name(ce, pos) - 1; + } + } + if (errs) + return 1; + /* Now we are committed to check them out */ memset(&state, 0, sizeof(state)); state.force = 1; @@ -114,7 +137,11 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (pathspec_match(pathspec, NULL, ce->name, 0)) { - errs |= checkout_entry(ce, &state, NULL); + if (!ce_stage(ce)) { + errs |= checkout_entry(ce, &state, NULL); + continue; + } + pos = skip_same_name(ce, pos) - 1; } } diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 291c43cf70..9b84c48dce 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -24,7 +24,7 @@ static void check_valid(unsigned char *sha1, enum object_type expect) typename(expect)); } -static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog"; +static const char commit_tree_usage[] = "git commit-tree <sha1> [-p <sha1>]* < changelog"; static void new_parent(struct commit *parent, struct commit_list **parents_p) { diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 9bf10bb37e..2b578c714d 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -50,7 +50,12 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) 3 < rev.max_count) usage(diff_files_usage); - if (rev.max_count == -1 && + /* + * "diff-files --base -p" should not combine merges because it + * was not asked to. "diff-files -c -p" should not densify + * (the user should ask with "diff-files --cc" explicitly). + */ + if (rev.max_count == -1 && !rev.combine_merges && (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; diff --git a/builtin-diff.c b/builtin-diff.c index 037c3039a4..d5fe775fc1 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -223,7 +223,13 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv argv++; argc--; } - if (revs->max_count == -1 && + /* + * "diff --base" should not combine merges because it was not + * asked to. "diff -c" should not densify (if the user wants + * dense one, --cc can be explicitly asked for, or just rely + * on the default). + */ + if (revs->max_count == -1 && !revs->combine_merges && (revs->diffopt.output_format & DIFF_FORMAT_PATCH)) revs->combine_merges = revs->dense_combined_merges = 1; diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 6b37281a95..85509f5ee5 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -750,7 +750,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) if (!ret && nr_heads) { /* If the heads to pull were given, we should have * consumed all of them by matching the remote. - * Otherwise, 'git-fetch remote no-such-ref' would + * Otherwise, 'git fetch remote no-such-ref' would * silently succeed without issuing an error. */ for (i = 0; i < nr_heads; i++) diff --git a/builtin-fetch.c b/builtin-fetch.c index 7eec4a0e43..ee93d3a93d 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -86,10 +86,10 @@ static void add_merge_config(struct ref **head, /* * Not fetched to a tracking branch? We need to fetch * it anyway to allow this branch's "branch.$name.merge" - * to be honored by git-pull, but we do not have to + * to be honored by 'git pull', but we do not have to * fail if branch.$name.merge is misconfigured to point * at a nonexisting branch. If we were indeed called by - * git-pull, it will notice the misconfiguration because + * 'git pull', it will notice the misconfiguration because * there is no entry in the resulting FETCH_HEAD marked * for merging. */ @@ -396,7 +396,7 @@ static int store_updated_refs(const char *url, const char *remote_name, * The refs we are going to fetch are in to_fetch (nr_heads in * total). If running * - * $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all + * $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all * * does not error out, that means everything reachable from the * refs we are going to fetch exists and is connected to some of diff --git a/builtin-http-fetch.c b/builtin-http-fetch.c index 3a062487a7..03f34d767d 100644 --- a/builtin-http-fetch.c +++ b/builtin-http-fetch.c @@ -42,7 +42,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) arg++; } if (argc < arg + 2 - commits_on_stdin) { - usage("git-http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); + usage("git http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); return 1; } if (commits_on_stdin) { @@ -75,7 +75,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) fprintf(stderr, "Some loose object were found to be corrupt, but they might be just\n" "a false '404 Not Found' error message sent with incorrect HTTP\n" -"status code. Suggest running git-fsck.\n"); +"status code. Suggest running 'git fsck'.\n"); } walker_free(walker); diff --git a/builtin-init-db.c b/builtin-init-db.c index baf0d09ac4..8140c1299a 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -37,7 +37,7 @@ static void copy_templates_1(char *path, int baselen, /* Note: if ".git/hooks" file exists in the repository being * re-initialized, /etc/core-git/templates/hooks/update would - * cause git-init to fail here. I think this is sane but + * cause "git init" to fail here. I think this is sane but * it means that the set of templates we ship by default, along * with the way the namespace under .git/ is organized, should * be really carefully chosen. diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index ef3befe57b..217fd49da9 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -23,7 +23,7 @@ #endif static const char pack_usage[] = "\ -git-pack-objects [{ -q | --progress | --all-progress }] \n\ +git pack-objects [{ -q | --progress | --all-progress }] \n\ [--max-pack-size=N] [--local] [--incremental] \n\ [--window=N] [--window-memory=N] [--depth=N] \n\ [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\ @@ -410,25 +410,22 @@ static unsigned long write_object(struct sha1file *f, return hdrlen + datalen; } -static off_t write_one(struct sha1file *f, +static int write_one(struct sha1file *f, struct object_entry *e, - off_t offset) + off_t *offset) { unsigned long size; /* offset is non zero if object is written already. */ if (e->idx.offset || e->preferred_base) - return offset; + return 1; /* if we are deltified, write out base object first. */ - if (e->delta) { - offset = write_one(f, e->delta, offset); - if (!offset) - return 0; - } + if (e->delta && !write_one(f, e->delta, offset)) + return 0; - e->idx.offset = offset; - size = write_object(f, e, offset); + e->idx.offset = *offset; + size = write_object(f, e, *offset); if (!size) { e->idx.offset = 0; return 0; @@ -436,9 +433,10 @@ static off_t write_one(struct sha1file *f, written_list[nr_written++] = &e->idx; /* make sure off_t is sufficiently large not to wrap */ - if (offset > offset + size) + if (*offset > *offset + size) die("pack too large for current definition of off_t"); - return offset + size; + *offset += size; + return 1; } /* forward declaration for write_pack_file */ @@ -448,7 +446,7 @@ static void write_pack_file(void) { uint32_t i = 0, j; struct sha1file *f; - off_t offset, offset_one, last_obj_offset = 0; + off_t offset; struct pack_header hdr; uint32_t nr_remaining = nr_result; time_t last_mtime = 0; @@ -480,11 +478,8 @@ static void write_pack_file(void) offset = sizeof(hdr); nr_written = 0; for (; i < nr_objects; i++) { - last_obj_offset = offset; - offset_one = write_one(f, objects + i, offset); - if (!offset_one) + if (!write_one(f, objects + i, &offset)) break; - offset = offset_one; display_progress(progress_state, written); } @@ -497,8 +492,9 @@ static void write_pack_file(void) } else if (nr_written == nr_remaining) { sha1close(f, sha1, CSUM_FSYNC); } else { - int fd = sha1close(f, NULL, 0); - fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written); + int fd = sha1close(f, sha1, 0); + fixup_pack_header_footer(fd, sha1, pack_tmp_name, + nr_written, sha1, offset); close(fd); } @@ -1876,7 +1872,7 @@ static void mark_in_pack_object(struct object *object, struct packed_git *p, str /* * Compare the objects in the offset order, in order to emulate the - * "git-rev-list --objects" output that produced the pack originally. + * "git rev-list --objects" output that produced the pack originally. */ static int ofscmp(const void *a_, const void *b_) { diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 362216b272..0706c95818 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -64,7 +64,7 @@ static void prime_cache_tree(void) } -static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])"; +static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])"; static struct lock_file lock_file; diff --git a/builtin-rev-list.c b/builtin-rev-list.c index c023003b2b..facaff288d 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -178,7 +178,7 @@ static void finish_object(struct object_array_entry *p) static void show_object(struct object_array_entry *p) { /* An object with name "foo\n0000000..." can be used to - * confuse downstream git-pack-objects very badly. + * confuse downstream "git pack-objects" very badly. */ const char *ep = strchr(p->name, '\n'); diff --git a/builtin-rm.c b/builtin-rm.c index 6bd82111d2..fdac34f242 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -104,7 +104,7 @@ static int check_local_mod(unsigned char *head, int index_only) "from both the file and the HEAD\n" "(use -f to force removal)", name); else if (!index_only) { - /* It's not dangerous to git-rm --cached a + /* It's not dangerous to "git rm --cached" a * file if the index matches the file or the * HEAD, since it means the deleted content is * still available somewhere. diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 7588d22885..2af9f29341 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -43,7 +43,7 @@ static int pack_objects(int fd, struct ref *refs) po.out = fd; po.git_cmd = 1; if (start_command(&po)) - die("git-pack-objects failed (%s)", strerror(errno)); + die("git pack-objects failed (%s)", strerror(errno)); /* * We feed the pack-objects we just spawned with revision diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index cb7007e25f..0713bca778 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -9,26 +9,26 @@ static const char tar_tree_usage[] = "git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n" -"*** Note that this command is now deprecated; use git-archive instead."; +"*** Note that this command is now deprecated; use \"git archive\" instead."; int cmd_tar_tree(int argc, const char **argv, const char *prefix) { /* - * git-tar-tree is now a wrapper around git-archive --format=tar + * "git tar-tree" is now a wrapper around "git archive --format=tar" * * $0 --remote=<repo> arg... ==> - * git-archive --format=tar --remote=<repo> arg... + * git archive --format=tar --remote=<repo> arg... * $0 tree-ish ==> - * git-archive --format=tar tree-ish + * git archive --format=tar tree-ish * $0 tree-ish basedir ==> - * git-archive --format-tar --prefix=basedir tree-ish + * git archive --format-tar --prefix=basedir tree-ish */ int i; const char **nargv = xcalloc(sizeof(*nargv), argc + 2); char *basedir_arg; int nargc = 0; - nargv[nargc++] = "git-archive"; + nargv[nargc++] = "archive"; nargv[nargc++] = "--format=tar"; if (2 <= argc && !prefixcmp(argv[1], "--remote=")) { @@ -53,8 +53,8 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) nargv[nargc] = NULL; fprintf(stderr, - "*** git-tar-tree is now deprecated.\n" - "*** Running git-archive instead.\n***"); + "*** \"git tar-tree\" is now deprecated.\n" + "*** Running \"git archive\" instead.\n***"); for (i = 0; i < nargc; i++) { fputc(' ', stderr); sq_quote_print(stderr, nargv[i]); diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index a891866665..40b20f26e8 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -13,7 +13,7 @@ #include "fsck.h" static int dry_run, quiet, recover, has_errors, strict; -static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file"; +static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file"; /* We always read in 4kB chunks. */ static unsigned char buffer[4096]; diff --git a/builtin-update-index.c b/builtin-update-index.c index 5637d417aa..9d19c51e8e 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -14,7 +14,7 @@ * Default to not allowing changes to the list of files. The * tool doesn't actually care, but this makes it harder to add * files to the revision control by mistake by doing something - * like "git-update-index *" and suddenly having all the object + * like "git update-index *" and suddenly having all the object * files be revision controlled. */ static int allow_add; @@ -310,18 +310,18 @@ static void read_index_info(int line_termination) /* This reads lines formatted in one of three formats: * * (1) mode SP sha1 TAB path - * The first format is what "git-apply --index-info" + * The first format is what "git apply --index-info" * reports, and used to reconstruct a partial tree * that is used for phony merge base tree when falling * back on 3-way merge. * * (2) mode SP type SP sha1 TAB path - * The second format is to stuff git-ls-tree output + * The second format is to stuff "git ls-tree" output * into the index file. * * (3) mode SP sha1 SP stage TAB path * This format is to put higher order stages into the - * index file and matches git-ls-files --stage output. + * index file and matches "git ls-files --stage" output. */ errno = 0; ul = strtoul(buf.buf, &ptr, 8); diff --git a/combine-diff.c b/combine-diff.c index 4dfc330867..aa9d79ea0b 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -500,6 +500,18 @@ static int hunk_comment_line(const char *bol) return (isalpha(ch) || ch == '_' || ch == '$'); } +static void show_line_to_eol(const char *line, int len, const char *reset) +{ + int saw_cr_at_eol = 0; + if (len < 0) + len = strlen(line); + saw_cr_at_eol = (len && line[len-1] == '\r'); + + printf("%.*s%s%s\n", len - saw_cr_at_eol, line, + reset, + saw_cr_at_eol ? "\r" : ""); +} + static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, int use_color) { @@ -593,7 +605,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, else putchar(' '); } - printf("%s%s\n", ll->line, c_reset); + show_line_to_eol(ll->line, -1, c_reset); ll = ll->next; } if (cnt < lno) @@ -617,7 +629,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, putchar(' '); p_mask <<= 1; } - printf("%.*s%s\n", sl->len, sl->bol, c_reset); + show_line_to_eol(sl->bol, sl->len, c_reset); } } } diff --git a/compat/fnmatch.c b/compat/fnmatch/fnmatch.c index 1f4ead5f98..1f4ead5f98 100644 --- a/compat/fnmatch.c +++ b/compat/fnmatch/fnmatch.c diff --git a/compat/fnmatch.h b/compat/fnmatch/fnmatch.h index cc3ec37940..cc3ec37940 100644 --- a/compat/fnmatch.h +++ b/compat/fnmatch/fnmatch.h diff --git a/compat/regex.c b/compat/regex/regex.c index 87b33e4669..87b33e4669 100644 --- a/compat/regex.c +++ b/compat/regex/regex.c diff --git a/compat/regex.h b/compat/regex/regex.h index 6eb64f1402..6eb64f1402 100644 --- a/compat/regex.h +++ b/compat/regex/regex.h diff --git a/csum-file.c b/csum-file.c index ace64f165e..28389541a3 100644 --- a/csum-file.c +++ b/csum-file.c @@ -42,11 +42,11 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags) sha1flush(f, offset); f->offset = 0; } + SHA1_Final(f->buffer, &f->ctx); + if (result) + hashcpy(result, f->buffer); if (flags & (CSUM_CLOSE | CSUM_FSYNC)) { /* write checksum and close fd */ - SHA1_Final(f->buffer, &f->ctx); - if (result) - hashcpy(result, f->buffer); sha1flush(f, 20); if (flags & CSUM_FSYNC) fsync_or_die(f->fd, f->name); @@ -511,13 +511,20 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) { - int has_trailing_newline = (len > 0 && line[len-1] == '\n'); + int has_trailing_newline, has_trailing_carriage_return; + + has_trailing_newline = (len > 0 && line[len-1] == '\n'); if (has_trailing_newline) len--; + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; fputs(set, file); fwrite(line, len, 1, file); fputs(reset, file); + if (has_trailing_carriage_return) + fputc('\r', file); if (has_trailing_newline) fputc('\n', file); } @@ -2393,13 +2400,6 @@ int diff_setup_done(struct diff_options *options) DIFF_OPT_SET(options, EXIT_WITH_STATUS); } - /* - * If we postprocess in diffcore, we cannot simply return - * upon the first hit. We need to run diff as usual. - */ - if (options->pickaxe || options->filter) - DIFF_OPT_CLR(options, QUIET); - return 0; } @@ -3391,10 +3391,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) void diffcore_std(struct diff_options *options) { - if (DIFF_OPT_TST(options, QUIET)) - return; - - if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER)) + if (options->skip_stat_unmatch) diffcore_skip_stat_unmatch(options); if (options->break_opt != -1) diffcore_break(options->break_opt); diff --git a/fast-import.c b/fast-import.c index 7089e6f9e6..d85b3a561f 100644 --- a/fast-import.c +++ b/fast-import.c @@ -951,7 +951,8 @@ static void end_packfile(void) close_pack_windows(pack_data); fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1, - pack_data->pack_name, object_count); + pack_data->pack_name, object_count, + NULL, 0); close(pack_data->pack_fd); idx_name = keep_pack(create_index()); diff --git a/git-svn.perl b/git-svn.perl index 7a1d26db8b..7c7fc39483 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3284,7 +3284,7 @@ sub close_file { my $out = syswrite($tmp_fh, $str, $res); defined($out) && $out == $res or croak("write ", - $tmp_fh->filename, + Git::temp_path($tmp_fh), ": $!\n"); } defined $res or croak $!; @@ -3295,7 +3295,7 @@ sub close_file { } $hash = $::_repository->hash_and_insert_object( - $fh->filename); + Git::temp_path($fh)); $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n"; Git::temp_release($fb->{base}, 1); @@ -3969,21 +3969,21 @@ sub gs_do_switch { my $old_url = $full_url; $full_url .= '/' . escape_uri_only($path) if length $path; my ($ra, $reparented); - if ($old_url ne $full_url) { - if ($old_url !~ m#^svn(\+ssh)?://#) { - SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, - $pool); - $self->{url} = $full_url; - $reparented = 1; - } else { - $_[0] = undef; - $self = undef; - $RA = undef; - $ra = Git::SVN::Ra->new($full_url); - $ra_invalid = 1; - } + + if ($old_url =~ m#^svn(\+ssh)?://#) { + $_[0] = undef; + $self = undef; + $RA = undef; + $ra = Git::SVN::Ra->new($full_url); + $ra_invalid = 1; + } elsif ($old_url ne $full_url) { + SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool); + $self->{url} = $full_url; + $reparented = 1; } + $ra ||= $self; + $url_b = escape_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : (); $reporter->set_path('', $rev_a, 0, @lock, $pool); @@ -4383,7 +4383,7 @@ sub config_pager { sub run_pager { return unless -t *STDOUT && defined $pager; - pipe my $rfd, my $wfd or return; + pipe my ($rfd, $wfd) or return; defined(my $pid = fork) or ::fatal "Can't fork: $!"; if (!$pid) { open STDOUT, '>&', $wfd or diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 90cd99bf91..269f1125d9 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2092,7 +2092,7 @@ sub parse_commit_text { last; } } - if ($co{'title'} eq "") { + if (! defined $co{'title'} || $co{'title'} eq "") { $co{'title'} = $co{'title_short'} = '(no commit message)'; } # remove added spaces @@ -2,6 +2,19 @@ #include "grep.h" #include "xdiff-interface.h" +void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat) +{ + struct grep_pat *p = xcalloc(1, sizeof(*p)); + p->pattern = pat; + p->origin = "header"; + p->no = 0; + p->token = GREP_PATTERN_HEAD; + p->field = field; + *opt->pattern_tail = p; + opt->pattern_tail = &p->next; + p->next = NULL; +} + void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t) { @@ -247,16 +260,53 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match) } } +static int strip_timestamp(char *bol, char **eol_p) +{ + char *eol = *eol_p; + int ch; + + while (bol < --eol) { + if (*eol != '>') + continue; + *eol_p = ++eol; + ch = *eol; + *eol = '\0'; + return ch; + } + return 0; +} + +static struct { + const char *field; + size_t len; +} header_field[] = { + { "author ", 7 }, + { "committer ", 10 }, +}; + static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx) { int hit = 0; int at_true_bol = 1; + int saved_ch = 0; regmatch_t pmatch[10]; if ((p->token != GREP_PATTERN) && ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD))) return 0; + if (p->token == GREP_PATTERN_HEAD) { + const char *field; + size_t len; + assert(p->field < ARRAY_SIZE(header_field)); + field = header_field[p->field].field; + len = header_field[p->field].len; + if (strncmp(bol, field, len)) + return 0; + bol += len; + saved_ch = strip_timestamp(bol, &eol); + } + again: if (!opt->fixed) { regex_t *exp = &p->regexp; @@ -298,6 +348,8 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol goto again; } } + if (p->token == GREP_PATTERN_HEAD && saved_ch) + *eol = saved_ch; return hit; } @@ -17,12 +17,18 @@ enum grep_context { GREP_CONTEXT_BODY, }; +enum grep_header_field { + GREP_HEADER_AUTHOR = 0, + GREP_HEADER_COMMITTER, +}; + struct grep_pat { struct grep_pat *next; const char *origin; int no; enum grep_pat_token token; const char *pattern; + enum grep_header_field field; regex_t regexp; }; @@ -74,6 +80,7 @@ struct grep_opt { }; extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t); +extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *); extern void compile_grep_patterns(struct grep_opt *opt); extern void free_grep_patterns(struct grep_opt *opt); extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size); @@ -165,7 +165,16 @@ static CURL* get_curl_handle(void) { CURL* result = curl_easy_init(); - curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify); + if (!curl_ssl_verify) { + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0); + } else { + /* Verify authenticity of the peer's certificate */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1); + /* The name in the cert must match whom we tried to connect */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2); + } + #if LIBCURL_VERSION_NUM >= 0x070907 curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif diff --git a/index-pack.c b/index-pack.c index 728af7da9c..a6e91fe3ba 100644 --- a/index-pack.c +++ b/index-pack.c @@ -654,7 +654,7 @@ static void parse_pack_objects(unsigned char *sha1) } } -static int write_compressed(int fd, void *in, unsigned int size, uint32_t *obj_crc) +static int write_compressed(struct sha1file *f, void *in, unsigned int size) { z_stream stream; unsigned long maxsize; @@ -674,13 +674,12 @@ static int write_compressed(int fd, void *in, unsigned int size, uint32_t *obj_c deflateEnd(&stream); size = stream.total_out; - write_or_die(fd, out, size); - *obj_crc = crc32(*obj_crc, out, size); + sha1write(f, out, size); free(out); return size; } -static struct object_entry *append_obj_to_pack( +static struct object_entry *append_obj_to_pack(struct sha1file *f, const unsigned char *sha1, void *buf, unsigned long size, enum object_type type) { @@ -696,15 +695,15 @@ static struct object_entry *append_obj_to_pack( s >>= 7; } header[n++] = c; - write_or_die(output_fd, header, n); - obj[0].idx.crc32 = crc32(0, Z_NULL, 0); - obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n); + crc32_begin(f); + sha1write(f, header, n); obj[0].size = size; obj[0].hdr_size = n; obj[0].type = type; obj[0].real_type = type; obj[1].idx.offset = obj[0].idx.offset + n; - obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32); + obj[1].idx.offset += write_compressed(f, buf, size); + obj[0].idx.crc32 = crc32_end(f); hashcpy(obj->idx.sha1, sha1); return obj; } @@ -716,7 +715,7 @@ static int delta_pos_compare(const void *_a, const void *_b) return a->obj_no - b->obj_no; } -static void fix_unresolved_deltas(int nr_unresolved) +static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved) { struct delta_entry **sorted_by_pos; int i, n = 0; @@ -754,8 +753,8 @@ static void fix_unresolved_deltas(int nr_unresolved) if (check_sha1_signature(d->base.sha1, base_obj.data, base_obj.size, typename(type))) die("local object %s is corrupt", sha1_to_hex(d->base.sha1)); - base_obj.obj = append_obj_to_pack(d->base.sha1, base_obj.data, - base_obj.size, type); + base_obj.obj = append_obj_to_pack(f, d->base.sha1, + base_obj.data, base_obj.size, type); link_base_data(NULL, &base_obj); find_delta_children(&d->base, &first, &last); @@ -875,7 +874,7 @@ int main(int argc, char **argv) const char *keep_name = NULL, *keep_msg = NULL; char *index_name_buf = NULL, *keep_name_buf = NULL; struct pack_idx_entry **idx_objects; - unsigned char sha1[20]; + unsigned char pack_sha1[20]; int nongit = 0; setup_git_directory_gently(&nongit); @@ -962,13 +961,15 @@ int main(int argc, char **argv) parse_pack_header(); objects = xmalloc((nr_objects + 1) * sizeof(struct object_entry)); deltas = xmalloc(nr_objects * sizeof(struct delta_entry)); - parse_pack_objects(sha1); + parse_pack_objects(pack_sha1); if (nr_deltas == nr_resolved_deltas) { stop_progress(&progress); /* Flush remaining pack final 20-byte SHA1. */ flush(); } else { if (fix_thin_pack) { + struct sha1file *f; + unsigned char read_sha1[20], tail_sha1[20]; char msg[48]; int nr_unresolved = nr_deltas - nr_resolved_deltas; int nr_objects_initial = nr_objects; @@ -977,12 +978,19 @@ int main(int argc, char **argv) objects = xrealloc(objects, (nr_objects + nr_unresolved + 1) * sizeof(*objects)); - fix_unresolved_deltas(nr_unresolved); + f = sha1fd(output_fd, curr_pack); + fix_unresolved_deltas(f, nr_unresolved); sprintf(msg, "completed with %d local objects", nr_objects - nr_objects_initial); stop_progress_msg(&progress, msg); - fixup_pack_header_footer(output_fd, sha1, - curr_pack, nr_objects); + sha1close(f, tail_sha1, 0); + hashcpy(read_sha1, pack_sha1); + fixup_pack_header_footer(output_fd, pack_sha1, + curr_pack, nr_objects, + read_sha1, consumed_bytes-20); + if (hashcmp(read_sha1, tail_sha1) != 0) + die("Unexpected tail checksum for %s " + "(disk corruption?)", curr_pack); } if (nr_deltas != nr_resolved_deltas) die("pack has %d unresolved deltas", @@ -995,13 +1003,13 @@ int main(int argc, char **argv) idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *)); for (i = 0; i < nr_objects; i++) idx_objects[i] = &objects[i].idx; - curr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1); + curr_index = write_idx_file(index_name, idx_objects, nr_objects, pack_sha1); free(idx_objects); final(pack_name, curr_pack, index_name, curr_index, keep_name, keep_msg, - sha1); + pack_sha1); free(objects); free(index_name_buf); free(keep_name_buf); diff --git a/pack-write.c b/pack-write.c index ddcfd37af2..939ed56362 100644 --- a/pack-write.c +++ b/pack-write.c @@ -144,41 +144,93 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, return index_name; } +/* + * Update pack header with object_count and compute new SHA1 for pack data + * associated to pack_fd, and write that SHA1 at the end. That new SHA1 + * is also returned in new_pack_sha1. + * + * If partial_pack_sha1 is non null, then the SHA1 of the existing pack + * (without the header update) is computed and validated against the + * one provided in partial_pack_sha1. The validation is performed at + * partial_pack_offset bytes in the pack file. The SHA1 of the remaining + * data (i.e. from partial_pack_offset to the end) is then computed and + * returned in partial_pack_sha1. + * + * Note that new_pack_sha1 is updated last, so both new_pack_sha1 and + * partial_pack_sha1 can refer to the same buffer if the caller is not + * interested in the resulting SHA1 of pack data above partial_pack_offset. + */ void fixup_pack_header_footer(int pack_fd, - unsigned char *pack_file_sha1, + unsigned char *new_pack_sha1, const char *pack_name, - uint32_t object_count) + uint32_t object_count, + unsigned char *partial_pack_sha1, + off_t partial_pack_offset) { - static const int buf_sz = 128 * 1024; - SHA_CTX c; + int aligned_sz, buf_sz = 8 * 1024; + SHA_CTX old_sha1_ctx, new_sha1_ctx; struct pack_header hdr; char *buf; + SHA1_Init(&old_sha1_ctx); + SHA1_Init(&new_sha1_ctx); + if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start: %s", strerror(errno)); + die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) die("Unable to reread header of %s: %s", pack_name, strerror(errno)); if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start: %s", strerror(errno)); + die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); + SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr)); hdr.hdr_entries = htonl(object_count); + SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr)); write_or_die(pack_fd, &hdr, sizeof(hdr)); - - SHA1_Init(&c); - SHA1_Update(&c, &hdr, sizeof(hdr)); + partial_pack_offset -= sizeof(hdr); buf = xmalloc(buf_sz); + aligned_sz = buf_sz - sizeof(hdr); for (;;) { - ssize_t n = xread(pack_fd, buf, buf_sz); + ssize_t m, n; + m = (partial_pack_sha1 && partial_pack_offset < aligned_sz) ? + partial_pack_offset : aligned_sz; + n = xread(pack_fd, buf, m); if (!n) break; if (n < 0) die("Failed to checksum %s: %s", pack_name, strerror(errno)); - SHA1_Update(&c, buf, n); + SHA1_Update(&new_sha1_ctx, buf, n); + + aligned_sz -= n; + if (!aligned_sz) + aligned_sz = buf_sz; + + if (!partial_pack_sha1) + continue; + + SHA1_Update(&old_sha1_ctx, buf, n); + partial_pack_offset -= n; + if (partial_pack_offset == 0) { + unsigned char sha1[20]; + SHA1_Final(sha1, &old_sha1_ctx); + if (hashcmp(sha1, partial_pack_sha1) != 0) + die("Unexpected checksum for %s " + "(disk corruption?)", pack_name); + /* + * Now let's compute the SHA1 of the remainder of the + * pack, which also means making partial_pack_offset + * big enough not to matter anymore. + */ + SHA1_Init(&old_sha1_ctx); + partial_pack_offset = ~partial_pack_offset; + partial_pack_offset -= MSB(partial_pack_offset, 1); + } } free(buf); - SHA1_Final(pack_file_sha1, &c); - write_or_die(pack_fd, pack_file_sha1, 20); + if (partial_pack_sha1) + SHA1_Final(partial_pack_sha1, &old_sha1_ctx); + SHA1_Final(new_pack_sha1, &new_sha1_ctx); + write_or_die(pack_fd, new_pack_sha1, 20); fsync_or_die(pack_fd, pack_name); } @@ -58,7 +58,7 @@ struct pack_idx_entry { extern char *write_idx_file(char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1); extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr); extern int verify_pack(struct packed_git *); -extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t); +extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t); extern char *index_pack_lockfile(int fd); #define PH_ERROR_EOF (-1) diff --git a/perl/Git.pm b/perl/Git.pm index 102e6a4ce3..6aab712e6a 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -58,7 +58,7 @@ require Exporter; command_bidi_pipe command_close_bidi_pipe version exec_path hash_object git_cmd_try remote_refs - temp_acquire temp_release temp_reset); + temp_acquire temp_release temp_reset temp_path); =head1 DESCRIPTION @@ -937,7 +937,7 @@ sub _close_cat_blob { { # %TEMP_* Lexical Context -my (%TEMP_LOCKS, %TEMP_FILES); +my (%TEMP_FILEMAP, %TEMP_FILES); =item temp_acquire ( NAME ) @@ -965,7 +965,7 @@ sub temp_acquire { my $temp_fd = _temp_cache($name); - $TEMP_LOCKS{$temp_fd} = 1; + $TEMP_FILES{$temp_fd}{locked} = 1; $temp_fd; } @@ -991,16 +991,16 @@ the same string. sub temp_release { my ($self, $temp_fd, $trunc) = _maybe_self(@_); - if (ref($temp_fd) ne 'File::Temp') { + if (exists $TEMP_FILEMAP{$temp_fd}) { $temp_fd = $TEMP_FILES{$temp_fd}; } - unless ($TEMP_LOCKS{$temp_fd}) { + unless ($TEMP_FILES{$temp_fd}{locked}) { carp "Attempt to release temp file '", $temp_fd, "' that has not been locked"; } temp_reset($temp_fd) if $trunc and $temp_fd->opened; - $TEMP_LOCKS{$temp_fd} = 0; + $TEMP_FILES{$temp_fd}{locked} = 0; undef; } @@ -1009,9 +1009,9 @@ sub _temp_cache { _verify_require(); - my $temp_fd = \$TEMP_FILES{$name}; + my $temp_fd = \$TEMP_FILEMAP{$name}; if (defined $$temp_fd and $$temp_fd->opened) { - if ($TEMP_LOCKS{$$temp_fd}) { + if ($TEMP_FILES{$$temp_fd}{locked}) { throw Error::Simple("Temp file with moniker '", $name, "' already in use"); } @@ -1021,12 +1021,13 @@ sub _temp_cache { carp "Temp file '", $name, "' was closed. Opening replacement."; } - $$temp_fd = File::Temp->new( - TEMPLATE => 'Git_XXXXXX', - DIR => File::Spec->tmpdir + my $fname; + ($$temp_fd, $fname) = File::Temp->tempfile( + 'Git_XXXXXX', UNLINK => 1 ) or throw Error::Simple("couldn't open new temp file"); $$temp_fd->autoflush; binmode $$temp_fd; + $TEMP_FILES{$$temp_fd}{fname} = $fname; } $$temp_fd; } @@ -1053,8 +1054,25 @@ sub temp_reset { or throw Error::Simple("expected file position to be reset"); } +=item temp_path ( NAME ) + +=item temp_path ( FILEHANDLE ) + +Returns the filename associated with the given tempfile. + +=cut + +sub temp_path { + my ($self, $temp_fd) = _maybe_self(@_); + + if (exists $TEMP_FILEMAP{$temp_fd}) { + $temp_fd = $TEMP_FILEMAP{$temp_fd}; + } + $TEMP_FILES{$temp_fd}{fname}; +} + sub END { - unlink values %TEMP_FILES if %TEMP_FILES; + unlink values %TEMP_FILEMAP if %TEMP_FILEMAP; } } # %TEMP_* Lexical Context diff --git a/read-cache.c b/read-cache.c index 35fec468b1..8f96fd1722 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1244,6 +1244,7 @@ int discard_index(struct index_state *istate) istate->cache_nr = 0; istate->cache_changed = 0; istate->timestamp = 0; + istate->name_hash_initialized = 0; free_hash(&istate->name_hash); cache_tree_free(&(istate->cache_tree)); free(istate->alloc); diff --git a/revision.c b/revision.c index 36291b6b86..270294af83 100644 --- a/revision.c +++ b/revision.c @@ -953,22 +953,9 @@ static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token append_grep_pattern(&revs->grep_filter, ptn, "command line", 0, what); } -static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern) +static void add_header_grep(struct rev_info *revs, enum grep_header_field field, const char *pattern) { - char *pat; - const char *prefix; - int patlen, fldlen; - - fldlen = strlen(field); - patlen = strlen(pattern); - pat = xmalloc(patlen + fldlen + 10); - prefix = ".*"; - if (*pattern == '^') { - prefix = ""; - pattern++; - } - sprintf(pat, "^%s %s%s", field, prefix, pattern); - add_grep(revs, pat, GREP_PATTERN_HEAD); + append_header_grep_pattern(&revs->grep_filter, field, pattern); } static void add_message_grep(struct rev_info *revs, const char *pattern) @@ -1154,9 +1141,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg * Grepping the commit log */ else if (!prefixcmp(arg, "--author=")) { - add_header_grep(revs, "author", arg+9); + add_header_grep(revs, GREP_HEADER_AUTHOR, arg+9); } else if (!prefixcmp(arg, "--committer=")) { - add_header_grep(revs, "committer", arg+12); + add_header_grep(revs, GREP_HEADER_COMMITTER, arg+12); } else if (!prefixcmp(arg, "--grep=")) { add_message_grep(revs, arg+7); } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) { diff --git a/sha1_file.c b/sha1_file.c index 477d3fb4b0..e2cb342a32 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2136,7 +2136,9 @@ static void write_sha1_file_prepare(const void *buf, unsigned long len, */ int move_temp_to_file(const char *tmpfile, const char *filename) { - int ret = link(tmpfile, filename); + int ret = 0; + if (link(tmpfile, filename)) + ret = errno; /* * Coda hack - coda doesn't like cross-directory links, diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index a841df2a9e..5b5f288809 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -135,3 +135,20 @@ close $wr or die $!; close $rd or die $!; EOF } + +require_svnserve () { + if test -z "$SVNSERVE_PORT" + then + say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)' + test_done + exit + fi +} + +start_svnserve () { + svnserve --listen-port $SVNSERVE_PORT \ + --root "$rawsvnrepo" \ + --listen-once \ + --listen-host 127.0.0.1 & +} + diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh new file mode 100644 index 0000000000..e5330395fc --- /dev/null +++ b/t/t0024-crlf-archive.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +test_description='respect crlf in git archive' + +. ./test-lib.sh +UNZIP=${UNZIP:-unzip} + +test_expect_success setup ' + + git config core.autocrlf true + + printf "CRLF line ending\r\nAnd another\r\n" > sample && + git add sample && + + test_tick && + git commit -m Initial + +' + +test_expect_success 'tar archive' ' + + git archive --format=tar HEAD | + ( mkdir untarred && cd untarred && "$TAR" -xf - ) + + test_cmp sample untarred/sample + +' + +"$UNZIP" -v >/dev/null 2>&1 +if [ $? -eq 127 ]; then + echo "Skipping ZIP test, because unzip was not found" + test_done + exit +fi + +test_expect_success 'zip archive' ' + + git archive --format=zip HEAD >test.zip && + + ( mkdir unzipped && cd unzipped && unzip ../test.zip ) && + + test_cmp sample unzipped/sample + +' + +test_done diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 833d6cbcfc..18bcd9713d 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -57,4 +57,10 @@ test_expect_success 'last regexp must not be negated' ' test_must_fail git diff --no-index Beer.java Beer-correct.java ' +test_expect_success 'alternation in pattern' ' + git config diff.java.funcname "^[ ]*\\(\\(public\\|static\\).*\\)$" + git diff --no-index Beer.java Beer-correct.java | + grep "^@@.*@@ public static void main(" +' + test_done diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 7eae1f4500..84a1fe3115 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -178,4 +178,16 @@ test_expect_success 'trailing empty lines (2)' ' ' +test_expect_success 'do not color trailing cr in context' ' + git config --unset core.whitespace + rm -f .gitattributes && + echo AAAQ | tr Q "\015" >G && + git add G && + echo BBBQ | tr Q "\015" >>G + git diff --color G | tr "\015" Q >output && + grep "BBB.*${blue_grep}Q" output && + grep "AAA.*\[mQ" output + +' + test_done diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index c8b4f65f38..5e359cb561 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -22,6 +22,7 @@ test_expect_success setup ' mkdir t && echo test >t/t && git add file x y z t/t && + test_tick && git commit -m initial ' @@ -113,4 +114,54 @@ do done +test_expect_success 'log grep setup' ' + echo a >>file && + test_tick && + GIT_AUTHOR_NAME="With * Asterisk" \ + GIT_AUTHOR_EMAIL="xyzzy@frotz.com" \ + git commit -a -m "second" && + + echo a >>file && + test_tick && + git commit -a -m "third" + +' + +test_expect_success 'log grep (1)' ' + git log --author=author --pretty=tformat:%s >actual && + ( echo third ; echo initial ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (2)' ' + git log --author=" * " -F --pretty=tformat:%s >actual && + ( echo second ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (3)' ' + git log --author="^A U" --pretty=tformat:%s >actual && + ( echo third ; echo initial ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (4)' ' + git log --author="frotz\.com>$" --pretty=tformat:%s >actual && + ( echo second ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (5)' ' + git log --author=Thor -F --grep=Thu --pretty=tformat:%s >actual && + ( echo third ; echo initial ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (6)' ' + git log --author=-0700 --pretty=tformat:%s >actual && + >expect && + test_cmp expect actual + +' + test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 2e2b3bf53d..fbec70d3c6 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -337,4 +337,26 @@ test_expect_success \ test refs/heads/delete-me = "$(git symbolic-ref HEAD)" && test_must_fail git checkout --track -b track' +test_expect_success 'checkout an unmerged path should fail' ' + rm -f .git/index && + O=$(echo original | git hash-object -w --stdin) && + A=$(echo ourside | git hash-object -w --stdin) && + B=$(echo theirside | git hash-object -w --stdin) && + ( + echo "100644 $A 0 fild" && + echo "100644 $O 1 file" && + echo "100644 $A 2 file" && + echo "100644 $B 3 file" && + echo "100644 $A 0 filf" + ) | git update-index --index-info && + echo "none of the above" >sample && + cat sample >fild && + cat sample >file && + cat sample >filf && + test_must_fail git checkout fild file filf && + test_cmp sample fild && + test_cmp sample filf && + test_cmp sample file +' + test_done diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 469bff8873..63bfc6d8b3 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -141,7 +141,7 @@ EOF test_expect_success \ 'validate git rev-list output.' \ - 'diff current expected' + 'test_cmp expected current' test_expect_success 'partial commit that involves removal (1)' ' @@ -151,7 +151,7 @@ test_expect_success 'partial commit that involves removal (1)' ' git commit -m "Partial: add elif" elif && git diff-tree --name-status HEAD^ HEAD >current && echo "A elif" >expected && - diff expected current + test_cmp expected current ' @@ -160,7 +160,7 @@ test_expect_success 'partial commit that involves removal (2)' ' git commit -m "Partial: remove file" file && git diff-tree --name-status HEAD^ HEAD >current && echo "D file" >expected && - diff expected current + test_cmp expected current ' @@ -171,7 +171,7 @@ test_expect_success 'partial commit that involves removal (3)' ' git commit -m "Partial: modify elif" elif && git diff-tree --name-status HEAD^ HEAD >current && echo "M elif" >expected && - diff expected current + test_cmp expected current ' @@ -187,7 +187,7 @@ test_expect_success 'amend commit to fix author' ' expected && git commit --amend --author="$author" && git cat-file -p HEAD > current && - diff expected current + test_cmp expected current ' @@ -256,7 +256,7 @@ test_expect_success 'amend commit to fix author' ' expected && git commit --amend --author="$author" && git cat-file -p HEAD > current && - diff expected current + test_cmp expected current ' diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh index ae78e334ac..c2b24a439d 100755 --- a/t/t9113-git-svn-dcommit-new-file.sh +++ b/t/t9113-git-svn-dcommit-new-file.sh @@ -12,19 +12,7 @@ test_description='git-svn dcommit new files over svn:// test' . ./lib-git-svn.sh -if test -z "$SVNSERVE_PORT" -then - say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)' - test_done - exit -fi - -start_svnserve () { - svnserve --listen-port $SVNSERVE_PORT \ - --root "$rawsvnrepo" \ - --listen-once \ - --listen-host 127.0.0.1 & -} +require_svnserve test_expect_success 'start tracking an empty repo' ' svn mkdir -m "empty dir" "$svnrepo"/empty-dir && diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 3281cbd347..43ceb75d59 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -6,6 +6,10 @@ test_description='git-svn funky branch names' . ./lib-git-svn.sh +# Abo-Uebernahme (Bug #994) +scary_uri='Abo-Uebernahme%20%28Bug%20%23994%29' +scary_ref='Abo-Uebernahme%20(Bug%20#994)' + test_expect_success 'setup svnrepo' ' mkdir project project/trunk project/branches project/tags && echo foo > project/trunk/foo && @@ -15,6 +19,8 @@ test_expect_success 'setup svnrepo' ' "$svnrepo/pr ject/branches/fun plugin" && svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \ "$svnrepo/pr ject/branches/more fun plugin!" && + svn cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \ + "$svnrepo/pr ject/branches/$scary_uri" && start_httpd ' @@ -23,6 +29,7 @@ test_expect_success 'test clone with funky branch names' ' cd project && git rev-parse "refs/remotes/fun%20plugin" && git rev-parse "refs/remotes/more%20fun%20plugin!" && + git rev-parse "refs/remotes/$scary_ref" && cd .. ' @@ -35,6 +42,15 @@ test_expect_success 'test dcommit to funky branch' " cd .. " +test_expect_success 'test dcommit to scary branch' ' + cd project && + git reset --hard "refs/remotes/$scary_ref" && + echo urls are scary >> foo && + git commit -m "eep" -- foo && + git svn dcommit && + cd .. + ' + stop_httpd test_done diff --git a/t/t9126-git-svn-follow-deleted-readded-directory.sh b/t/t9126-git-svn-follow-deleted-readded-directory.sh new file mode 100755 index 0000000000..edec640e97 --- /dev/null +++ b/t/t9126-git-svn-follow-deleted-readded-directory.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Copyright (c) 2008 Alec Berryman + +test_description='git svn fetch repository with deleted and readded directory' + +. ./lib-git-svn.sh + +# Don't run this by default; it opens up a port. +require_svnserve + +test_expect_success 'load repository' ' + svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9126/follow-deleted-readded.dump + ' + +test_expect_success 'fetch repository' ' + start_svnserve && + git svn init svn://127.0.0.1:$SVNSERVE_PORT && + git svn fetch + ' + +test_done diff --git a/t/t9126/follow-deleted-readded.dump b/t/t9126/follow-deleted-readded.dump new file mode 100644 index 0000000000..19da5d1ddc --- /dev/null +++ b/t/t9126/follow-deleted-readded.dump @@ -0,0 +1,201 @@ +SVN-fs-dump-format-version: 2 + +UUID: 1807dc6f-c693-4cda-9710-00e1be8c1f21 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2008-09-14T19:53:13.006748Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 111 +Content-length: 111 + +K 7 +svn:log +V 12 +Create trunk +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:13.239689Z +PROPS-END + +Node-path: trunk +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 2 +Prop-content-length: 119 +Content-length: 119 + +K 7 +svn:log +V 20 +Create trunk/project +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:13.548860Z +PROPS-END + +Node-path: trunk/project +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 3 +Prop-content-length: 111 +Content-length: 111 + +K 7 +svn:log +V 12 +add new file +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:15.433630Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 4 +Text-content-md5: d3b07384d113edec49eaa6238ad5ff00 +Content-length: 14 + +PROPS-END +foo + + +Revision-number: 4 +Prop-content-length: 116 +Content-length: 116 + +K 7 +svn:log +V 17 +change foo to bar +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:17.339884Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: c157a79031e1c40f85931829bc5fc552 +Content-length: 4 + +bar + + +Revision-number: 5 +Prop-content-length: 114 +Content-length: 114 + +K 7 +svn:log +V 15 +don't like that +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:19.335001Z +PROPS-END + +Node-path: trunk/project +Node-action: delete + + +Revision-number: 6 +Prop-content-length: 110 +Content-length: 110 + +K 7 +svn:log +V 11 +reset trunk +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:19.845897Z +PROPS-END + +Node-path: trunk/project +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 4 +Node-copyfrom-path: trunk/project + + +Revision-number: 7 +Prop-content-length: 113 +Content-length: 113 + +K 7 +svn:log +V 14 +change to quux +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:21.367947Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: change +Text-content-length: 5 +Text-content-md5: d3b07a382ec010c01889250fce66fb13 +Content-length: 5 + +quux + + diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 4d2312548a..504f95a47d 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -9,7 +9,6 @@ use Test::More qw(no_plan); use Cwd; use File::Basename; -use File::Temp; BEGIN { use_ok('Git') } @@ -38,7 +37,7 @@ is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color"); # Failure cases for config: # Save and restore STDERR; we will probably extract this into a # "dies_ok" method and possibly move the STDERR handling to Git.pm. -open our $tmpstderr, ">&", STDERR or die "cannot save STDERR"; close STDERR; +open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR; eval { $r->config("test.dupstring") }; ok($@, "config: duplicate entry in scalar context fails"); eval { $r->config_bool("test.boolother") }; @@ -69,21 +68,25 @@ is($r->ident_person("Name", "email", "123 +0000"), "Name <email>", # objects and hashes ok(our $file1hash = $r->command_oneline('rev-parse', "HEAD:file1"), "(get file hash)"); -our $tmpfile = File::Temp->new; -is($r->cat_blob($file1hash, $tmpfile), 15, "cat_blob: size"); +my $tmpfile = "file.tmp"; +open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!"; +is($r->cat_blob($file1hash, \*TEMPFILE), 15, "cat_blob: size"); our $blobcontents; -{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; } +{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; } is($blobcontents, "changed file 1\n", "cat_blob: data"); -seek $tmpfile, 0, 0; +close TEMPFILE or die "Failed writing to $tmpfile: $!"; is(Git::hash_object("blob", $tmpfile), $file1hash, "hash_object: roundtrip"); -$tmpfile = File::Temp->new(); -print $tmpfile my $test_text = "test blob, to be inserted\n"; +open TEMPFILE, ">$tmpfile" or die "Can't open $tmpfile: $!"; +print TEMPFILE my $test_text = "test blob, to be inserted\n"; +close TEMPFILE or die "Failed writing to $tmpfile: $!"; like(our $newhash = $r->hash_and_insert_object($tmpfile), qr/[0-9a-fA-F]{40}/, "hash_and_insert_object: returns hash"); -$tmpfile = File::Temp->new; -is($r->cat_blob($newhash, $tmpfile), length $test_text, "cat_blob: roundtrip size"); -{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; } +open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!"; +is($r->cat_blob($newhash, \*TEMPFILE), length $test_text, "cat_blob: roundtrip size"); +{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; } is($blobcontents, $test_text, "cat_blob: roundtrip data"); +close TEMPFILE; +unlink $tmpfile; # paths is($r->repo_path, "./.git", "repo_path"); diff --git a/templates/Makefile b/templates/Makefile index cc3fc3094c..a12c6e214e 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -23,17 +23,19 @@ all: boilerplates.made custom bpsrc = $(filter-out %~,$(wildcard *--*)) boilerplates.made : $(bpsrc) - $(QUIET)ls *--* 2>/dev/null | \ + $(QUIET)umask 022 && ls *--* 2>/dev/null | \ while read boilerplate; \ do \ case "$$boilerplate" in *~) continue ;; esac && \ dst=`echo "$$boilerplate" | sed -e 's|^this|.|;s|--|/|g'` && \ dir=`expr "$$dst" : '\(.*\)/'` && \ - $(INSTALL) -d -m 755 blt/$$dir && \ + mkdir -p blt/$$dir && \ case "$$boilerplate" in \ - *--) ;; \ - *) cp -p $$boilerplate blt/$$dst ;; \ - esac || exit; \ + *--) continue;; \ + esac && \ + cp $$boilerplate blt/$$dst && \ + if test -x "blt/$$dst"; then rx=rx; else rx=r; fi && \ + chmod a+$$rx "blt/$$dst" || exit; \ done && \ date >$@ |