diff --git a/Documentation/RelNotes-1.5.2.txt b/Documentation/RelNotes-1.5.2.txt index 712ebb0b78..02b8ea0a68 100644 --- a/Documentation/RelNotes-1.5.2.txt +++ b/Documentation/RelNotes-1.5.2.txt @@ -171,6 +171,6 @@ this release, unless otherwise noted. -- exec >/var/tmp/1 -O=v1.5.2-rc0-106-g07c785d +O=v1.5.2-rc1-32-g125a5f1 echo O=`git describe refs/heads/master` git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint diff --git a/Documentation/config.txt b/Documentation/config.txt index c257cdf525..24f9655fef 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -520,7 +520,7 @@ merge.summary:: merge.tool:: Controls which merge resolution program is used by gitlink:git-mergetool[l]. Valid values are: "kdiff3", "tkdiff", - "meld", "xxdiff", "emerge", "vimdiff" + "meld", "xxdiff", "emerge", "vimdiff", and "opendiff" merge.verbosity:: Controls the amount of output shown by the recursive merge diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt index 378e72f38f..e38a1f1405 100644 --- a/Documentation/diff-format.txt +++ b/Documentation/diff-format.txt @@ -59,6 +59,28 @@ When `-z` option is not used, TAB, LF, and backslash characters in pathnames are represented as `\t`, `\n`, and `\\`, respectively. +diff format for merges +---------------------- + +"git-diff-tree" and "git-diff-files" can take '-c' or '--cc' option +to generate diff output also for merge commits. The output differs +from the format described above in the following way: + +. there is a colon for each parent +. there are more "src" modes and "src" sha1 +. status is concatenated status characters for each parent +. no optional "score" number +. single path, only for "dst" + +Example: + +------------------------------------------------ +::100644 100644 100644 fabadb8... cc95eb0... 4866510... MM describe.c +------------------------------------------------ + +Note that 'combined diff' lists only files which were modified from +all parents. + Generating patches with -p -------------------------- diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 34288fe08b..add01e855a 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -25,7 +25,7 @@ OPTIONS -t or --tool=:: Use the merge resolution program specified by . Valid merge tools are: - kdiff3, tkdiff, meld, xxdiff, emerge, and vimdiff. + kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, and opendiff + If a merge resolution program is not specified, 'git mergetool' will use the configuration variable merge.tool. If the diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index a9fb6a9a5e..3dde7134a5 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -40,7 +40,7 @@ With `-t ` option, instead of the default glob refspec for the remote to track all branches under `$GIT_DIR/remotes//`, a refspec to track only `` is created. You can give more than one `-t ` to track -multiple branche without grabbing all branches. +multiple branches without grabbing all branches. + With `-m ` option, `$GIT_DIR/remotes//HEAD` is set up to point at remote's `` branch instead of whatever diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 62d7ef8be4..c0d7d9597b 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -38,32 +38,30 @@ COMMANDS argument. Normally this command initializes the current directory. --T:: ---trunk=:: --t:: ---tags=:: --b:: ---branches=:: +-T;; +--trunk=;; +-t;; +--tags=;; +-b;; +--branches=;; These are optional command-line options for init. Each of these flags can point to a relative repository path (--tags=project/tags') or a full url (--tags=https://foo.org/project/tags) - ---no-metadata:: +--no-metadata;; Set the 'noMetadata' option in the [svn-remote] config. ---use-svm-props:: +--use-svm-props;; Set the 'useSvmProps' option in the [svn-remote] config. ---use-svnsync-props:: +--use-svnsync-props;; Set the 'useSvnsyncProps' option in the [svn-remote] config. ---rewrite-root=:: +--rewrite-root=;; Set the 'rewriteRoot' option in the [svn-remote] config. ---username=:: +--username=;; For transports that SVN handles authentication for (http, https, and plain svn), specify the username. For other transports (eg svn+ssh://), you must include the username in the URL, eg svn+ssh://foo@svn.bar.com/project - ---prefix=:: +--prefix=;; This allows one to specify a prefix which is prepended to the names of remotes if trunk/branches/tags are specified. The prefix does not automatically include a @@ -73,7 +71,6 @@ COMMANDS repository. 'fetch':: - Fetch unfetched revisions from the Subversion remote we are tracking. The name of the [svn-remote "..."] section in the .git/config file may be specified as an optional command-line @@ -104,14 +101,11 @@ accepts. However '--fetch-all' only fetches from the current Like 'git-rebase'; this requires that the working tree be clean and have no uncommitted changes. -+ --- + -l;; --local;; Do not fetch remotely; only run 'git-rebase' against the last fetched commit from the upstream SVN. --- -+ 'dcommit':: Commit each diff from a specified head directly to the SVN @@ -125,6 +119,9 @@ and have no uncommitted changes. alternative to HEAD. This is advantageous over 'set-tree' (below) because it produces cleaner, more linear history. ++ +--no-rebase;; + After committing, do not rebase or reset. -- 'log':: diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 70235e8ddb..4e3e02756c 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -9,9 +9,10 @@ git-tag - Create, list, delete or verify a tag object signed with GPG SYNOPSIS -------- [verse] -'git-tag' [-a | -s | -u ] [-f | -v] [-m | -F ] [] +'git-tag' [-a | -s | -u ] [-f] [-m | -F ] [] 'git-tag' -d ... 'git-tag' -l [] +'git-tag' -v DESCRIPTION ----------- @@ -77,8 +78,10 @@ committer identity (of the form "Your Name ") to find a key. If you want to use a different default key, you can specify it in the repository configuration as follows: +------------------------------------- [user] signingkey = +------------------------------------- DISCUSSION diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt index e978562d6e..99efce4576 100644 --- a/Documentation/tutorial.txt +++ b/Documentation/tutorial.txt @@ -1,5 +1,5 @@ -A tutorial introduction to git -============================== +A tutorial introduction to git (for version 1.5.1 or newer) +=========================================================== This tutorial explains how to import a new project into git, make changes to it, and share changes with other developers. diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 9c4c41df5a..dff438f768 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -1,5 +1,5 @@ -Git User's Manual -_________________ +Git User's Manual (for version 1.5.1 or newer) +______________________________________________ This manual is designed to be readable by someone with basic unix command-line skills, but no previous knowledge of git. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 0a6ea68dec..f6adb91ed2 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.2-rc1.GIT +DEF_VER=v1.5.2-rc2.GIT LF=' ' diff --git a/Makefile b/Makefile index 7772e7327f..7a9cb066bf 100644 --- a/Makefile +++ b/Makefile @@ -302,8 +302,8 @@ LIB_OBJS = \ lockfile.o \ spawn-pipe.o \ patch-ids.o \ - object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \ - reachable.o reflog-walk.o \ + object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \ + sideband.o reachable.o reflog-walk.o \ quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ diff --git a/builtin-blame.c b/builtin-blame.c index 3442d282aa..35471fc261 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -20,13 +20,12 @@ #include "mailmap.h" static char blame_usage[] = -"git-blame [-c] [-b] [-l] [--root] [-x] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" +"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" " -c Use the same output mode as git-annotate (Default: off)\n" " -b Show blank SHA-1 for boundary commits (Default: off)\n" " -l Show long commit SHA1 (Default: off)\n" " --root Do not treat root commits as boundaries (Default: off)\n" " -t Show raw timestamp (Default: off)\n" -" -x Do not use .mailmap file\n" " -f, --show-name Show original filename (Default: auto)\n" " -n, --show-number Show original linenumber (Default: off)\n" " -s Suppress author name and timestamp (Default: off)\n" @@ -46,7 +45,6 @@ static int show_root; static int blank_boundary; static int incremental; static int cmd_is_annotate; -static int no_mailmap; static struct path_list mailmap; #ifndef DEBUG @@ -61,6 +59,7 @@ static int num_commits; #define PICKAXE_BLAME_MOVE 01 #define PICKAXE_BLAME_COPY 02 #define PICKAXE_BLAME_COPY_HARDER 04 +#define PICKAXE_BLAME_COPY_HARDEST 010 /* * blame for a blame_entry with score lower than these thresholds @@ -896,6 +895,39 @@ static void copy_split_if_better(struct scoreboard *sb, memcpy(best_so_far, this, sizeof(struct blame_entry [3])); } +/* + * We are looking at a part of the final image represented by + * ent (tlno and same are offset by ent->s_lno). + * tlno is where we are looking at in the final image. + * up to (but not including) same match preimage. + * plno is where we are looking at in the preimage. + * + * <-------------- final image ----------------------> + * <------ent------> + * ^tlno ^same + * <---------preimage-----> + * ^plno + * + * All line numbers are 0-based. + */ +static void handle_split(struct scoreboard *sb, + struct blame_entry *ent, + int tlno, int plno, int same, + struct origin *parent, + struct blame_entry *split) +{ + if (ent->num_lines <= tlno) + return; + if (tlno < same) { + struct blame_entry this[3]; + tlno += ent->s_lno; + same += ent->s_lno; + split_overlap(this, ent, tlno, plno, same, parent); + copy_split_if_better(sb, split, this); + decref_split(this); + } +} + /* * Find the lines from parent that are the same as ent so that * we can pass blames to it. file_p has the blob contents for @@ -928,26 +960,21 @@ static void find_copy_in_blob(struct scoreboard *sb, patch = compare_buffer(file_p, &file_o, 1); + /* + * file_o is a part of final image we are annotating. + * file_p partially may match that image. + */ memset(split, 0, sizeof(struct blame_entry [3])); plno = tlno = 0; for (i = 0; i < patch->num; i++) { struct chunk *chunk = &patch->chunks[i]; - /* tlno to chunk->same are the same as ent */ - if (ent->num_lines <= tlno) - break; - if (tlno < chunk->same) { - struct blame_entry this[3]; - split_overlap(this, ent, - tlno + ent->s_lno, plno, - chunk->same + ent->s_lno, - parent); - copy_split_if_better(sb, split, this); - decref_split(this); - } + handle_split(sb, ent, tlno, plno, chunk->same, parent, split); plno = chunk->p_next; tlno = chunk->t_next; } + /* remainder, if any, all match the preimage */ + handle_split(sb, ent, tlno, plno, ent->num_lines, parent, split); free_patch(patch); } @@ -1057,8 +1084,9 @@ static int find_copy_in_parent(struct scoreboard *sb, * and this code needs to be after diff_setup_done(), which * usually makes find-copies-harder imply copy detection. */ - if ((opt & PICKAXE_BLAME_COPY_HARDER) && - (!porigin || strcmp(target->path, porigin->path))) + if ((opt & PICKAXE_BLAME_COPY_HARDEST) + || ((opt & PICKAXE_BLAME_COPY_HARDER) + && (!porigin || strcmp(target->path, porigin->path)))) diff_opts.find_copies_harder = 1; if (is_null_sha1(target->commit->object.sha1)) @@ -2138,6 +2166,15 @@ int cmd_blame(int argc, const char **argv, const char *prefix) blame_move_score = parse_score(arg+2); } else if (!prefixcmp(arg, "-C")) { + /* + * -C enables copy from removed files; + * -C -C enables copy from existing files, but only + * when blaming a new file; + * -C -C -C enables copy from existing files for + * everybody + */ + if (opt & PICKAXE_BLAME_COPY_HARDER) + opt |= PICKAXE_BLAME_COPY_HARDEST; if (opt & PICKAXE_BLAME_COPY) opt |= PICKAXE_BLAME_COPY_HARDER; opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE; @@ -2173,9 +2210,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix) else if (!strcmp("-p", arg) || !strcmp("--porcelain", arg)) output_option |= OUTPUT_PORCELAIN; - else if (!strcmp("-x", arg) || - !strcmp("--no-mailmap", arg)) - no_mailmap = 1; else if (!strcmp("--", arg)) { seen_dashdash = 1; i++; @@ -2375,8 +2409,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) die("reading graft file %s failed: %s", revs_file, strerror(errno)); - if (!no_mailmap) - read_mailmap(&mailmap, ".mailmap", NULL); + read_mailmap(&mailmap, ".mailmap", NULL); assign_blame(&sb, &revs, opt); diff --git a/commit.c b/commit.c index f1ba972d9a..d01833d813 100644 --- a/commit.c +++ b/commit.c @@ -638,7 +638,9 @@ static char *get_header(const struct commit *commit, const char *key) next = NULL; } else next = eol + 1; - if (!strncmp(line, key, key_len) && line[key_len] == ' ') { + if (eol - line > key_len && + !strncmp(line, key, key_len) && + line[key_len] == ' ') { int len = eol - line - key_len; char *ret = xmalloc(len); memcpy(ret, line + key_len + 1, len - 1); @@ -718,14 +720,6 @@ static char *logmsg_reencode(const struct commit *commit, return out; } -static char *xstrndup(const char *text, int len) -{ - char *result = xmalloc(len + 1); - memcpy(result, text, len); - result[len] = '\0'; - return result; -} - static void fill_person(struct interp *table, const char *msg, int len) { int start, end, tz = 0; diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index d2363a415d..a43b2c52f0 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -52,6 +52,25 @@ foreach my $tar_file (@ARGV) Z8 Z1 Z100 Z6 Z2 Z32 Z32 Z8 Z8 Z*', $_; last unless $name; + if ($name eq '././@LongLink') { + # GNU tar extension + if (read(I, $_, 512) != 512) { + die ('Short archive'); + } + $name = unpack 'Z257', $_; + next unless $name; + + my $dummy; + if (read(I, $_, 512) != 512) { + die ('Short archive'); + } + ($dummy, $mode, $uid, $gid, $size, $mtime, + $chksum, $typeflag, $linkname, $magic, + $version, $uname, $gname, $devmajor, $devminor, + $prefix) = unpack 'Z100 Z8 Z8 Z8 Z12 Z12 + Z8 Z1 Z100 Z6 + Z2 Z32 Z32 Z8 Z8 Z*', $_; + } next if $name =~ m{/\z}; $mode = oct $mode; $size = oct $size; diff --git a/diff.c b/diff.c index b012c784db..bb6527cb43 100644 --- a/diff.c +++ b/diff.c @@ -1573,14 +1573,15 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) enum object_type type; struct sha1_size_cache *e; + if (size_only && use_size_cache && + (e = locate_size_cache(s->sha1, 1, 0)) != NULL) { + s->size = e->size; + return 0; + } + if (size_only) { - e = locate_size_cache(s->sha1, 1, 0); - if (e) { - s->size = e->size; - return 0; - } type = sha1_object_info(s->sha1, &s->size); - if (type < 0) + if (use_size_cache && 0 < type) locate_size_cache(s->sha1, 0, s->size); } else { diff --git a/fast-import.c b/fast-import.c index b4cbcd9011..3a2d5ed8e6 100644 --- a/fast-import.c +++ b/fast-import.c @@ -651,42 +651,6 @@ static void start_packfile(void) all_packs[pack_id] = p; } -static void fixup_header_footer(void) -{ - static const int buf_sz = 128 * 1024; - int pack_fd = pack_data->pack_fd; - SHA_CTX c; - struct pack_header hdr; - char *buf; - - if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start: %s", strerror(errno)); - if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - die("Unable to reread header of %s", pack_data->pack_name); - if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start: %s", strerror(errno)); - hdr.hdr_entries = htonl(object_count); - write_or_die(pack_fd, &hdr, sizeof(hdr)); - - SHA1_Init(&c); - SHA1_Update(&c, &hdr, sizeof(hdr)); - - buf = xmalloc(buf_sz); - for (;;) { - ssize_t n = xread(pack_fd, buf, buf_sz); - if (!n) - break; - if (n < 0) - die("Failed to checksum %s", pack_data->pack_name); - SHA1_Update(&c, buf, n); - } - free(buf); - - SHA1_Final(pack_data->sha1, &c); - write_or_die(pack_fd, pack_data->sha1, sizeof(pack_data->sha1)); - close(pack_fd); -} - static int oecmp (const void *a_, const void *b_) { struct object_entry *a = *((struct object_entry**)a_); @@ -802,7 +766,9 @@ static void end_packfile(void) struct branch *b; struct tag *t; - fixup_header_footer(); + fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1, + pack_data->pack_name, object_count); + close(pack_data->pack_fd); idx_name = keep_pack(create_index()); /* Register the packfile with core git's machinary. */ diff --git a/git-compat-util.h b/git-compat-util.h index 56a8eb1971..ec377d3d72 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -204,6 +204,19 @@ static inline void *xmalloc(size_t size) return ret; } +static inline char *xstrndup(const char *str, size_t len) +{ + char *p; + + p = memchr(str, '\0', len); + if (p) + len = p - str; + p = xmalloc(len + 1); + memcpy(p, str, len); + p[len] = '\0'; + return p; +} + static inline void *xrealloc(void *ptr, size_t size) { void *ret = realloc(ptr, size); diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 087e3abaef..3e7bf5b54a 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2519,7 +2519,7 @@ sub update #$log->debug("ADDED $name"); $head->{$name} = { name => $name, - revision => 1, + revision => $head->{$name}{revision} ? $head->{$name}{revision}+1 : 1, filehash => $hash, commithash => $commit->{hash}, modified => $commit->{date}, diff --git a/git-request-pull.sh b/git-request-pull.sh index 4eacc3a059..ba577d4ce1 100755 --- a/git-request-pull.sh +++ b/git-request-pull.sh @@ -9,25 +9,48 @@ LONG_USAGE='Summarizes the changes since to the standard output, and includes in the message generated.' SUBDIRECTORY_OK='Yes' . git-sh-setup +. git-parse-remote -revision=$1 +base=$1 url=$2 head=${3-HEAD} -[ "$revision" ] || usage +[ "$base" ] || usage [ "$url" ] || usage -baserev=`git-rev-parse --verify "$revision"^0` && +baserev=`git-rev-parse --verify "$base"^0` && headrev=`git-rev-parse --verify "$head"^0` || exit +merge_base=`git merge-base $baserev $headrev` || +die "fatal: No commits in common between $base and $head" + +url="`get_remote_url "$url"`" +branch=`git peek-remote "$url" \ + | sed -n -e "/^$headrev refs.heads./{ + s/^.* refs.heads.// + p + q + }"` +if [ -z "$branch" ]; then + echo "warn: No branch of $url is at:" >&2 + git log --max-count=1 --pretty='format:warn: %h: %s' $headrev >&2 + echo "warn: Are you sure you pushed $head there?" >&2 + echo >&2 + echo >&2 + branch=..BRANCH.NOT.VERIFIED.. + status=1 +fi + +PAGER= +export PAGER echo "The following changes since commit $baserev:" -git log --max-count=1 --pretty=short "$baserev" | -git-shortlog | sed -e 's/^\(.\)/ \1/' +git shortlog --max-count=1 $baserev | sed -e 's/^\(.\)/ \1/' -echo "are found in the git repository at:" +echo "are available in the git repository at:" echo -echo " $url" +echo " $url $branch" echo -git log $baserev..$headrev | git-shortlog ; -git diff -M --stat --summary $baserev..$headrev +git shortlog ^$baserev $headrev +git diff -M --stat --summary $merge_base $headrev +exit $status diff --git a/git-svn.perl b/git-svn.perl index 6657e100fb..3c4f490b74 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -55,7 +55,7 @@ $sha1_short = qr/[a-f\d]{4,40}/; my ($_stdin, $_help, $_edit, $_message, $_file, $_template, $_shared, - $_version, $_fetch_all, + $_version, $_fetch_all, $_no_rebase, $_merge, $_strategy, $_dry_run, $_local, $_prefix, $_no_checkout, $_verbose); $Git::SVN::_follow_parent = 1; @@ -114,6 +114,7 @@ my %cmd = ( 'verbose|v' => \$_verbose, 'dry-run|n' => \$_dry_run, 'fetch-all|all' => \$_fetch_all, + 'no-rebase' => \$_no_rebase, %cmt_opts, %fc_opts } ], 'set-tree' => [ \&cmd_set_tree, "Set an SVN repository to a git tree-ish", @@ -413,21 +414,23 @@ sub cmd_dcommit { return; } $_fetch_all ? $gs->fetch_all : $gs->fetch; - # we always want to rebase against the current HEAD, not any - # head that was passed to us - my @diff = command('diff-tree', 'HEAD', $gs->refname, '--'); - my @finish; - if (@diff) { - @finish = rebase_cmd(); - print STDERR "W: HEAD and ", $gs->refname, " differ, ", - "using @finish:\n", "@diff"; - } else { - print "No changes between current HEAD and ", - $gs->refname, "\nResetting to the latest ", - $gs->refname, "\n"; - @finish = qw/reset --mixed/; + unless ($_no_rebase) { + # we always want to rebase against the current HEAD, not any + # head that was passed to us + my @diff = command('diff-tree', 'HEAD', $gs->refname, '--'); + my @finish; + if (@diff) { + @finish = rebase_cmd(); + print STDERR "W: HEAD and ", $gs->refname, " differ, ", + "using @finish:\n", "@diff"; + } else { + print "No changes between current HEAD and ", + $gs->refname, "\nResetting to the latest ", + $gs->refname, "\n"; + @finish = qw/reset --mixed/; + } + command_noisy(@finish, $gs->refname); } - command_noisy(@finish, $gs->refname); } sub cmd_find_rev { diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index cbd8d03e64..ba5cc43e5b 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -564,12 +564,6 @@ sub validate_refname { return $input; } -# very thin wrapper for decode("utf8", $str, Encode::FB_DEFAULT); -sub to_utf8 { - my $str = shift; - return decode("utf8", $str, Encode::FB_DEFAULT); -} - # quote unsafe chars, but keep the slash, even when it's not # correct, but quoted slashes look too horrible in bookmarks sub esc_param { @@ -594,7 +588,7 @@ sub esc_html ($;%) { my $str = shift; my %opts = @_; - $str = to_utf8($str); + $str = decode_utf8($str); $str = $cgi->escapeHTML($str); if ($opts{'-nbsp'}) { $str =~ s/ / /g; @@ -608,7 +602,7 @@ sub esc_path { my $str = shift; my %opts = @_; - $str = to_utf8($str); + $str = decode_utf8($str); $str = $cgi->escapeHTML($str); if ($opts{'-nbsp'}) { $str =~ s/ / /g; @@ -891,7 +885,7 @@ sub format_subject_html { if (length($short) < length($long)) { return $cgi->a({-href => $href, -class => "list subject", - -title => to_utf8($long)}, + -title => decode_utf8($long)}, esc_html($short) . $extra); } else { return $cgi->a({-href => $href, -class => "list subject"}, @@ -1126,7 +1120,7 @@ sub git_get_projects_list { if (check_export_ok("$projectroot/$path")) { my $pr = { path => $path, - owner => to_utf8($owner), + owner => decode_utf8($owner), }; push @list, $pr; (my $forks_path = $path) =~ s/\.git$//; @@ -1156,7 +1150,7 @@ sub git_get_project_owner { $pr = unescape($pr); $ow = unescape($ow); if ($pr eq $project) { - $owner = to_utf8($ow); + $owner = decode_utf8($ow); last; } } @@ -1630,7 +1624,7 @@ sub get_file_owner { } my $owner = $gcos; $owner =~ s/[,;].*$//; - return to_utf8($owner); + return decode_utf8($owner); } ## ...................................................................... @@ -1713,7 +1707,7 @@ sub git_header_html { my $title = "$site_name"; if (defined $project) { - $title .= " - " . to_utf8($project); + $title .= " - " . decode_utf8($project); if (defined $action) { $title .= "/$action"; if (defined $file_name) { @@ -1986,7 +1980,7 @@ sub git_print_page_path { print "
"; print $cgi->a({-href => href(action=>"tree", hash_base=>$hb), - -title => 'tree root'}, to_utf8("[$project]")); + -title => 'tree root'}, decode_utf8("[$project]")); print " / "; if (defined $name) { my @dirname = split '/', $name; @@ -2604,7 +2598,7 @@ sub git_project_list_body { ($pr->{'age'}, $pr->{'age_string'}) = @aa; if (!defined $pr->{'descr'}) { my $descr = git_get_project_description($pr->{'path'}) || ""; - $pr->{'descr_long'} = to_utf8($descr); + $pr->{'descr_long'} = decode_utf8($descr); $pr->{'descr'} = chop_str($descr, 25, 5); } if (!defined $pr->{'owner'}) { @@ -3636,7 +3630,7 @@ sub git_snapshot { $hash = git_get_head_hash($project); } - my $filename = to_utf8(basename($project)) . "-$hash.tar.$suffix"; + my $filename = decode_utf8(basename($project)) . "-$hash.tar.$suffix"; print $cgi->header( -type => "application/$ctype", diff --git a/http.h b/http.h index 324fcf4f54..69b6b667d9 100644 --- a/http.h +++ b/http.h @@ -6,7 +6,7 @@ #include #include -#if LIBCURL_VERSION_NUM >= 0x070908 +#if LIBCURL_VERSION_NUM >= 0x071000 #define USE_CURL_MULTI #define DEFAULT_MAX_REQUESTS 5 #endif diff --git a/index-pack.c b/index-pack.c index 824004f9a2..b9da19f55b 100644 --- a/index-pack.c +++ b/index-pack.c @@ -602,37 +602,6 @@ static void fix_unresolved_deltas(int nr_unresolved) free(sorted_by_pos); } -static void readjust_pack_header_and_sha1(unsigned char *sha1) -{ - struct pack_header hdr; - SHA_CTX ctx; - int size; - - /* Rewrite pack header with updated object number */ - if (lseek(output_fd, 0, SEEK_SET) != 0) - die("cannot seek back: %s", strerror(errno)); - if (read_in_full(output_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - die("cannot read pack header back: %s", strerror(errno)); - hdr.hdr_entries = htonl(nr_objects); - if (lseek(output_fd, 0, SEEK_SET) != 0) - die("cannot seek back: %s", strerror(errno)); - write_or_die(output_fd, &hdr, sizeof(hdr)); - if (lseek(output_fd, 0, SEEK_SET) != 0) - die("cannot seek back: %s", strerror(errno)); - - /* Recompute and store the new pack's SHA1 */ - SHA1_Init(&ctx); - do { - unsigned char *buf[4096]; - size = xread(output_fd, buf, sizeof(buf)); - if (size < 0) - die("cannot read pack data back: %s", strerror(errno)); - SHA1_Update(&ctx, buf, size); - } while (size > 0); - SHA1_Final(sha1, &ctx); - write_or_die(output_fd, sha1, 20); -} - static uint32_t index_default_version = 1; static uint32_t index_off32_limit = 0x7fffffff; @@ -963,7 +932,8 @@ int main(int argc, char **argv) fprintf(stderr, "%d objects were added to complete this thin pack.\n", nr_objects - nr_objects_initial); } - readjust_pack_header_and_sha1(sha1); + fixup_pack_header_footer(output_fd, sha1, + curr_pack, nr_objects); } if (nr_deltas != nr_resolved_deltas) die("pack has %d unresolved deltas", diff --git a/log-tree.c b/log-tree.c index c679324c07..4bef909144 100644 --- a/log-tree.c +++ b/log-tree.c @@ -244,10 +244,10 @@ void show_log(struct rev_info *opt, const char *sep) stdout); if (opt->commit_format != CMIT_FMT_ONELINE) fputs("commit ", stdout); - if (opt->left_right) { - if (commit->object.flags & BOUNDARY) - putchar('-'); - else if (commit->object.flags & SYMMETRIC_LEFT) + if (commit->object.flags & BOUNDARY) + putchar('-'); + else if (opt->left_right) { + if (commit->object.flags & SYMMETRIC_LEFT) putchar('<'); else putchar('>'); diff --git a/pack-write.c b/pack-write.c new file mode 100644 index 0000000000..de72f44dc8 --- /dev/null +++ b/pack-write.c @@ -0,0 +1,39 @@ +#include "cache.h" +#include "pack.h" + +void fixup_pack_header_footer(int pack_fd, + unsigned char *pack_file_sha1, + const char *pack_name, + uint32_t object_count) +{ + static const int buf_sz = 128 * 1024; + SHA_CTX c; + struct pack_header hdr; + char *buf; + + if (lseek(pack_fd, 0, SEEK_SET) != 0) + die("Failed seeking to start: %s", 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)); + hdr.hdr_entries = htonl(object_count); + write_or_die(pack_fd, &hdr, sizeof(hdr)); + + SHA1_Init(&c); + SHA1_Update(&c, &hdr, sizeof(hdr)); + + buf = xmalloc(buf_sz); + for (;;) { + size_t n = xread(pack_fd, buf, buf_sz); + if (!n) + break; + if (n < 0) + die("Failed to checksum %s: %s", pack_name, strerror(errno)); + SHA1_Update(&c, buf, n); + } + free(buf); + + SHA1_Final(pack_file_sha1, &c); + write_or_die(pack_fd, pack_file_sha1, 20); +} diff --git a/pack.h b/pack.h index d4d412ccbb..d667fb8d5a 100644 --- a/pack.h +++ b/pack.h @@ -44,6 +44,7 @@ struct pack_idx_header { extern int verify_pack(struct packed_git *, int); +extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t); #define PH_ERROR_EOF (-1) #define PH_ERROR_PACK_SIGNATURE (-2) diff --git a/perl/Makefile b/perl/Makefile index 05763e45e5..c8c764fff6 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -37,7 +37,7 @@ $(makfile): ../GIT-CFLAGS Makefile echo ' echo $(instdir_SQ)' >> $@ else $(makfile): Makefile.PL ../GIT-CFLAGS - '$(PERL_PATH_SQ)' $< PREFIX='$(prefix_SQ)' + $(PERL_PATH) $< PREFIX='$(prefix_SQ)' endif # this is just added comfort for calling make directly in perl dir diff --git a/revision.c b/revision.c index e60a26c6bb..0125d41136 100644 --- a/revision.c +++ b/revision.c @@ -318,7 +318,10 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) while ((parent = *pp) != NULL) { struct commit *p = parent->item; - parse_commit(p); + if (parse_commit(p) < 0) + die("cannot simplify commit %s (because of %s)", + sha1_to_hex(commit->object.sha1), + sha1_to_hex(p->object.sha1)); switch (rev_compare_tree(revs, p->tree, commit->tree)) { case REV_TREE_SAME: tree_same = 1; @@ -347,7 +350,10 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) * IOW, we pretend this parent is a * "root" commit. */ - parse_commit(p); + if (parse_commit(p) < 0) + die("cannot simplify commit %s (invalid %s)", + sha1_to_hex(commit->object.sha1), + sha1_to_hex(p->object.sha1)); p->parents = NULL; } /* fallthrough */ @@ -362,14 +368,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) commit->object.flags |= TREECHANGE; } -static void add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list) +static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list) { struct commit_list *parent = commit->parents; unsigned left_flag; int add, rest; if (commit->object.flags & ADDED) - return; + return 0; commit->object.flags |= ADDED; /* @@ -388,7 +394,8 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st while (parent) { struct commit *p = parent->item; parent = parent->next; - parse_commit(p); + if (parse_commit(p) < 0) + return -1; p->object.flags |= UNINTERESTING; if (p->parents) mark_parents_uninteresting(p); @@ -397,7 +404,7 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st p->object.flags |= SEEN; insert_by_date(p, list); } - return; + return 0; } /* @@ -409,7 +416,7 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st revs->prune_fn(revs, commit); if (revs->no_walk) - return; + return 0; left_flag = (commit->object.flags & SYMMETRIC_LEFT); @@ -418,7 +425,8 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st struct commit *p = parent->item; parent = parent->next; - parse_commit(p); + if (parse_commit(p) < 0) + return -1; p->object.flags |= left_flag; if (p->object.flags & SEEN) continue; @@ -426,6 +434,7 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st if (add) insert_by_date(p, list); } + return 0; } static void cherry_pick_list(struct commit_list *list) @@ -508,7 +517,7 @@ static void cherry_pick_list(struct commit_list *list) free_patch_ids(&ids); } -static void limit_list(struct rev_info *revs) +static int limit_list(struct rev_info *revs) { struct commit_list *list = revs->commits; struct commit_list *newlist = NULL; @@ -524,7 +533,8 @@ static void limit_list(struct rev_info *revs) if (revs->max_age != -1 && (commit->date < revs->max_age)) obj->flags |= UNINTERESTING; - add_parents_to_list(revs, commit, &list); + if (add_parents_to_list(revs, commit, &list) < 0) + return -1; if (obj->flags & UNINTERESTING) { mark_parents_uninteresting(commit); if (everybody_uninteresting(list)) @@ -539,6 +549,7 @@ static void limit_list(struct rev_info *revs) cherry_pick_list(newlist); revs->commits = newlist; + return 0; } struct all_refs_cb { @@ -1227,7 +1238,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch return left; } -void prepare_revision_walk(struct rev_info *revs) +int prepare_revision_walk(struct rev_info *revs) { int nr = revs->pending.nr; struct object_array_entry *e, *list; @@ -1249,42 +1260,57 @@ void prepare_revision_walk(struct rev_info *revs) free(list); if (revs->no_walk) - return; + return 0; if (revs->limited) - limit_list(revs); + if (limit_list(revs) < 0) + return -1; if (revs->topo_order) sort_in_topological_order_fn(&revs->commits, revs->lifo, revs->topo_setter, revs->topo_getter); + return 0; } -static int rewrite_one(struct rev_info *revs, struct commit **pp) +enum rewrite_result { + rewrite_one_ok, + rewrite_one_noparents, + rewrite_one_error, +}; + +static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp) { for (;;) { struct commit *p = *pp; if (!revs->limited) - add_parents_to_list(revs, p, &revs->commits); + if (add_parents_to_list(revs, p, &revs->commits) < 0) + return rewrite_one_error; if (p->parents && p->parents->next) - return 0; + return rewrite_one_ok; if (p->object.flags & (TREECHANGE | UNINTERESTING)) - return 0; + return rewrite_one_ok; if (!p->parents) - return -1; + return rewrite_one_noparents; *pp = p->parents->item; } } -static void rewrite_parents(struct rev_info *revs, struct commit *commit) +static int rewrite_parents(struct rev_info *revs, struct commit *commit) { struct commit_list **pp = &commit->parents; while (*pp) { struct commit_list *parent = *pp; - if (rewrite_one(revs, &parent->item) < 0) { + switch (rewrite_one(revs, &parent->item)) { + case rewrite_one_ok: + break; + case rewrite_one_noparents: *pp = parent->next; continue; + case rewrite_one_error: + return -1; } pp = &parent->next; } + return 0; } static int commit_match(struct commit *commit, struct rev_info *opt) @@ -1320,7 +1346,8 @@ static struct commit *get_revision_1(struct rev_info *revs) if (revs->max_age != -1 && (commit->date < revs->max_age)) continue; - add_parents_to_list(revs, commit, &revs->commits); + if (add_parents_to_list(revs, commit, &revs->commits) < 0) + return NULL; } if (commit->object.flags & SHOWN) continue; @@ -1348,8 +1375,8 @@ static struct commit *get_revision_1(struct rev_info *revs) if (!commit->parents || !commit->parents->next) continue; } - if (revs->parents) - rewrite_parents(revs, commit); + if (revs->parents && rewrite_parents(revs, commit) < 0) + return NULL; } return commit; } while (revs->commits); diff --git a/revision.h b/revision.h index cdf94ad695..2845167746 100644 --- a/revision.h +++ b/revision.h @@ -113,7 +113,7 @@ extern void init_revisions(struct rev_info *revs, const char *prefix); extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def); extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename); -extern void prepare_revision_walk(struct rev_info *revs); +extern int prepare_revision_walk(struct rev_info *revs); extern struct commit *get_revision(struct rev_info *revs); extern void mark_parents_uninteresting(struct commit *commit); diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index 6ba63d7173..c64ebbb2e9 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -44,7 +44,7 @@ mkdir .git/rr-cache test_expect_failure 'conflicting merge' 'git pull . first' -sha1=$(sed -e 's/\t.*//' .git/rr-cache/MERGE_RR) +sha1=$(sed -e 's/ .*//' .git/rr-cache/MERGE_RR) rr=.git/rr-cache/$sha1 test_expect_success 'recorded preimage' "grep ======= $rr/preimage" diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 6902fc6d48..4d06eca6a5 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -10,11 +10,14 @@ test_expect_success \ 'setup' \ 'rm -rf .git git-init && - for i in `seq -w 100` + i=1 && + while test $i -le 100 do + i=`printf '%03i' $i` echo $i >file_$i && test-genrandom "$i" 8192 >>file_$i && - git-update-index --add file_$i || return 1 + git-update-index --add file_$i && + i=`expr $i + 1` || return 1 done && { echo 101 && test-genrandom 100 8192; } >file_101 && git-update-index --add file_101 && diff --git a/t/t8003-blame.sh b/t/t8003-blame.sh new file mode 100755 index 0000000000..db51b3a6bb --- /dev/null +++ b/t/t8003-blame.sh @@ -0,0 +1,132 @@ +#!/bin/sh + +test_description='git blame corner cases' +. ./test-lib.sh + +pick_fc='s/^[0-9a-f^]* *\([^ ]*\) *(\([^ ]*\) .*/\1-\2/' + +test_expect_success setup ' + + echo A A A A A >one && + echo B B B B B >two && + echo C C C C C >tres && + echo ABC >mouse && + git add one two tres mouse && + test_tick && + GIT_AUTHOR_NAME=Initial git commit -m Initial && + + cat one >uno && + mv two dos && + cat one >>tres && + echo DEF >>mouse + git add uno dos tres mouse && + test_tick && + GIT_AUTHOR_NAME=Second git commit -a -m Second && + + echo GHIJK >>mouse && + git add mouse && + test_tick && + GIT_AUTHOR_NAME=Third git commit -m Third && + + cat mouse >cow && + git add cow && + test_tick && + GIT_AUTHOR_NAME=Fourth git commit -m Fourth && + + { + echo ABC + echo DEF + echo XXXX + echo GHIJK + } >cow && + git add cow && + test_tick && + GIT_AUTHOR_NAME=Fifth git commit -m Fifth +' + +test_expect_success 'straight copy without -C' ' + + git blame uno | grep Second + +' + +test_expect_success 'straight move without -C' ' + + git blame dos | grep Initial + +' + +test_expect_success 'straight copy with -C' ' + + git blame -C1 uno | grep Second + +' + +test_expect_success 'straight move with -C' ' + + git blame -C1 dos | grep Initial + +' + +test_expect_success 'straight copy with -C -C' ' + + git blame -C -C1 uno | grep Initial + +' + +test_expect_success 'straight move with -C -C' ' + + git blame -C -C1 dos | grep Initial + +' + +test_expect_success 'append without -C' ' + + git blame -L2 tres | grep Second + +' + +test_expect_success 'append with -C' ' + + git blame -L2 -C1 tres | grep Second + +' + +test_expect_success 'append with -C -C' ' + + git blame -L2 -C -C1 tres | grep Second + +' + +test_expect_success 'append with -C -C -C' ' + + git blame -L2 -C -C -C1 tres | grep Initial + +' + +test_expect_success 'blame wholesale copy' ' + + git blame -f -C -C1 HEAD^ -- cow | sed -e "$pick_fc" >current && + { + echo mouse-Initial + echo mouse-Second + echo mouse-Third + } >expected && + diff -u expected current + +' + +test_expect_success 'blame wholesale copy and more' ' + + git blame -f -C -C1 HEAD -- cow | sed -e "$pick_fc" >current && + { + echo mouse-Initial + echo mouse-Second + echo cow-Fifth + echo mouse-Third + } >expected && + diff -u expected current + +' + +test_done diff --git a/test-delta.c b/test-delta.c index 16595ef0a9..3d885ff37e 100644 --- a/test-delta.c +++ b/test-delta.c @@ -10,8 +10,9 @@ #include "git-compat-util.h" #include "delta.h" +#include "cache.h" -static const char usage[] = +static const char usage_str[] = "test-delta (-d|-p) "; int main(int argc, char *argv[]) @@ -22,7 +23,7 @@ int main(int argc, char *argv[]) unsigned long from_size, data_size, out_size; if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) { - fprintf(stderr, "Usage: %s\n", usage); + fprintf(stderr, "Usage: %s\n", usage_str); return 1; }