diff options
-rw-r--r-- | Documentation/git-am.txt | 9 | ||||
-rw-r--r-- | Documentation/git-apply.txt | 30 | ||||
-rw-r--r-- | Documentation/git-read-tree.txt | 15 | ||||
-rw-r--r-- | Documentation/git-rev-list.txt | 10 | ||||
-rw-r--r-- | Documentation/git-svnimport.txt | 5 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | apply.c | 2 | ||||
-rw-r--r-- | cat-file.c | 119 | ||||
-rwxr-xr-x | contrib/git-svn/git-svn.perl | 63 | ||||
-rw-r--r-- | contrib/git-svn/git-svn.txt | 18 | ||||
-rw-r--r-- | contrib/git-svn/t/t0000-contrib-git-svn.sh | 36 | ||||
-rwxr-xr-x | contrib/gitview/gitview | 5 | ||||
-rw-r--r-- | diffcore-break.c | 21 | ||||
-rw-r--r-- | diffcore-delta.c | 43 | ||||
-rw-r--r-- | diffcore-rename.c | 28 | ||||
-rw-r--r-- | diffcore.h | 6 | ||||
-rwxr-xr-x | git-am.sh | 3 | ||||
-rwxr-xr-x | git-annotate.perl | 20 | ||||
-rwxr-xr-x | git-svnimport.perl | 25 | ||||
-rwxr-xr-x | git-verify-tag.sh | 21 | ||||
-rw-r--r-- | read-tree.c | 8 | ||||
-rw-r--r-- | refs.c | 9 | ||||
-rwxr-xr-x | t/t8001-annotate.sh | 89 |
23 files changed, 470 insertions, 118 deletions
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 02cabc935..910457d3b 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -9,7 +9,8 @@ git-am - Apply a series of patches in a mailbox SYNOPSIS -------- [verse] -'git-am' [--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox>... +'git-am' [--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] + [--interactive] [--whitespace=<option>] <mbox>... 'git-am' [--skip | --resolved] DESCRIPTION @@ -46,6 +47,10 @@ OPTIONS Skip the current patch. This is only meaningful when restarting an aborted patch. +--whitespace=<option>:: + This flag is passed to the `git-apply` program that applies + the patch. + --interactive:: Run interactively, just like git-applymbox. @@ -80,7 +85,7 @@ names. SEE ALSO -------- -gitlink:git-applymbox[1], gitlink:git-applypatch[1]. +gitlink:git-applymbox[1], gitlink:git-applypatch[1], gitlink:git-apply[1]. Author diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index 75076b612..1c64a1aa8 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -11,6 +11,7 @@ SYNOPSIS [verse] 'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] + [--whitespace=<nowarn|warn|error|error-all|strip>] [<patch>...] DESCRIPTION @@ -97,6 +98,35 @@ OPTIONS result. This allows binary files to be patched in a very limited way. +--whitespace=<option>:: + When applying a patch, detect a new or modified line + that ends with trailing whitespaces (this includes a + line that solely consists of whitespaces). By default, + the command outputs warning messages and applies the + patch. + When `git-apply` is used for statistics and not applying a + patch, it defaults to `nowarn`. + You can use different `<option>` to control this + behaviour: ++ +* `nowarn` turns off the trailing whitespace warning. +* `warn` outputs warnings for a few such errors, but applies the + patch (default). +* `error` outputs warnings for a few such errors, and refuses + to apply the patch. +* `error-all` is similar to `error` but shows all errors. +* `strip` outputs warnings for a few such errors, strips out the + trailing whitespaces and applies the patch. + + +Configuration +------------- + +apply.whitespace:: + When no `--whitespace` flag is given from the command + line, this configuration item is used as the default. + + Author ------ Written by Linus Torvalds <torvalds@osdl.org> diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt index 6fbd6d936..844cfda8d 100644 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@ -8,7 +8,7 @@ git-read-tree - Reads tree information into the index SYNOPSIS -------- -'git-read-tree' (<tree-ish> | [[-m | --reset] [-u | -i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]]) +'git-read-tree' (<tree-ish> | [[-m [--aggressive]| --reset] [-u | -i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]]) DESCRIPTION @@ -50,6 +50,19 @@ OPTIONS trees that are not directly related to the current working tree status into a temporary index file. +--aggressive:: + Usually a three-way merge by `git-read-tree` resolves + the merge for really trivial cases and leaves other + cases unresolved in the index, so that Porcelains can + implement different merge policies. This flag makes the + command to resolve a few more cases internally: ++ +* when one side removes a path and the other side leaves the path + unmodified. The resolution is to remove that path. +* when both sides remove a path. The resolution is to remove that path. +* when both sides adds a path identically. The resolution + is to add that path. + <tree-ish#>:: The id of the tree object(s) to be read/merged. diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 1c6146c76..27f18e2c5 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -18,7 +18,7 @@ SYNOPSIS [ \--all ] [ [ \--merge-order [ \--show-breaks ] ] | [ \--topo-order ] ] [ \--parents ] - [ \--objects [ \--unpacked ] ] + [ [\--objects | \--objects-edge] [ \--unpacked ] ] [ \--pretty | \--header ] [ \--bisect ] <commit>... [ \-- <paths>... ] @@ -53,6 +53,14 @@ OPTIONS which I need to download if I have the commit object 'bar', but not 'foo'". +--objects-edge:: + Similar to `--objects`, but also print the IDs of + excluded commits refixed with a `-` character. This is + used by `git-pack-objects` to build 'thin' pack, which + records objects in deltified form based on objects + contained in these excluded commits to reduce network + traffic. + --unpacked:: Only useful with `--objects`; print the object IDs that are not in packs. diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt index 912a80865..a1588138e 100644 --- a/Documentation/git-svnimport.txt +++ b/Documentation/git-svnimport.txt @@ -82,6 +82,11 @@ When importing incrementally, you might need to edit the .git/svn2git file. "username". If encountering a commit made by a user not in the list, abort. + For convenience, this data is saved to $GIT_DIR/svn-authors + each time the -A option is provided, and read from that same + file each time git-svnimport is run with an existing GIT + repository without -A. + -m:: Attempt to detect merges based on the commit message. This option will enable default regexes that try to capture the name source @@ -196,7 +196,8 @@ LIB_H = \ DIFF_OBJS = \ diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \ - diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o + diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \ + diffcore-delta.o LIB_OBJS = \ blob.o commit.o connect.o count-delta.o csum-file.o \ @@ -32,7 +32,7 @@ static int no_add = 0; static int show_index_info = 0; static int line_termination = '\n'; static const char apply_usage[] = -"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] <patch>..."; +"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>..."; static enum whitespace_eol { nowarn_whitespace, diff --git a/cat-file.c b/cat-file.c index 96d66b430..1a613f3ee 100644 --- a/cat-file.c +++ b/cat-file.c @@ -4,6 +4,92 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "exec_cmd.h" + +static void flush_buffer(const char *buf, unsigned long size) +{ + while (size > 0) { + long ret = xwrite(1, buf, size); + if (ret < 0) { + /* Ignore epipe */ + if (errno == EPIPE) + break; + die("git-cat-file: %s", strerror(errno)); + } else if (!ret) { + die("git-cat-file: disk full?"); + } + size -= ret; + buf += ret; + } +} + +static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size) +{ + /* the parser in tag.c is useless here. */ + const char *endp = buf + size; + const char *cp = buf; + + while (cp < endp) { + char c = *cp++; + if (c != '\n') + continue; + if (7 <= endp - cp && !memcmp("tagger ", cp, 7)) { + const char *tagger = cp; + + /* Found the tagger line. Copy out the contents + * of the buffer so far. + */ + flush_buffer(buf, cp - buf); + + /* + * Do something intelligent, like pretty-printing + * the date. + */ + while (cp < endp) { + if (*cp++ == '\n') { + /* tagger to cp is a line + * that has ident and time. + */ + const char *sp = tagger; + char *ep; + unsigned long date; + long tz; + while (sp < cp && *sp != '>') + sp++; + if (sp == cp) { + /* give up */ + flush_buffer(tagger, + cp - tagger); + break; + } + while (sp < cp && + !('0' <= *sp && *sp <= '9')) + sp++; + flush_buffer(tagger, sp - tagger); + date = strtoul(sp, &ep, 10); + tz = strtol(ep, NULL, 10); + sp = show_date(date, tz); + flush_buffer(sp, strlen(sp)); + xwrite(1, "\n", 1); + break; + } + } + break; + } + if (cp < endp && *cp == '\n') + /* end of header */ + break; + } + /* At this point, we have copied out the header up to the end of + * the tagger line and cp points at one past \n. It could be the + * next header line after the tagger line, or it could be another + * \n that marks the end of the headers. We need to copy out the + * remainder as is. + */ + if (cp < endp) + flush_buffer(cp, endp - cp); + return 0; +} int main(int argc, char **argv) { @@ -15,7 +101,7 @@ int main(int argc, char **argv) setup_git_directory(); if (argc != 3 || get_sha1(argv[2], sha1)) - usage("git-cat-file [-t|-s|-e|<type>] <sha1>"); + usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>"); opt = 0; if ( argv[1][0] == '-' ) { @@ -43,6 +129,23 @@ int main(int argc, char **argv) case 'e': return !has_sha1_file(sha1); + case 'p': + if (get_sha1(argv[2], sha1) || + sha1_object_info(sha1, type, NULL)) + die("Not a valid object name %s", argv[2]); + + /* custom pretty-print here */ + if (!strcmp(type, "tree")) + return execl_git_cmd("ls-tree", argv[2], NULL); + + buf = read_sha1_file(sha1, type, &size); + if (!buf) + die("Cannot read object %s", argv[2]); + if (!strcmp(type, "tag")) + return pprint_tag(sha1, buf, size); + + /* otherwise just spit out the data */ + break; case 0: buf = read_object_with_reference(sha1, argv[1], &size, NULL); break; @@ -54,18 +157,6 @@ int main(int argc, char **argv) if (!buf) die("git-cat-file %s: bad file", argv[2]); - while (size > 0) { - long ret = xwrite(1, buf, size); - if (ret < 0) { - /* Ignore epipe */ - if (errno == EPIPE) - break; - die("git-cat-file: %s", strerror(errno)); - } else if (!ret) { - die("git-cat-file: disk full?"); - } - size -= ret; - buf += ret; - } + flush_buffer(buf, size); return 0; } diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl index 0b7416526..0e092c5d3 100755 --- a/contrib/git-svn/git-svn.perl +++ b/contrib/git-svn/git-svn.perl @@ -34,13 +34,14 @@ use POSIX qw/strftime/; my $sha1 = qr/[a-f\d]{40}/; my $sha1_short = qr/[a-f\d]{6,40}/; my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit, - $_find_copies_harder, $_l, $_version); + $_find_copies_harder, $_l, $_version, $_upgrade); GetOptions( 'revision|r=s' => \$_revision, 'no-ignore-externals' => \$_no_ignore_ext, 'stdin|' => \$_stdin, 'edit|e' => \$_edit, 'rmdir' => \$_rmdir, + 'upgrade' => \$_upgrade, 'help|H|h' => \$_help, 'find-copies-harder' => \$_find_copies_harder, 'l=i' => \$_l, @@ -106,13 +107,18 @@ sub rebuild { $SVN_URL = shift or undef; my $repo_uuid; my $newest_rev = 0; + if ($_upgrade) { + sys('git-update-ref',"refs/remotes/$GIT_SVN","$GIT_SVN-HEAD"); + } else { + check_upgrade_needed(); + } my $pid = open(my $rev_list,'-|'); defined $pid or croak $!; if ($pid == 0) { - exec("git-rev-list","$GIT_SVN-HEAD") or croak $!; + exec("git-rev-list","refs/remotes/$GIT_SVN") or croak $!; } - my $first; + my $latest; while (<$rev_list>) { chomp; my $c = $_; @@ -132,18 +138,20 @@ sub rebuild { "$c, $id\n"; } } + + # if we merged or otherwise started elsewhere, this is + # how we break out of it + next if (defined $repo_uuid && ($uuid ne $repo_uuid)); + next if (defined $SVN_URL && ($url ne $SVN_URL)); + print "r$rev = $c\n"; - unless (defined $first) { + unless (defined $latest) { if (!$SVN_URL && !$url) { croak "SVN repository location required: $url\n"; } $SVN_URL ||= $url; - $repo_uuid = setup_git_svn(); - $first = $rev; - } - if ($uuid ne $repo_uuid) { - croak "Repository UUIDs do not match!\ngot: $uuid\n", - "expected: $repo_uuid\n"; + $repo_uuid ||= setup_git_svn(); + $latest = $rev; } assert_revision_eq_or_unknown($rev, $c); sys('git-update-ref',"$GIT_SVN/revs/$rev",$c); @@ -151,7 +159,7 @@ sub rebuild { } close $rev_list or croak $?; if (!chdir $SVN_WC) { - my @svn_co = ('svn','co',"-r$first"); + my @svn_co = ('svn','co',"-r$latest"); push @svn_co, '--ignore-externals' unless $_no_ignore_ext; sys(@svn_co, $SVN_URL, $SVN_WC); chdir $SVN_WC or croak $!; @@ -168,6 +176,13 @@ sub rebuild { exec('git-write-tree'); } waitpid $pid, 0; + + if ($_upgrade) { + print STDERR <<""; +Keeping deprecated refs/head/$GIT_SVN-HEAD for now. Please remove it +when you have upgraded your tools and habits to use refs/remotes/$GIT_SVN + + } } sub init { @@ -180,6 +195,7 @@ sub init { sub fetch { my (@parents) = @_; + check_upgrade_needed(); $SVN_URL ||= file_to_s("$GIT_DIR/$GIT_SVN/info/url"); my @log_args = -d $SVN_WC ? ($SVN_WC) : ($SVN_URL); unless ($_revision) { @@ -222,6 +238,7 @@ sub fetch { sub commit { my (@commits) = @_; + check_upgrade_needed(); if ($_stdin || !@commits) { print "Reading from stdin...\n"; @commits = (); @@ -863,7 +880,7 @@ sub git_commit { if ($commit !~ /^$sha1$/o) { croak "Failed to commit, invalid sha1: $commit\n"; } - my @update_ref = ('git-update-ref',"refs/heads/$GIT_SVN-HEAD",$commit); + my @update_ref = ('git-update-ref',"refs/remotes/$GIT_SVN",$commit); if (my $primary_parent = shift @exec_parents) { push @update_ref, $primary_parent; } @@ -936,6 +953,28 @@ sub svn_check_ignore_externals { $_no_ignore_ext = 1; } } + +sub check_upgrade_needed { + my $old = eval { + my $pid = open my $child, '-|'; + defined $pid or croak $!; + if ($pid == 0) { + close STDERR; + exec('git-rev-parse',"$GIT_SVN-HEAD") or croak $?; + } + my @ret = (<$child>); + close $child or croak $?; + die $? if $?; # just in case close didn't error out + return wantarray ? @ret : join('',@ret); + }; + return unless $old; + my $head = eval { safe_qx('git-rev-parse',"refs/remotes/$GIT_SVN") }; + if ($@ || !$head) { + print STDERR "Please run: $0 rebuild --upgrade\n"; + exit 1; + } +} + __END__ Data structures: diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt index b29073997..4102deb38 100644 --- a/contrib/git-svn/git-svn.txt +++ b/contrib/git-svn/git-svn.txt @@ -41,12 +41,12 @@ init:: fetch:: Fetch unfetched revisions from the SVN_URL we are tracking. - refs/heads/git-svn-HEAD will be updated to the latest revision. + refs/heads/remotes/git-svn will be updated to the latest revision. - Note: You should never attempt to modify the git-svn-HEAD branch - outside of git-svn. Instead, create a branch from git-svn-HEAD + Note: You should never attempt to modify the remotes/git-svn branch + outside of git-svn. Instead, create a branch from remotes/git-svn and work on that branch. Use the 'commit' command (see below) - to write git commits back to git-svn-HEAD. + to write git commits back to remotes/git-svn. commit:: Commit specified commit or tree objects to SVN. This relies on @@ -155,13 +155,13 @@ Tracking and contributing to an Subversion managed-project: # Fetch remote revisions:: git-svn fetch # Create your own branch to hack on:: - git checkout -b my-branch git-svn-HEAD + git checkout -b my-branch remotes/git-svn # Commit only the git commits you want to SVN:: git-svn commit <tree-ish> [<tree-ish_2> ...] # Commit all the git commits from my-branch that don't exist in SVN:: - git-svn commit git-svn-HEAD..my-branch + git-svn commit remotes/git-svn..my-branch # Something is committed to SVN, pull the latest into your branch:: - git-svn fetch && git pull . git-svn-HEAD + git-svn fetch && git pull . remotes/git-svn # Append svn:ignore settings to the default git exclude file: git-svn show-ignore >> .git/info/exclude @@ -184,8 +184,8 @@ SVN repositories via one git repository. Simply set the GIT_SVN_ID environment variable to a name other other than "git-svn" (the default) and git-svn will ignore the contents of the $GIT_DIR/git-svn directory and instead do all of its work in $GIT_DIR/$GIT_SVN_ID for that -invocation. The interface branch will be $GIT_SVN_ID-HEAD, instead of -git-svn-HEAD. Any $GIT_SVN_ID-HEAD branch should never be modified +invocation. The interface branch will be remotes/$GIT_SVN_ID, instead of +remotes/git-svn. Any remotes/$GIT_SVN_ID branch should never be modified by the user outside of git-svn commands. ADDITIONAL FETCH ARGUMENTS diff --git a/contrib/git-svn/t/t0000-contrib-git-svn.sh b/contrib/git-svn/t/t0000-contrib-git-svn.sh index 181dfe008..80ad3573d 100644 --- a/contrib/git-svn/t/t0000-contrib-git-svn.sh +++ b/contrib/git-svn/t/t0000-contrib-git-svn.sh @@ -71,14 +71,14 @@ test_expect_success \ name='try a deep --rmdir with a commit' -git checkout -b mybranch git-svn-HEAD +git checkout -b mybranch remotes/git-svn mv dir/a/b/c/d/e/file dir/file cp dir/file file git update-index --add --remove dir/a/b/c/d/e/file dir/file file git commit -m "$name" test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch && + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch && test -d $SVN_TREE/dir && test ! -d $SVN_TREE/dir/a" @@ -91,13 +91,13 @@ git update-index --add dir/file/file git commit -m "$name" test_expect_code 1 "$name" \ - 'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch' \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch' \ || true name='detect node change from directory to file #1' rm -rf dir $GIT_DIR/index -git checkout -b mybranch2 git-svn-HEAD +git checkout -b mybranch2 remotes/git-svn mv bar/zzz zzz rm -rf bar mv zzz bar @@ -106,13 +106,13 @@ git update-index --add -- bar git commit -m "$name" test_expect_code 1 "$name" \ - 'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch2' \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch2' \ || true name='detect node change from file to directory #2' rm -f $GIT_DIR/index -git checkout -b mybranch3 git-svn-HEAD +git checkout -b mybranch3 remotes/git-svn rm bar/zzz git-update-index --remove bar/zzz mkdir bar/zzz @@ -121,13 +121,13 @@ git-update-index --add bar/zzz/yyy git commit -m "$name" test_expect_code 1 "$name" \ - 'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch3' \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch3' \ || true name='detect node change from directory to file #2' rm -f $GIT_DIR/index -git checkout -b mybranch4 git-svn-HEAD +git checkout -b mybranch4 remotes/git-svn rm -rf dir git update-index --remove -- dir/file touch dir @@ -136,19 +136,19 @@ git update-index --add -- dir git commit -m "$name" test_expect_code 1 "$name" \ - 'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch4' \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch4' \ || true name='remove executable bit from a file' rm -f $GIT_DIR/index -git checkout -b mybranch5 git-svn-HEAD +git checkout -b mybranch5 remotes/git-svn chmod -x exec.sh git update-index exec.sh git commit -m "$name" test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 && + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && test ! -x $SVN_TREE/exec.sh" @@ -158,7 +158,7 @@ git update-index exec.sh git commit -m "$name" test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 && + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && test -x $SVN_TREE/exec.sh" @@ -170,7 +170,7 @@ git update-index exec.sh git commit -m "$name" test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 && + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && test -L $SVN_TREE/exec.sh" @@ -182,7 +182,7 @@ git update-index --add bar/zzz exec-2.sh git commit -m "$name" test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 && + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && test -x $SVN_TREE/bar/zzz && test -L $SVN_TREE/exec-2.sh" @@ -196,7 +196,7 @@ git update-index exec-2.sh git commit -m "$name" test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 && + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && test -f $SVN_TREE/exec-2.sh && test ! -L $SVN_TREE/exec-2.sh && diff -u help $SVN_TREE/exec-2.sh" @@ -207,9 +207,9 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID' GIT_SVN_ID=alt export GIT_SVN_ID test_expect_success "$name" \ - "git-svn init $svnrepo && git-svn fetch -v && - git-rev-list --pretty=raw git-svn-HEAD | grep ^tree | uniq > a && - git-rev-list --pretty=raw alt-HEAD | grep ^tree | uniq > b && + "git-svn init $svnrepo && git-svn fetch && + git-rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a && + git-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b && diff -u a b" test_done diff --git a/contrib/gitview/gitview b/contrib/gitview/gitview index ea05cd424..de9f3f3c7 100755 --- a/contrib/gitview/gitview +++ b/contrib/gitview/gitview @@ -513,7 +513,7 @@ class GitView: scrollwin = gtk.ScrolledWindow() - scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrollwin.set_shadow_type(gtk.SHADOW_IN) vbox.pack_start(scrollwin, expand=True, fill=True) scrollwin.show() @@ -526,9 +526,6 @@ class GitView: self.treeview.show() cell = CellRendererGraph() - # Set the default width to 265 - # This make sure that we have nice display with large tag names - cell.set_property("width", 265) column = gtk.TreeViewColumn() column.set_resizable(True) column.pack_start(cell, expand=True) diff --git a/diffcore-break.c b/diffcore-break.c index 95b5eb492..0fc2b860b 100644 --- a/diffcore-break.c +++ b/diffcore-break.c @@ -4,8 +4,6 @@ #include "cache.h" #include "diff.h" #include "diffcore.h" -#include "delta.h" -#include "count-delta.h" static int should_break(struct diff_filespec *src, struct diff_filespec *dst, @@ -47,7 +45,6 @@ static int should_break(struct diff_filespec *src, * The value we return is 1 if we want the pair to be broken, * or 0 if we do not. */ - void *delta; unsigned long delta_size, base_size, src_copied, literal_added; int to_break = 0; @@ -69,19 +66,11 @@ static int should_break(struct diff_filespec *src, if (base_size < MINIMUM_BREAK_SIZE) return 0; /* we do not break too small filepair */ - delta = diff_delta(src->data, src->size, - dst->data, dst->size, - &delta_size, 0); - if (!delta) - return 0; /* error but caught downstream */ - - /* Estimate the edit size by interpreting delta. */ - if (count_delta(delta, delta_size, - &src_copied, &literal_added)) { - free(delta); - return 0; /* we cannot tell */ - } - free(delta); + if (diffcore_count_changes(src->data, src->size, + dst->data, dst->size, + 0, + &src_copied, &literal_added)) + return 0; /* Compute merge-score, which is "how much is removed * from the source material". The clean-up stage will diff --git a/diffcore-delta.c b/diffcore-delta.c new file mode 100644 index 000000000..1e6a6911e --- /dev/null +++ b/diffcore-delta.c @@ -0,0 +1,43 @@ +#include "cache.h" +#include "diff.h" +#include "diffcore.h" +#include "delta.h" +#include "count-delta.h" + +static int diffcore_count_changes_1(void *src, unsigned long src_size, + void *dst, unsigned long dst_size, + unsigned long delta_limit, + unsigned long *src_copied, + unsigned long *literal_added) +{ + void *delta; + unsigned long delta_size; + + delta = diff_delta(src, src_size, + dst, dst_size, + &delta_size, delta_limit); + if (!delta) + /* If delta_limit is exceeded, we have too much differences */ + return -1; + + /* Estimate the edit size by interpreting delta. */ + if (count_delta(delta, delta_size, src_copied, literal_added)) { + free(delta); + return -1; + } + free(delta); + return 0; +} + +int diffcore_count_changes(void *src, unsigned long src_size, + void *dst, unsigned long dst_size, + unsigned long delta_limit, + unsigned long *src_copied, + unsigned long *literal_added) +{ + return diffcore_count_changes_1(src, src_size, + dst, dst_size, + delta_limit, + src_copied, + literal_added); +} diff --git a/diffcore-rename.c b/diffcore-rename.c index ffd126af0..55cf1c37f 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -4,8 +4,6 @@ #include "cache.h" #include "diff.h" #include "diffcore.h" -#include "delta.h" -#include "count-delta.h" /* Table of rename/copy destinations */ @@ -135,7 +133,6 @@ static int estimate_similarity(struct diff_filespec *src, * match than anything else; the destination does not even * call into this function in that case. */ - void *delta; unsigned long delta_size, base_size, src_copied, literal_added; unsigned long delta_limit; int score; @@ -165,28 +162,13 @@ static int estimate_similarity(struct diff_filespec *src, if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) return 0; /* error but caught downstream */ - delta_limit = base_size * (MAX_SCORE-minimum_score) / MAX_SCORE; - delta = diff_delta(src->data, src->size, - dst->data, dst->size, - &delta_size, delta_limit); - if (!delta) - /* If delta_limit is exceeded, we have too much differences */ - return 0; - - /* A delta that has a lot of literal additions would have - * big delta_size no matter what else it does. - */ - if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE) { - free(delta); - return 0; - } - /* Estimate the edit size by interpreting delta. */ - if (count_delta(delta, delta_size, &src_copied, &literal_added)) { - free(delta); + delta_limit = base_size * (MAX_SCORE-minimum_score) / MAX_SCORE; + if (diffcore_count_changes(src->data, src->size, + dst->data, dst->size, + delta_limit, + &src_copied, &literal_added)) return 0; - } - free(delta); /* Extent of damage */ if (src->size + literal_added < src_copied) diff --git a/diffcore.h b/diffcore.h index 12cd81659..dba4f1765 100644 --- a/diffcore.h +++ b/diffcore.h @@ -101,4 +101,10 @@ void diff_debug_queue(const char *, struct diff_queue_struct *); #define diff_debug_queue(a,b) do {} while(0) #endif +extern int diffcore_count_changes(void *src, unsigned long src_size, + void *dst, unsigned long dst_size, + unsigned long delta_limit, + unsigned long *src_copied, + unsigned long *literal_added); + #endif @@ -2,7 +2,8 @@ # # Copyright (c) 2005, 2006 Junio C Hamano -USAGE='[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox> +USAGE='[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] + [--interactive] [--whitespace=<option>] <mbox>... or, when resuming [--skip | --resolved]' . git-sh-setup diff --git a/git-annotate.perl b/git-annotate.perl index f9c2c6caf..08d479f4b 100755 --- a/git-annotate.perl +++ b/git-annotate.perl @@ -15,6 +15,8 @@ sub usage() { print STDERR 'Usage: ${\basename $0} [-s] [-S revs-file] file [ revision ] -l, --long Show long rev (Defaults off) + -t, --time + Show raw timestamp (Defaults off) -r, --rename Follow renames (Defaults on). -S, --rev-file revs-file @@ -26,12 +28,13 @@ sub usage() { exit(1); } -our ($help, $longrev, $rename, $starting_rev, $rev_file) = (0, 0, 1); +our ($help, $longrev, $rename, $rawtime, $starting_rev, $rev_file) = (0, 0, 1); my $rc = GetOptions( "long|l" => \$longrev, + "time|t" => \$rawtime, "help|h" => \$help, "rename|r" => \$rename, - "rev-file|S" => \$rev_file); + "rev-file|S=s" => \$rev_file); if (!$rc or $help) { usage(); } @@ -174,7 +177,8 @@ sub git_rev_list { my $revlist; if ($rev_file) { - open($revlist, '<' . $rev_file); + open($revlist, '<' . $rev_file) + or die "Failed to open $rev_file : $!"; } else { $revlist = open_pipe("git-rev-list","--parents","--remove-empty",$rev,"--",$file) or die "Failed to exec git-rev-list: $!"; @@ -304,6 +308,12 @@ sub _git_diff_parse { } $ri++; + } elsif (m/^\\/) { + ; + # Skip \No newline at end of file. + # But this can be internationalized, so only look + # for an initial \ + } else { if (substr($_,1) ne get_line($slines,$ri) ) { die sprintf("Line %d (%d) does not match:\n|%s\n|%s\n%s => %s\n", @@ -404,8 +414,10 @@ sub git_commit_info { } sub format_date { + if ($rawtime) { + return $_[0]; + } my ($timestamp, $timezone) = split(' ', $_[0]); - return strftime("%Y-%m-%d %H:%M:%S " . $timezone, gmtime($timestamp)); } diff --git a/git-svnimport.perl b/git-svnimport.perl index 86837edbd..639aa4186 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -13,6 +13,7 @@ use strict; use warnings; use Getopt::Std; +use File::Copy; use File::Spec; use File::Temp qw(tempfile); use File::Path qw(mkpath); @@ -68,10 +69,16 @@ if ($opt_M) { push (@mergerx, qr/$opt_M/); } +# Absolutize filename now, since we will have chdir'ed by the time we +# get around to opening it. +$opt_A = File::Spec->rel2abs($opt_A) if $opt_A; + our %users = (); -if ($opt_A) { - die "Cannot open $opt_A\n" unless -f $opt_A; - open(my $authors,$opt_A); +our $users_file = undef; +sub read_users($) { + $users_file = File::Spec->rel2abs(@_); + die "Cannot open $users_file\n" unless -f $users_file; + open(my $authors,$users_file); while(<$authors>) { chomp; next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; @@ -302,6 +309,14 @@ EOM -d $git_dir or die "Could not create git subdir ($git_dir).\n"; +my $default_authors = "$git_dir/svn-authors"; +if ($opt_A) { + read_users($opt_A); + copy($opt_A,$default_authors) or die "Copy failed: $!"; +} else { + read_users($default_authors) if -f $default_authors; +} + open BRANCHES,">>", "$git_dir/svn2git"; sub node_kind($$$) { @@ -498,8 +513,8 @@ sub commit { if (not defined $author) { $author_name = $author_email = "unknown"; - } elsif ($opt_A) { - die "User $author is not listed in $opt_A\n" + } elsif (defined $users_file) { + die "User $author is not listed in $users_file\n" unless exists $users{$author}; ($author_name,$author_email) = @{$users{$author}}; } elsif ($author =~ /^(.*?)\s+<(.*)>$/) { diff --git a/git-verify-tag.sh b/git-verify-tag.sh index 726b1e706..36f171b30 100755 --- a/git-verify-tag.sh +++ b/git-verify-tag.sh @@ -4,9 +4,21 @@ USAGE='<tag>' SUBDIRECTORY_OK='Yes' . git-sh-setup +verbose= +while case $# in 0) break;; esac +do + case "$1" in + -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) + verbose=t ;; + *) + break ;; + esac + shift +done + if [ "$#" != "1" ] then - usage + usage fi type="$(git-cat-file -t "$1" 2>/dev/null)" || @@ -15,6 +27,13 @@ type="$(git-cat-file -t "$1" 2>/dev/null)" || test "$type" = tag || die "$1: cannot verify a non-tag object of type $type." +case "$verbose" in +t) + git-cat-file -p "$1" | + sed -n -e '/^-----BEGIN PGP SIGNATURE-----/q' -e p + ;; +esac + git-cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1 cat "$GIT_DIR/.tmp-vtag" | sed '/-----BEGIN PGP/Q' | diff --git a/read-tree.c b/read-tree.c index f39fe5ca6..be29b3fe1 100644 --- a/read-tree.c +++ b/read-tree.c @@ -560,9 +560,11 @@ static int threeway_merge(struct cache_entry **stages) */ if ((head_deleted && remote_deleted) || (head_deleted && remote && remote_match) || - (remote_deleted && head && head_match)) + (remote_deleted && head && head_match)) { + if (index) + return deleted_entry(index, index); return 0; - + } /* * Added in both, identically. */ @@ -704,7 +706,7 @@ static int read_cache_unmerged(void) return deleted; } -static const char read_tree_usage[] = "git-read-tree (<sha> | -m [-u | -i] <sha1> [<sha2> [<sha3>]])"; +static const char read_tree_usage[] = "git-read-tree (<sha> | -m [--aggressive] [-u | -i] <sha1> [<sha2> [<sha3>]])"; static struct cache_file cache_file; @@ -151,10 +151,15 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u break; continue; } - if (read_ref(git_path("%s", path), sha1) < 0) + if (read_ref(git_path("%s", path), sha1) < 0) { + fprintf(stderr, "%s points nowhere!", path); continue; - if (!has_sha1_file(sha1)) + } + if (!has_sha1_file(sha1)) { + fprintf(stderr, "%s does not point to a valid " + "commit object!", path); continue; + } retval = fn(path, sha1); if (retval) break; diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh new file mode 100755 index 000000000..cae179436 --- /dev/null +++ b/t/t8001-annotate.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +test_description='git-annotate' +. ./test-lib.sh + +test_expect_success \ + 'prepare reference tree' \ + 'echo "1A quick brown fox jumps over the" >file && + echo "lazy dog" >>file && + git add file + GIT_AUTHOR_NAME="A" git commit -a -m "Initial."' + +test_expect_success \ + 'check all lines blamed on A' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "A") == 2 ]' + +test_expect_success \ + 'Setup new lines blamed on B' \ + 'echo "2A quick brown fox jumps over the" >>file && + echo "lazy dog" >> file && + GIT_AUTHOR_NAME="B" git commit -a -m "Second."' + +test_expect_success \ + 'Two lines blamed on A' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "A") == 2 ]' + +test_expect_success \ + 'Two lines blamed on B' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "B") == 2 ]' + +test_expect_success \ + 'merge-setup part 1' \ + 'git checkout -b branch1 master && + echo "3A slow green fox jumps into the" >> file && + echo "well." >> file && + GIT_AUTHOR_NAME="B1" git commit -a -m "Branch1-1"' + +test_expect_success \ + 'Two lines blamed on A' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^A$") == 2 ]' + +test_expect_success \ + 'Two lines blamed on B' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^B$") == 2 ]' + +test_expect_success \ + 'Two lines blamed on B1' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^B1$") == 2 ]' + +test_expect_success \ + 'merge-setup part 2' \ + 'git checkout -b branch2 master && + sed -i -e "s/2A quick brown/4A quick brown lazy dog/" file && + GIT_AUTHOR_NAME="B2" git commit -a -m "Branch2-1"' + +test_expect_success \ + 'Two lines blamed on A' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^A$") == 2 ]' + +test_expect_success \ + 'One line blamed on B' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^B$") == 1 ]' + +test_expect_success \ + 'One line blamed on B2' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^B2$") == 1 ]' + + +test_expect_success \ + 'merge-setup part 3' \ + 'git pull . branch1' + +test_expect_success \ + 'Two lines blamed on A' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^A$") == 2 ]' + +test_expect_success \ + 'One line blamed on B' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^B$") == 1 ]' + +test_expect_success \ + 'Two lines blamed on B1' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^B1$") == 2 ]' + +test_expect_success \ + 'One line blamed on B2' \ + '[ $(git annotate file | awk "{print \$3}" | grep -c "^B2$") == 1 ]' + +test_done |