diff --git a/Makefile b/Makefile index f7deeea967..6709c0351e 100644 --- a/Makefile +++ b/Makefile @@ -132,6 +132,8 @@ GITWEB_CONFIG = gitweb_config.perl GITWEB_HOME_LINK_STR = projects GITWEB_SITENAME = GITWEB_PROJECTROOT = /pub/git +GITWEB_EXPORT_OK = +GITWEB_STRICT_EXPORT = GITWEB_BASE_URL = GITWEB_LIST = GITWEB_HOMETEXT = indextext.html @@ -676,6 +678,8 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \ -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \ -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \ + -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \ + -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \ -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \ -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \ -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \ diff --git a/builtin-apply.c b/builtin-apply.c index 6e0864ce27..25e90d8d29 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -27,6 +27,7 @@ static const char *prefix; static int prefix_length = -1; static int newfd = -1; +static int unidiff_zero; static int p_value = 1; static int check_index; static int write_index; @@ -854,11 +855,10 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc } /* - * Parse a unified diff. Note that this really needs - * to parse each fragment separately, since the only - * way to know the difference between a "---" that is - * part of a patch, and a "---" that starts the next - * patch is to look at the line counts.. + * Parse a unified diff. Note that this really needs to parse each + * fragment separately, since the only way to know the difference + * between a "---" that is part of a patch, and a "---" that starts + * the next patch is to look at the line counts.. */ static int parse_fragment(char *line, unsigned long size, struct patch *patch, struct fragment *fragment) { @@ -875,31 +875,14 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s leading = 0; trailing = 0; - if (patch->is_new < 0) { - patch->is_new = !oldlines; - if (!oldlines) - patch->old_name = NULL; - } - if (patch->is_delete < 0) { - patch->is_delete = !newlines; - if (!newlines) - patch->new_name = NULL; - } - - if (patch->is_new && oldlines) - return error("new file depends on old contents"); - if (patch->is_delete != !newlines) { - if (newlines) - return error("deleted file still has contents"); - fprintf(stderr, "** warning: file %s becomes empty but is not deleted\n", patch->new_name); - } - /* Parse the thing.. */ line += len; size -= len; linenr++; added = deleted = 0; - for (offset = len; size > 0; offset += len, size -= len, line += len, linenr++) { + for (offset = len; + 0 < size; + offset += len, size -= len, line += len, linenr++) { if (!oldlines && !newlines) break; len = linelen(line, size); @@ -972,12 +955,18 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s patch->lines_added += added; patch->lines_deleted += deleted; + + if (0 < patch->is_new && oldlines) + return error("new file depends on old contents"); + if (0 < patch->is_delete && newlines) + return error("deleted file still has contents"); return offset; } static int parse_single_patch(char *line, unsigned long size, struct patch *patch) { unsigned long offset = 0; + unsigned long oldlines = 0, newlines = 0, context = 0; struct fragment **fragp = &patch->fragments; while (size > 4 && !memcmp(line, "@@ -", 4)) { @@ -988,9 +977,11 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc len = parse_fragment(line, size, patch, fragment); if (len <= 0) die("corrupt patch at line %d", linenr); - fragment->patch = line; fragment->size = len; + oldlines += fragment->oldlines; + newlines += fragment->newlines; + context += fragment->leading + fragment->trailing; *fragp = fragment; fragp = &fragment->next; @@ -999,6 +990,46 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc line += len; size -= len; } + + /* + * If something was removed (i.e. we have old-lines) it cannot + * be creation, and if something was added it cannot be + * deletion. However, the reverse is not true; --unified=0 + * patches that only add are not necessarily creation even + * though they do not have any old lines, and ones that only + * delete are not necessarily deletion. + * + * Unfortunately, a real creation/deletion patch do _not_ have + * any context line by definition, so we cannot safely tell it + * apart with --unified=0 insanity. At least if the patch has + * more than one hunk it is not creation or deletion. + */ + if (patch->is_new < 0 && + (oldlines || (patch->fragments && patch->fragments->next))) + patch->is_new = 0; + if (patch->is_delete < 0 && + (newlines || (patch->fragments && patch->fragments->next))) + patch->is_delete = 0; + if (!unidiff_zero || context) { + /* If the user says the patch is not generated with + * --unified=0, or if we have seen context lines, + * then not having oldlines means the patch is creation, + * and not having newlines means the patch is deletion. + */ + if (patch->is_new < 0 && !oldlines) + patch->is_new = 1; + if (patch->is_delete < 0 && !newlines) + patch->is_delete = 1; + } + + if (0 < patch->is_new && oldlines) + die("new file %s depends on old contents", patch->new_name); + if (0 < patch->is_delete && newlines) + die("deleted file %s still has contents", patch->old_name); + if (!patch->is_delete && !newlines && context) + fprintf(stderr, "** warning: file %s becomes empty but " + "is not deleted\n", patch->new_name); + return offset; } @@ -1556,9 +1587,19 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i /* * If we don't have any leading/trailing data in the patch, * we want it to match at the beginning/end of the file. + * + * But that would break if the patch is generated with + * --unified=0; sane people wouldn't do that to cause us + * trouble, but we try to please not so sane ones as well. */ - match_beginning = !leading && (frag->oldpos == 1); - match_end = !trailing; + if (unidiff_zero) { + match_beginning = (!leading && !frag->oldpos); + match_end = 0; + } + else { + match_beginning = !leading && (frag->oldpos == 1); + match_end = !trailing; + } lines = 0; pos = frag->newpos; @@ -1804,7 +1845,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * patch->result = desc.buffer; patch->resultsize = desc.size; - if (patch->is_delete && patch->resultsize) + if (0 < patch->is_delete && patch->resultsize) return error("removal patch leaves file contents"); return 0; @@ -1876,7 +1917,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) old_name, st_mode, patch->old_mode); } - if (new_name && prev_patch && prev_patch->is_delete && + if (new_name && prev_patch && 0 < prev_patch->is_delete && !strcmp(prev_patch->old_name, new_name)) /* A type-change diff is always split into a patch to * delete old, immediately followed by a patch to @@ -1889,7 +1930,8 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) else ok_if_exists = 0; - if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) { + if (new_name && + ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) { if (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0 && !ok_if_exists) @@ -1906,7 +1948,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) return error("%s: %s", new_name, strerror(errno)); } if (!patch->new_mode) { - if (patch->is_new) + if (0 < patch->is_new) patch->new_mode = S_IFREG | 0644; else patch->new_mode = patch->old_mode; @@ -1957,7 +1999,7 @@ static void show_index_list(struct patch *list) const char *name; name = patch->old_name ? patch->old_name : patch->new_name; - if (patch->is_new) + if (0 < patch->is_new) sha1_ptr = null_sha1; else if (get_sha1(patch->old_sha1_prefix, sha1)) die("sha1 information is lacking or useless (%s).", @@ -2543,6 +2585,10 @@ int cmd_apply(int argc, const char **argv, const char *prefix) apply_in_reverse = 1; continue; } + if (!strcmp(arg, "--unidiff-zero")) { + unidiff_zero = 1; + continue; + } if (!strcmp(arg, "--reject")) { apply = apply_with_reject = apply_verbosely = 1; continue; diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index f2679a8637..437eb726a9 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -3,7 +3,6 @@ */ #include #include "cache.h" -#include "tree-walk.h" #include "commit.h" #include "strbuf.h" #include "tar.h" @@ -248,37 +247,6 @@ static void write_global_extended_header(const unsigned char *sha1) free(ext_header.buf); } -static void traverse_tree(struct tree_desc *tree, struct strbuf *path) -{ - int pathlen = path->len; - struct name_entry entry; - - while (tree_entry(tree, &entry)) { - void *eltbuf; - char elttype[20]; - unsigned long eltsize; - - eltbuf = read_sha1_file(entry.sha1, elttype, &eltsize); - if (!eltbuf) - die("cannot read %s", sha1_to_hex(entry.sha1)); - - path->len = pathlen; - strbuf_append_string(path, entry.path); - if (S_ISDIR(entry.mode)) - strbuf_append_string(path, "/"); - - write_entry(entry.sha1, path, entry.mode, eltbuf, eltsize); - - if (S_ISDIR(entry.mode)) { - struct tree_desc subtree; - subtree.buf = eltbuf; - subtree.size = eltsize; - traverse_tree(&subtree, path); - } - free(eltbuf); - } -} - static int git_tar_config(const char *var, const char *value) { if (!strcmp(var, "tar.umask")) { @@ -295,51 +263,29 @@ static int git_tar_config(const char *var, const char *value) static int generate_tar(int argc, const char **argv, const char *prefix) { - unsigned char sha1[20], tree_sha1[20]; - struct commit *commit; - struct tree_desc tree; - struct strbuf current_path; - void *buffer; - - current_path.buf = xmalloc(PATH_MAX); - current_path.alloc = PATH_MAX; - current_path.len = current_path.eof = 0; + struct archiver_args args; + int result; + char *base = NULL; git_config(git_tar_config); - switch (argc) { - case 3: - strbuf_append_string(¤t_path, argv[2]); - strbuf_append_string(¤t_path, "/"); - /* FALLTHROUGH */ - case 2: - if (get_sha1(argv[1], sha1)) - die("Not a valid object name %s", argv[1]); - break; - default: + memset(&args, 0, sizeof(args)); + if (argc != 2 && argc != 3) usage(tar_tree_usage); + if (argc == 3) { + int baselen = strlen(argv[2]); + base = xmalloc(baselen + 2); + memcpy(base, argv[2], baselen); + base[baselen] = '/'; + base[baselen + 1] = '\0'; } + args.base = base; + parse_treeish_arg(argv + 1, &args, NULL); - commit = lookup_commit_reference_gently(sha1, 1); - if (commit) { - write_global_extended_header(commit->object.sha1); - archive_time = commit->date; - } else - archive_time = time(NULL); + result = write_tar_archive(&args); + free(base); - tree.buf = buffer = read_object_with_reference(sha1, tree_type, - &tree.size, tree_sha1); - if (!tree.buf) - die("not a reference to a tag, commit or tree object: %s", - sha1_to_hex(sha1)); - - if (current_path.len > 0) - write_entry(tree_sha1, ¤t_path, 040777, NULL, 0); - traverse_tree(&tree, ¤t_path); - write_trailer(); - free(buffer); - free(current_path.buf); - return 0; + return result; } static int write_tar_entry(const unsigned char *sha1, @@ -383,7 +329,7 @@ static int write_tar_entry(const unsigned char *sha1, int write_tar_archive(struct archiver_args *args) { - int plen = strlen(args->base); + int plen = args->base ? strlen(args->base) : 0; git_config(git_tar_config); diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a81c8d4cf2..497129aefc 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -54,6 +54,13 @@ our $favicon = "++GITWEB_FAVICON++"; # source of projects list our $projects_list = "++GITWEB_LIST++"; +# show repository only if this file exists +# (only effective if this variable evaluates to true) +our $export_ok = "++GITWEB_EXPORT_OK++"; + +# only allow viewing of repositories also shown on the overview page +our $strict_export = "++GITWEB_STRICT_EXPORT++"; + # list of git base URLs used for URL to where fetch project from, # i.e. full URL is "$git_base_url/$project" our @git_base_url_list = ("++GITWEB_BASE_URL++"); @@ -196,23 +203,16 @@ if (defined $action) { } } -our $project = ($cgi->param('p') || $ENV{'PATH_INFO'}); +our $project = $cgi->param('p'); if (defined $project) { - $project =~ s|^/||; - $project =~ s|/$||; - $project = undef unless $project; -} -if (defined $project) { - if (!validate_input($project)) { - die_error(undef, "Invalid project parameter"); - } - if (!(-d "$projectroot/$project")) { - die_error(undef, "No such directory"); - } - if (!(-e "$projectroot/$project/HEAD")) { + if (!validate_input($project) || + !(-d "$projectroot/$project") || + !(-e "$projectroot/$project/HEAD") || + ($export_ok && !(-e "$projectroot/$project/$export_ok")) || + ($strict_export && !project_in_list($project))) { + undef $project; die_error(undef, "No such project"); } - $git_dir = "$projectroot/$project"; } our $file_name = $cgi->param('f'); @@ -272,6 +272,32 @@ if (defined $searchtext) { $searchtext = quotemeta $searchtext; } +# now read PATH_INFO and use it as alternative to parameters +our $path_info = $ENV{"PATH_INFO"}; +$path_info =~ s|^/||; +$path_info =~ s|/$||; +if (validate_input($path_info) && !defined $project) { + $project = $path_info; + while ($project && !-e "$projectroot/$project/HEAD") { + $project =~ s,/*[^/]*$,,; + } + if (defined $project) { + $project = undef unless $project; + } + if ($path_info =~ m,^$project/([^/]+)/(.+)$,) { + # we got "project.git/branch/filename" + $action ||= "blob_plain"; + $hash_base ||= $1; + $file_name ||= $2; + } elsif ($path_info =~ m,^$project/([^/]+)$,) { + # we got "project.git/branch" + $action ||= "shortlog"; + $hash ||= $1; + } +} + +$git_dir = "$projectroot/$project"; + # dispatch my %actions = ( "blame" => \&git_blame2, @@ -405,6 +431,12 @@ sub untabify { return $line; } +sub project_in_list { + my $project = shift; + my @list = git_get_projects_list(); + return @list && scalar(grep { $_->{'path'} eq $project } @list); +} + ## ---------------------------------------------------------------------- ## HTML aware string manipulation @@ -717,7 +749,8 @@ sub git_get_projects_list { my $subdir = substr($File::Find::name, $pfxlen + 1); # we check related file in $projectroot - if (-e "$projectroot/$subdir/HEAD") { + if (-e "$projectroot/$subdir/HEAD" && (!$export_ok || + -e "$projectroot/$subdir/$export_ok")) { push @list, { path => $subdir }; $File::Find::prune = 1; } @@ -738,7 +771,8 @@ sub git_get_projects_list { if (!defined $path) { next; } - if (-e "$projectroot/$path/HEAD") { + if (-e "$projectroot/$path/HEAD" && (!$export_ok || + -e "$projectroot/$path/$export_ok")) { my $pr = { path => $path, owner => decode("utf8", $owner, Encode::FB_DEFAULT), @@ -2527,11 +2561,7 @@ sub git_heads { } sub git_blob_plain { - # blobs defined by non-textual hash id's can be cached my $expires; - if ($hash =~ m/^[0-9a-fA-F]{40}$/) { - $expires = "+1d"; - } if (!defined $hash) { if (defined $file_name) { @@ -2541,7 +2571,11 @@ sub git_blob_plain { } else { die_error(undef, "No file name defined"); } + } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) { + # blobs defined by non-textual hash id's can be cached + $expires = "+1d"; } + my $type = shift; open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or die_error(undef, "Couldn't cat $file_name, $hash"); @@ -2569,11 +2603,7 @@ sub git_blob_plain { } sub git_blob { - # blobs defined by non-textual hash id's can be cached my $expires; - if ($hash =~ m/^[0-9a-fA-F]{40}$/) { - $expires = "+1d"; - } if (!defined $hash) { if (defined $file_name) { @@ -2583,7 +2613,11 @@ sub git_blob { } else { die_error(undef, "No file name defined"); } + } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) { + # blobs defined by non-textual hash id's can be cached + $expires = "+1d"; } + my ($have_blame) = gitweb_check_feature('blame'); open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or die_error(undef, "Couldn't cat $file_name, $hash"); diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index ddc80bbeae..b3b920edb1 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -19,51 +19,51 @@ n=$n_dir/fixes test_expect_success \ "create $m" \ - 'git-update-ref $m $A && - test $A = $(cat .git/$m)' + "git-update-ref $m $A && + test $A"' = $(cat .git/'"$m"')' test_expect_success \ "create $m" \ - 'git-update-ref $m $B $A && - test $B = $(cat .git/$m)' + "git-update-ref $m $B $A && + test $B"' = $(cat .git/'"$m"')' rm -f .git/$m test_expect_success \ "fail to create $n" \ - 'touch .git/$n_dir + "touch .git/$n_dir git-update-ref $n $A >out 2>err - test $? = 1 && + test "'$? = 1 && test "" = "$(cat out)" && grep "error: unable to resolve reference" err && - grep $n err' + grep '"$n err" rm -f .git/$n_dir out err test_expect_success \ "create $m (by HEAD)" \ - 'git-update-ref HEAD $A && - test $A = $(cat .git/$m)' + "git-update-ref HEAD $A && + test $A"' = $(cat .git/'"$m"')' test_expect_success \ "create $m (by HEAD)" \ - 'git-update-ref HEAD $B $A && - test $B = $(cat .git/$m)' + "git-update-ref HEAD $B $A && + test $B"' = $(cat .git/'"$m"')' rm -f .git/$m test_expect_failure \ '(not) create HEAD with old sha1' \ - 'git-update-ref HEAD $A $B' + "git-update-ref HEAD $A $B" test_expect_failure \ "(not) prior created .git/$m" \ - 'test -f .git/$m' + "test -f .git/$m" rm -f .git/$m test_expect_success \ "create HEAD" \ - 'git-update-ref HEAD $A' + "git-update-ref HEAD $A" test_expect_failure \ '(not) change HEAD with wrong SHA1' \ - 'git-update-ref HEAD $B $Z' + "git-update-ref HEAD $B $Z" test_expect_failure \ "(not) changed .git/$m" \ - 'test $B = $(cat .git/$m)' + "test $B"' = $(cat .git/'"$m"')' rm -f .git/$m mkdir -p .git/logs/refs/heads @@ -71,18 +71,18 @@ touch .git/logs/refs/heads/master test_expect_success \ "create $m (logged by touch)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git-update-ref HEAD $A -m "Initial Creation" && - test $A = $(cat .git/$m)' + git-update-ref HEAD '"$A"' -m "Initial Creation" && + test '"$A"' = $(cat .git/'"$m"')' test_expect_success \ "update $m (logged by touch)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:31" \ - git-update-ref HEAD $B $A -m "Switch" && - test $B = $(cat .git/$m)' + git-update-ref HEAD'" $B $A "'-m "Switch" && + test '"$B"' = $(cat .git/'"$m"')' test_expect_success \ "set $m (logged by touch)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:41" \ - git-update-ref HEAD $A && - test $A = $(cat .git/$m)' + git-update-ref HEAD'" $A && + test $A"' = $(cat .git/'"$m"')' cat >expect < 1117150200 +0000 Initial Creation @@ -91,7 +91,7 @@ $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000 EOF test_expect_success \ "verifying $m's log" \ - 'diff expect .git/logs/$m' + "diff expect .git/logs/$m" rm -rf .git/$m .git/logs expect test_expect_success \ @@ -102,18 +102,18 @@ test_expect_success \ test_expect_success \ "create $m (logged by config)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:32" \ - git-update-ref HEAD $A -m "Initial Creation" && - test $A = $(cat .git/$m)' + git-update-ref HEAD'" $A "'-m "Initial Creation" && + test '"$A"' = $(cat .git/'"$m"')' test_expect_success \ "update $m (logged by config)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:33" \ - git-update-ref HEAD $B $A -m "Switch" && - test $B = $(cat .git/$m)' + git-update-ref HEAD'" $B $A "'-m "Switch" && + test '"$B"' = $(cat .git/'"$m"')' test_expect_success \ "set $m (logged by config)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:43" \ - git-update-ref HEAD $A && - test $A = $(cat .git/$m)' + git-update-ref HEAD '"$A && + test $A"' = $(cat .git/'"$m"')' cat >expect < 1117150320 +0000 Initial Creation @@ -140,50 +140,50 @@ test_expect_success \ 'Query "master@{May 25 2005}" (before history)' \ 'rm -f o e git-rev-parse --verify "master@{May 25 2005}" >o 2>e && - test $C = $(cat o) && - test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"' + test '"$C"' = $(cat o) && + test "warning: Log .git/logs/'"$m only goes back to $ed"'." = "$(cat e)"' test_expect_success \ "Query master@{2005-05-25} (before history)" \ 'rm -f o e git-rev-parse --verify master@{2005-05-25} >o 2>e && - test $C = $(cat o) && - echo test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"' + test '"$C"' = $(cat o) && + echo test "warning: Log .git/logs/'"$m only goes back to $ed"'." = "$(cat e)"' test_expect_success \ 'Query "master@{May 26 2005 23:31:59}" (1 second before history)' \ 'rm -f o e git-rev-parse --verify "master@{May 26 2005 23:31:59}" >o 2>e && - test $C = $(cat o) && - test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"' + test '"$C"' = $(cat o) && + test "warning: Log .git/logs/'"$m only goes back to $ed"'." = "$(cat e)"' test_expect_success \ 'Query "master@{May 26 2005 23:32:00}" (exactly history start)' \ 'rm -f o e git-rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e && - test $A = $(cat o) && + test '"$A"' = $(cat o) && test "" = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-26 23:33:01}" (middle of history with gap)' \ 'rm -f o e git-rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e && - test $B = $(cat o) && - test "warning: Log .git/logs/$m has gap after $gd." = "$(cat e)"' + test '"$B"' = $(cat o) && + test "warning: Log .git/logs/'"$m has gap after $gd"'." = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-26 23:38:00}" (middle of history)' \ 'rm -f o e git-rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e && - test $Z = $(cat o) && + test '"$Z"' = $(cat o) && test "" = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-26 23:43:00}" (exact end of history)' \ 'rm -f o e git-rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e && - test $E = $(cat o) && + test '"$E"' = $(cat o) && test "" = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-28}" (past end of history)' \ 'rm -f o e git-rev-parse --verify "master@{2005-05-28}" >o 2>e && - test $D = $(cat o) && - test "warning: Log .git/logs/$m unexpectedly ended on $ld." = "$(cat e)"' + test '"$D"' = $(cat o) && + test "warning: Log .git/logs/'"$m unexpectedly ended on $ld"'." = "$(cat e)"' rm -f .git/$m .git/logs/$m expect @@ -221,7 +221,7 @@ $h_FIXED $h_MERGED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151100 +0000 c EOF test_expect_success \ 'git-commit logged updates' \ - 'diff expect .git/logs/$m' + "diff expect .git/logs/$m" unset h_TEST h_OTHER h_FIXED h_MERGED test_expect_success \ diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index 8ab63c5276..bb25315361 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -37,7 +37,9 @@ test_expect_success setup ' git branch skip-merge skip-reference ' -test_expect_failure 'rebase with git am -3 (default)' 'git rebase master' +test_expect_failure 'rebase with git am -3 (default)' ' + git rebase master +' test_expect_success 'rebase --skip with am -3' ' git reset --hard HEAD && diff --git a/t/t4104-apply-boundary.sh b/t/t4104-apply-boundary.sh new file mode 100755 index 0000000000..2ff800c23f --- /dev/null +++ b/t/t4104-apply-boundary.sh @@ -0,0 +1,115 @@ +#!/bin/sh +# +# Copyright (c) 2005 Junio C Hamano +# + +test_description='git-apply boundary tests + +' +. ./test-lib.sh + +L="c d e f g h i j k l m n o p q r s t u v w x" + +test_expect_success setup ' + for i in b '"$L"' y + do + echo $i + done >victim && + cat victim >original && + git update-index --add victim && + + : add to the head + for i in a b '"$L"' y + do + echo $i + done >victim && + cat victim >add-a-expect && + git diff victim >add-a-patch.with && + git diff --unified=0 >add-a-patch.without && + + : modify at the head + for i in a '"$L"' y + do + echo $i + done >victim && + cat victim >mod-a-expect && + git diff victim >mod-a-patch.with && + git diff --unified=0 >mod-a-patch.without && + + : remove from the head + for i in '"$L"' y + do + echo $i + done >victim && + cat victim >del-a-expect && + git diff victim >del-a-patch.with + git diff --unified=0 >del-a-patch.without && + + : add to the tail + for i in b '"$L"' y z + do + echo $i + done >victim && + cat victim >add-z-expect && + git diff victim >add-z-patch.with && + git diff --unified=0 >add-z-patch.without && + + : modify at the tail + for i in a '"$L"' y + do + echo $i + done >victim && + cat victim >mod-z-expect && + git diff victim >mod-z-patch.with && + git diff --unified=0 >mod-z-patch.without && + + : remove from the tail + for i in b '"$L"' + do + echo $i + done >victim && + cat victim >del-z-expect && + git diff victim >del-z-patch.with + git diff --unified=0 >del-z-patch.without && + + : done +' + +for with in with without +do + case "$with" in + with) u= ;; + without) u='--unidiff-zero ' ;; + esac + for kind in add-a add-z mod-a mod-z del-a del-z + do + test_expect_success "apply $kind-patch $with context" ' + cat original >victim && + git update-index victim && + git apply --index '"$u$kind-patch.$with"' || { + cat '"$kind-patch.$with"' + (exit 1) + } && + diff -u '"$kind"'-expect victim + ' + done +done + +for kind in add-a add-z mod-a mod-z del-a del-z +do + rm -f $kind-ng.without + sed -e "s/^diff --git /diff /" \ + -e '/^index /d' \ + <$kind-patch.without >$kind-ng.without + test_expect_success "apply non-git $kind-patch without context" ' + cat original >victim && + git update-index victim && + git apply --unidiff-zero --index '"$kind-ng.without"' || { + cat '"$kind-ng.without"' + (exit 1) + } && + diff -u '"$kind"'-expect victim + ' +done + +test_done