diff options
52 files changed, 600 insertions, 196 deletions
diff --git a/Documentation/RelNotes-1.6.0.3.txt b/Documentation/RelNotes-1.6.0.3.txt new file mode 100644 index 000000000..46e13a450 --- /dev/null +++ b/Documentation/RelNotes-1.6.0.3.txt @@ -0,0 +1,45 @@ +GIT v1.6.0.3 Release Notes +========================== + +Fixes since v1.6.0.2 +-------------------- + +* "git archive --format=zip" did not honor core.autocrlf while + --format=tar did. + +* Continuing "git rebase -i" was very confused when the user left modified + files in the working tree while resolving conflicts. + +* Continuing "git rebase -i" was also very confused when the user left + some staged changes in the index after "edit". + +* Behaviour of "git diff --quiet" was inconsistent with "diff --exit-code" + with the output redirected to /dev/null. + +* "git stash apply sash@{1}" was fixed to error out. Prior versions + would have applied stash@{0} incorrectly. + +* "git for-each-ref --format=%(subject)" fixed for commits with no + no newline in the message body. + +* "git remote" fixed to protect printf from user input. + +* "git checkout -q" once again suppresses the locally modified file list. + +* Cross-directory renames are no longer used when creating packs. This + allows more graceful behavior on filesystems like sshfs. + +* Stale temporary files under $GIT_DIR/objects/pack are now cleaned up + automatically by "git prune". + +* "Git.pm" tests relied on unnecessarily more recent version of Perl. + +* "gitweb" triggered undef warning on commits without log messages. + +Many other documentation updates. + +-- +exec >/var/tmp/1 +O=v1.6.0.2-41-g7fe4a72 +echo O=$(git describe maint) +git shortlog --no-merges $O..maint diff --git a/Documentation/config.txt b/Documentation/config.txt index ed3285f89..5dda70de9 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -363,8 +363,17 @@ core.pager:: variable. Note that git sets the `LESS` environment variable to `FRSX` if it is unset when it runs the pager. One can change these settings by setting the - `LESS` variable to some other value or by giving the - `core.pager` option a value such as "`less -+FRSX`". + `LESS` variable to some other value. Alternately, + these settings can be overridden on a project or + global basis by setting the `core.pager` option. + Setting `core.pager` has no affect on the `LESS` + environment variable behaviour above, so if you want + to override git's default settings this way, you need + to be explicit. For example, to disable the S option + in a backward compatible manner, set `core.pager` + to "`less -+$LESS -FRX`". This will be passed to the + shell by git, which will translate the final command to + "`LESS=FRSX less -+FRSX -FRX`". core.whitespace:: A comma separated list of common whitespace problems to diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt index 6f4b9b017..309deac23 100644 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@ -160,7 +160,10 @@ Here are the "carry forward" rules: 0 nothing nothing nothing (does not happen) 1 nothing nothing exists use M 2 nothing exists nothing remove path from index - 3 nothing exists exists use M + 3 nothing exists exists, use M if "initial checkout" + H == M keep index otherwise + exists fail + H != M clean I==H I==M ------------------ @@ -207,6 +210,12 @@ you picked it up via e-mail in a patch form), `git diff-index merge, but it would not show in `git diff-index --cached $M` output after two-tree merge. +Case #3 is slightly tricky and needs explanation. The result from this +rule logically should be to remove the path if the user staged the removal +of the path and then swiching to a new branch. That however will prevent +the initial checkout from happening, so the rule is modified to use M (new +tree) only when the contents of the index is empty. Otherwise the removal +of the path is kept as long as $H and $M are the same. 3-Way Merge ~~~~~~~~~~~ diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt index 38ac60947..bbe1485a9 100644 --- a/Documentation/git-repack.txt +++ b/Documentation/git-repack.txt @@ -60,7 +60,7 @@ OPTIONS linkgit:git-pack-objects[1]. -f:: - Pass the `--no-reuse-delta` option to 'git-pack-objects'. See + Pass the `--no-reuse-object` option to `git-pack-objects`, see linkgit:git-pack-objects[1]. -q:: diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 9a752570f..2ae771f2f 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -270,27 +270,27 @@ See linkgit:git[1] for details. Defining a custom hunk-header ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Each group of changes (called "hunk") in the textual diff output +Each group of changes (called a "hunk") in the textual diff output is prefixed with a line of the form: @@ -k,l +n,m @@ TEXT -The text is called 'hunk header', and by default a line that -begins with an alphabet, an underscore or a dollar sign is used, -which matches what GNU 'diff -p' output uses. This default -selection however is not suited for some contents, and you can -use customized pattern to make a selection. +This is called a 'hunk header'. The "TEXT" portion is by default a line +that begins with an alphabet, an underscore or a dollar sign; this +matches what GNU 'diff -p' output uses. This default selection however +is not suited for some contents, and you can use a customized pattern +to make a selection. -First in .gitattributes, you would assign the `diff` attribute +First, in .gitattributes, you would assign the `diff` attribute for paths. ------------------------ *.tex diff=tex ------------------------ -Then, you would define "diff.tex.xfuncname" configuration to +Then, you would define a "diff.tex.xfuncname" configuration to specify a regular expression that matches a line that you would -want to appear as the hunk header, like this: +want to appear as the hunk header "TEXT", like this: ------------------------ [diff "tex"] diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt index 2bdbc3d4f..e8041bc08 100644 --- a/Documentation/gitdiffcore.txt +++ b/Documentation/gitdiffcore.txt @@ -36,11 +36,25 @@ files: - 'git-diff-tree' compares contents of two "tree" objects; -In all of these cases, the commands themselves compare -corresponding paths in the two sets of files. The result of -comparison is passed from these commands to what is internally -called "diffcore", in a format similar to what is output when -the -p option is not used. E.g. +In all of these cases, the commands themselves first optionally limit +the two sets of files by any pathspecs given on their command-lines, +and compare corresponding paths in the two resulting sets of files. + +The pathspecs are used to limit the world diff operates in. They remove +the filepairs outside the specified sets of pathnames. E.g. If the +input set of filepairs included: + +------------------------------------------------ +:100644 100644 bcd1234... 0123456... M junkfile +------------------------------------------------ + +but the command invocation was `git diff-files myfile`, then the +junkfile entry would be removed from the list because only "myfile" +is under consideration. + +The result of comparison is passed from these commands to what is +internally called "diffcore", in a format similar to what is output +when the -p option is not used. E.g. ------------------------------------------------ in-place edit :100644 100644 bcd1234... 0123456... M file0 @@ -52,9 +66,8 @@ unmerged :000000 000000 0000000... 0000000... U file6 The diffcore mechanism is fed a list of such comparison results (each of which is called "filepair", although at this point each of them talks about a single file), and transforms such a list -into another list. There are currently 6 such transformations: +into another list. There are currently 5 such transformations: -- diffcore-pathspec - diffcore-break - diffcore-rename - diffcore-merge-broken @@ -62,38 +75,14 @@ into another list. There are currently 6 such transformations: - diffcore-order These are applied in sequence. The set of filepairs 'git-diff-{asterisk}' -commands find are used as the input to diffcore-pathspec, and -the output from diffcore-pathspec is used as the input to the +commands find are used as the input to diffcore-break, and +the output from diffcore-break is used as the input to the next transformation. The final result is then passed to the output routine and generates either diff-raw format (see Output format sections of the manual for 'git-diff-{asterisk}' commands) or diff-patch format. -diffcore-pathspec: For Ignoring Files Outside Our Consideration ---------------------------------------------------------------- - -The first transformation in the chain is diffcore-pathspec, and -is controlled by giving the pathname parameters to the -'git-diff-{asterisk}' commands on the command line. The pathspec is used -to limit the world diff operates in. It removes the filepairs -outside the specified set of pathnames. E.g. If the input set -of filepairs included: - ------------------------------------------------- -:100644 100644 bcd1234... 0123456... M junkfile ------------------------------------------------- - -but the command invocation was `git diff-files myfile`, then the -junkfile entry would be removed from the list because only "myfile" -is under consideration. - -Implementation note. For performance reasons, 'git-diff-tree' -uses the pathname parameters on the command line to cull set of -filepairs it feeds the diffcore mechanism itself, and does not -use diffcore-pathspec, but the end result is the same. - - diffcore-break: For Splitting Up "Complete Rewrites" ---------------------------------------------------- diff --git a/builtin-apply.c b/builtin-apply.c index 20bef1f21..70c9f9355 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -13,6 +13,7 @@ #include "delta.h" #include "builtin.h" #include "string-list.h" +#include "dir.h" /* * --check turns on checking that the working tree matches the @@ -2735,15 +2736,7 @@ static void remove_file(struct patch *patch, int rmdir_empty) warning("unable to remove submodule %s", patch->old_name); } else if (!unlink(patch->old_name) && rmdir_empty) { - char *name = xstrdup(patch->old_name); - char *end = strrchr(name, '/'); - while (end) { - *end = 0; - if (rmdir(name)) - break; - end = strrchr(name, '/'); - } - free(name); + remove_path(patch->old_name); } } } diff --git a/builtin-archive.c b/builtin-archive.c index 5ceec433f..432ce2acc 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -111,6 +111,8 @@ int cmd_archive(int argc, const char **argv, const char *prefix) { const char *remote = NULL; + git_config(git_default_config, NULL); + remote = extract_remote_arg(&argc, argv); if (remote) return run_remote_archiver(remote, argc, argv); diff --git a/builtin-checkout.c b/builtin-checkout.c index d986ac7ab..4ca76a6f4 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -269,6 +269,8 @@ static int merge_working_tree(struct checkout_opts *opts, } /* 2-way merge to the new branch */ + topts.initial_checkout = (!active_nr && + (old->commit == new->commit)); topts.update = 1; topts.merge = 1; topts.gently = opts->merge; @@ -326,7 +328,7 @@ static int merge_working_tree(struct checkout_opts *opts, commit_locked_index(lock_file)) die("unable to write new index file"); - if (!opts->force) + if (!opts->force && !opts->quiet) show_local_changes(&new->commit->object); return 0; diff --git a/builtin-clone.c b/builtin-clone.c index c8435295c..5b40e07ba 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -58,7 +58,7 @@ static struct option builtin_clone_options[] = { OPT_STRING(0, "reference", &option_reference, "repo", "reference repository"), OPT_STRING('o', "origin", &option_origin, "branch", - "use <branch> instead or 'origin' to track upstream"), + "use <branch> instead of 'origin' to track upstream"), OPT_STRING('u', "upload-pack", &option_upload_pack, "path", "path to git-upload-pack on the remote"), OPT_STRING(0, "depth", &option_depth, "depth", diff --git a/builtin-commit.c b/builtin-commit.c index 8165bb3d3..6b23143cd 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -639,7 +639,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) { - error("Error building trees"); + error("Error building trees; the index is unmerged?"); return 0; } diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 9bf10bb37..2b578c714 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -50,7 +50,12 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) 3 < rev.max_count) usage(diff_files_usage); - if (rev.max_count == -1 && + /* + * "diff-files --base -p" should not combine merges because it + * was not asked to. "diff-files -c -p" should not densify + * (the user should ask with "diff-files --cc" explicitly). + */ + if (rev.max_count == -1 && !rev.combine_merges && (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; diff --git a/builtin-diff.c b/builtin-diff.c index 037c3039a..d5fe775fc 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -223,7 +223,13 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv argv++; argc--; } - if (revs->max_count == -1 && + /* + * "diff --base" should not combine merges because it was not + * asked to. "diff -c" should not densify (if the user wants + * dense one, --cc can be explicitly asked for, or just rely + * on the default). + */ + if (revs->max_count == -1 && !revs->combine_merges && (revs->diffopt.output_format & DIFF_FORMAT_PATCH)) revs->combine_merges = revs->dense_combined_merges = 1; diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 21e92bbcb..72c087840 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -320,9 +320,7 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un static const char *copy_line(const char *buf) { - const char *eol = strchr(buf, '\n'); - if (!eol) - return ""; + const char *eol = strchrnul(buf, '\n'); return xmemdupz(buf, eol - buf); } diff --git a/builtin-log.c b/builtin-log.c index 1d3c5cbf5..d4aaddc9d 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -844,7 +844,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) committer = git_committer_info(IDENT_ERROR_ON_NO_NAME); endpos = strchr(committer, '>'); if (!endpos) - die("bogos committer info %s\n", committer); + die("bogus committer info %s\n", committer); add_signoff = xmemdupz(committer, endpos - committer + 1); } else if (!strcmp(argv[i], "--attach")) { diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index dfb363ee2..36aa79845 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -18,6 +18,7 @@ #include "ll-merge.h" #include "interpolate.h" #include "attr.h" +#include "dir.h" #include "merge-recursive.h" static int subtree_merge; @@ -416,24 +417,6 @@ static int update_stages(const char *path, struct diff_filespec *o, return 0; } -static int remove_path(const char *name) -{ - int ret; - char *slash, *dirs; - - ret = unlink(name); - if (ret) - return ret; - dirs = xstrdup(name); - while ((slash = strrchr(name, '/'))) { - *slash = '\0'; - if (rmdir(name) != 0) - break; - } - free(dirs); - return ret; -} - static int remove_file(int clean, const char *path, int no_wd) { int update_cache = index_only || clean; @@ -444,10 +427,8 @@ static int remove_file(int clean, const char *path, int no_wd) return -1; } if (update_working_directory) { - unlink(path); - if (errno != ENOENT || errno != EISDIR) + if (remove_path(path)) return -1; - remove_path(path); } return 0; } diff --git a/builtin-merge.c b/builtin-merge.c index 9ad979106..1094c5fd5 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -476,6 +476,8 @@ static int git_merge_config(const char *k, const char *v, void *cb) buf = xstrdup(v); argc = split_cmdline(buf, &argv); + if (argc < 0) + die("Bad branch.%s.mergeoptions string", branch); argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); argc++; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 217fd49da..4004e73e4 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -465,7 +465,7 @@ static void write_pack_file(void) char tmpname[PATH_MAX]; int fd; snprintf(tmpname, sizeof(tmpname), - "%s/tmp_pack_XXXXXX", get_object_directory()); + "%s/pack/tmp_pack_XXXXXX", get_object_directory()); fd = xmkstemp(tmpname); pack_tmp_name = xstrdup(tmpname); f = sha1fd(fd, pack_tmp_name); diff --git a/builtin-prune.c b/builtin-prune.c index c767a0ac8..1663f8bdb 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -13,7 +13,7 @@ static const char * const prune_usage[] = { static int show_only; static unsigned long expire; -static int prune_tmp_object(char *path, const char *filename) +static int prune_tmp_object(const char *path, const char *filename) { const char *fullpath = mkpath("%s/%s", path, filename); if (expire) { @@ -110,24 +110,22 @@ static void prune_object_dir(const char *path) /* * Write errors (particularly out of space) can result in * failed temporary packs (and more rarely indexes and other - * files begining with "tmp_") accumulating in the - * object directory. + * files begining with "tmp_") accumulating in the object + * and the pack directories. */ -static void remove_temporary_files(void) +static void remove_temporary_files(const char *path) { DIR *dir; struct dirent *de; - char* dirname=get_object_directory(); - dir = opendir(dirname); + dir = opendir(path); if (!dir) { - fprintf(stderr, "Unable to open object directory %s\n", - dirname); + fprintf(stderr, "Unable to open directory %s\n", path); return; } while ((de = readdir(dir)) != NULL) if (!prefixcmp(de->d_name, "tmp_")) - prune_tmp_object(dirname, de->d_name); + prune_tmp_object(path, de->d_name); closedir(dir); } @@ -141,6 +139,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) "expire objects older than <time>"), OPT_END() }; + char *s; save_commit_buffer = 0; init_revisions(&revs, prefix); @@ -163,6 +162,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix) prune_object_dir(get_object_directory()); prune_packed_objects(show_only); - remove_temporary_files(); + remove_temporary_files(get_object_directory()); + s = xstrdup(mkpath("%s/pack", get_object_directory())); + remove_temporary_files(s); + free(s); return 0; } diff --git a/builtin-read-tree.c b/builtin-read-tree.c index ac219ac2d..0706c9581 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -206,6 +206,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) break; case 2: opts.fn = twoway_merge; + opts.initial_checkout = !active_nr; break; case 3: default: diff --git a/builtin-remote.c b/builtin-remote.c index 01945a865..90a4e3582 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -407,14 +407,15 @@ static int rm(int argc, const char **argv) return i; } -static void show_list(const char *title, struct string_list *list) +static void show_list(const char *title, struct string_list *list, + const char *extra_arg) { int i; if (!list->nr) return; - printf(title, list->nr > 1 ? "es" : ""); + printf(title, list->nr > 1 ? "es" : "", extra_arg); printf("\n "); for (i = 0; i < list->nr; i++) printf("%s%s", i ? " " : "", list->items[i].string); @@ -477,7 +478,6 @@ static int show(int argc, const char **argv) memset(&states, 0, sizeof(states)); for (; argc; argc--, argv++) { - struct strbuf buf; int i; get_remote_ref_states(*argv, &states, !no_query); @@ -503,18 +503,16 @@ static int show(int argc, const char **argv) } if (!no_query) { - strbuf_init(&buf, 0); - strbuf_addf(&buf, " New remote branch%%s (next fetch " - "will store in remotes/%s)", states.remote->name); - show_list(buf.buf, &states.new); - strbuf_release(&buf); + show_list(" New remote branch%s (next fetch " + "will store in remotes/%s)", + &states.new, states.remote->name); show_list(" Stale tracking branch%s (use 'git remote " - "prune')", &states.stale); + "prune')", &states.stale, ""); } if (no_query) for_each_ref(append_ref_to_tracked_list, &states); - show_list(" Tracked remote branch%s", &states.tracked); + show_list(" Tracked remote branch%s", &states.tracked, ""); if (states.remote->push_refspec_nr) { printf(" Local branch%s pushed with 'git push'\n ", @@ -652,10 +650,13 @@ static int get_one_entry(struct remote *remote, void *priv) { struct string_list *list = priv; - string_list_append(remote->name, list)->util = remote->url_nr ? - (void *)remote->url[0] : NULL; - if (remote->url_nr > 1) - warning("Remote %s has more than one URL", remote->name); + if (remote->url_nr > 0) { + int i; + + for (i = 0; i < remote->url_nr; i++) + string_list_append(remote->name, list)->util = (void *)remote->url[i]; + } else + string_list_append(remote->name, list)->util = NULL; return 0; } @@ -671,10 +672,14 @@ static int show_all(void) sort_string_list(&list); for (i = 0; i < list.nr; i++) { struct string_list_item *item = list.items + i; - printf("%s%s%s\n", item->string, - verbose ? "\t" : "", - verbose && item->util ? - (const char *)item->util : ""); + if (verbose) + printf("%s\t%s\n", item->string, + item->util ? (const char *)item->util : ""); + else { + if (i && !strcmp((item - 1)->string, item->string)) + continue; + printf("%s\n", item->string); + } } } return result; diff --git a/builtin-rm.c b/builtin-rm.c index fdac34f24..50ae6d540 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -29,26 +29,6 @@ static void add_list(const char *name) list.name[list.nr++] = name; } -static int remove_file(const char *name) -{ - int ret; - char *slash; - - ret = unlink(name); - if (ret && errno == ENOENT) - /* The user has removed it from the filesystem by hand */ - ret = errno = 0; - - if (!ret && (slash = strrchr(name, '/'))) { - char *n = xstrdup(name); - do { - n[slash - name] = 0; - name = n; - } while (!rmdir(name) && (slash = strrchr(name, '/'))); - } - return ret; -} - static int check_local_mod(unsigned char *head, int index_only) { /* items in list are already sorted in the cache order, @@ -239,7 +219,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) int removed = 0; for (i = 0; i < list.nr; i++) { const char *path = list.name[i]; - if (!remove_file(path)) { + if (!remove_path(path)) { removed = 1; continue; } diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d3fb6ae50..2d8d1c3d7 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -750,7 +750,7 @@ _git_commit () --*) __gitcomp " --all --author= --signoff --verify --no-verify - --edit --amend --include --only + --edit --amend --include --only --interactive " return esac diff --git a/contrib/hooks/setgitperms.perl b/contrib/hooks/setgitperms.perl index dab7c8e3a..a577ad095 100644 --- a/contrib/hooks/setgitperms.perl +++ b/contrib/hooks/setgitperms.perl @@ -50,7 +50,7 @@ if ((@ARGV < 0) || !GetOptions( )) { die $usage; } die $usage unless ($read_mode xor $write_mode); -my $topdir = `git-rev-parse --show-cdup` or die "\n"; chomp $topdir; +my $topdir = `git rev-parse --show-cdup` or die "\n"; chomp $topdir; my $gitdir = $topdir . '.git'; my $gitmeta = $topdir . '.gitmeta'; @@ -155,7 +155,7 @@ elsif ($read_mode) { open (OUT, ">$gitmeta.tmp") or die "Could not open $gitmeta.tmp for writing: $!\n"; } - my @files = `git-ls-files`; + my @files = `git ls-files`; my %dirs; foreach my $path (@files) { @@ -2417,13 +2417,6 @@ int diff_setup_done(struct diff_options *options) DIFF_OPT_SET(options, EXIT_WITH_STATUS); } - /* - * If we postprocess in diffcore, we cannot simply return - * upon the first hit. We need to run diff as usual. - */ - if (options->pickaxe || options->filter) - DIFF_OPT_CLR(options, QUIET); - return 0; } @@ -3411,10 +3404,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) void diffcore_std(struct diff_options *options) { - if (DIFF_OPT_TST(options, QUIET)) - return; - - if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER)) + if (options->skip_stat_unmatch) diffcore_skip_stat_unmatch(options); if (options->break_opt != -1) diffcore_break(options->break_opt); diff --git a/diffcore.h b/diffcore.h index cc96c2073..8ae35785f 100644 --- a/diffcore.h +++ b/diffcore.h @@ -92,7 +92,6 @@ extern struct diff_filepair *diff_queue(struct diff_queue_struct *, struct diff_filespec *); extern void diff_q(struct diff_queue_struct *, struct diff_filepair *); -extern void diffcore_pathspec(const char **pathspec); extern void diffcore_break(int); extern void diffcore_rename(struct diff_options *); extern void diffcore_merge_broken(void); @@ -831,3 +831,23 @@ void setup_standard_excludes(struct dir_struct *dir) if (excludes_file && !access(excludes_file, R_OK)) add_excludes_from_file(dir, excludes_file); } + +int remove_path(const char *name) +{ + char *slash; + + if (unlink(name) && errno != ENOENT) + return -1; + + slash = strrchr(name, '/'); + if (slash) { + char *dirs = xstrdup(name); + slash = dirs + (slash - name); + do { + *slash = '\0'; + } while (rmdir(dirs) && (slash = strrchr(dirs, '/'))); + free(dirs); + } + return 0; +} + @@ -81,4 +81,7 @@ extern int is_inside_dir(const char *dir); extern void setup_standard_excludes(struct dir_struct *dir); extern int remove_dir_recursively(struct strbuf *path, int only_empty); +/* tries to remove the path with empty directories along it, ignores ENOENT */ +extern int remove_path(const char *path); + #endif diff --git a/fast-import.c b/fast-import.c index ccdf2e57b..ab6689a64 100644 --- a/fast-import.c +++ b/fast-import.c @@ -816,7 +816,7 @@ static void start_packfile(void) int pack_fd; snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_pack_XXXXXX", get_object_directory()); + "%s/pack/tmp_pack_XXXXXX", get_object_directory()); pack_fd = xmkstemp(tmpfile); p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2); strcpy(p->pack_name, tmpfile); @@ -878,7 +878,7 @@ static char *create_index(void) } snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_idx_XXXXXX", get_object_directory()); + "%s/pack/tmp_idx_XXXXXX", get_object_directory()); idx_fd = xmkstemp(tmpfile); f = sha1fd(idx_fd, tmpfile); sha1write(f, array, 256 * sizeof(int)); diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 929d681c4..edb6ec6ed 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -284,7 +284,7 @@ do_next () { pick_one $sha1 || die_with_patch $sha1 "Could not apply $sha1... $rest" make_patch $sha1 - : > "$DOTEST"/amend + git rev-parse --verify HEAD > "$DOTEST"/amend warn "Stopped at $sha1... $rest" warn "You can amend the commit now, with" warn @@ -427,14 +427,22 @@ do else . "$DOTEST"/author-script || die "Cannot find the author identity" + amend= if test -f "$DOTEST"/amend then + amend=$(git rev-parse --verify HEAD) + test "$amend" = $(cat "$DOTEST"/amend) || + die "\ +You have uncommitted changes in your working tree. Please, commit them +first and then run 'git rebase --continue' again." git reset --soft HEAD^ || die "Cannot rewind the HEAD" fi export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE && - git commit --no-verify -F "$DOTEST"/message -e || - die "Could not commit staged changes." + git commit --no-verify -F "$DOTEST"/message -e || { + test -n "$amend" && git reset --soft $amend + die "Could not commit staged changes." + } fi require_clean_work_tree diff --git a/git-repack.sh b/git-repack.sh index 683960b04..d39eb6cea 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -10,7 +10,7 @@ git repack [options] a pack everything in a single pack A same as -a, and turn unreachable objects loose d remove redundant packs, and run git-prune-packed -f pass --no-reuse-delta to git-pack-objects +f pass --no-reuse-object to git-pack-objects n do not run git-update-server-info q,quiet be quiet l pass --local to git-pack-objects diff --git a/git-stash.sh b/git-stash.sh index d799c7637..42f626f9d 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -144,7 +144,14 @@ show_stash () { then flags=--stat fi - s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") + + if test $# = 0 + then + set x "$ref_stash@{0}" + shift + fi + + s=$(git rev-parse --revs-only --no-flags "$@") w_commit=$(git rev-parse --verify "$s") && b_commit=$(git rev-parse --verify "$s^") && @@ -154,7 +161,7 @@ show_stash () { apply_stash () { git update-index -q --refresh && git diff-files --quiet --ignore-submodules || - die 'Cannot restore on top of a dirty state' + die 'Cannot apply to a dirty working tree, please stage your changes' unstash_index= case "$1" in @@ -163,13 +170,19 @@ apply_stash () { shift esac + if test $# = 0 + then + set x "$ref_stash@{0}" + shift + fi + # current index state c_tree=$(git write-tree) || die 'Cannot apply a stash in the middle of a merge' # stash records the work tree, and is a merge between the # base commit (first parent) and the index tree (second parent). - s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") && + s=$(git rev-parse --revs-only --no-flags "$@") && w_tree=$(git rev-parse --verify "$s:") && b_tree=$(git rev-parse --verify "$s^1:") && i_tree=$(git rev-parse --verify "$s^2:") || diff --git a/git-submodule.sh b/git-submodule.sh index 1c39b593a..c3d0d24bc 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -194,7 +194,7 @@ cmd_add() else module_clone "$path" "$realrepo" || exit - (unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) || + (unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) || die "Unable to checkout submodule '$path'" fi @@ -340,8 +340,13 @@ cmd_update() if test "$subsha1" != "$sha1" then + force= + if test -z "$subsha1" + then + force="-f" + fi (unset GIT_DIR; cd "$path" && git-fetch && - git-checkout -q "$sha1") || + git-checkout $force -q "$sha1") || die "Unable to checkout '$sha1' in submodule path '$path'" say "Submodule path '$path': checked out '$sha1'" diff --git a/git-svn.perl b/git-svn.perl index 2fe7bd3c4..af8279aca 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -4010,21 +4010,21 @@ sub gs_do_switch { my $old_url = $full_url; $full_url .= '/' . escape_uri_only($path) if length $path; my ($ra, $reparented); - if ($old_url ne $full_url) { - if ($old_url !~ m#^svn(\+ssh)?://#) { - SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, - $pool); - $self->{url} = $full_url; - $reparented = 1; - } else { - $_[0] = undef; - $self = undef; - $RA = undef; - $ra = Git::SVN::Ra->new($full_url); - $ra_invalid = 1; - } + + if ($old_url =~ m#^svn(\+ssh)?://#) { + $_[0] = undef; + $self = undef; + $RA = undef; + $ra = Git::SVN::Ra->new($full_url); + $ra_invalid = 1; + } elsif ($old_url ne $full_url) { + SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool); + $self->{url} = $full_url; + $reparented = 1; } + $ra ||= $self; + $url_b = escape_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : (); $reporter->set_path('', $rev_a, 0, @lock, $pool); @@ -162,6 +162,8 @@ static int handle_alias(int *argcp, const char ***argv) alias_string + 1, alias_command); } count = split_cmdline(alias_string, &new_argv); + if (count < 0) + die("Bad alias.%s string", alias_command); option_count = handle_options(&new_argv, &count, &envchanged); if (envchanged) die("alias '%s' changes environment variables\n" diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 29e21564c..da474d082 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2123,7 +2123,7 @@ sub parse_commit_text { last; } } - if ($co{'title'} eq "") { + if (! defined $co{'title'} || $co{'title'} eq "") { $co{'title'} = $co{'title_short'} = '(no commit message)'; } # remove added spaces @@ -165,7 +165,16 @@ static CURL* get_curl_handle(void) { CURL* result = curl_easy_init(); - curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify); + if (!curl_ssl_verify) { + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0); + } else { + /* Verify authenticity of the peer's certificate */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1); + /* The name in the cert must match whom we tried to connect */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2); + } + #if LIBCURL_VERSION_NUM >= 0x070907 curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif diff --git a/index-pack.c b/index-pack.c index a6e91fe3b..530d82037 100644 --- a/index-pack.c +++ b/index-pack.c @@ -172,7 +172,7 @@ static char *open_pack_file(char *pack_name) if (!pack_name) { static char tmpfile[PATH_MAX]; snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_pack_XXXXXX", get_object_directory()); + "%s/pack/tmp_pack_XXXXXX", get_object_directory()); output_fd = xmkstemp(tmpfile); pack_name = xstrdup(tmpfile); } else diff --git a/pack-write.c b/pack-write.c index 939ed5636..3621f1dd3 100644 --- a/pack-write.c +++ b/pack-write.c @@ -45,7 +45,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, if (!index_name) { static char tmpfile[PATH_MAX]; snprintf(tmpfile, sizeof(tmpfile), - "%s/tmp_idx_XXXXXX", get_object_directory()); + "%s/pack/tmp_idx_XXXXXX", get_object_directory()); fd = xmkstemp(tmpfile); index_name = xstrdup(tmpfile); } else { diff --git a/read-cache.c b/read-cache.c index 5150c1e14..5b1b3ad03 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1253,6 +1253,7 @@ int discard_index(struct index_state *istate) istate->cache_nr = 0; istate->cache_changed = 0; istate->timestamp = 0; + istate->name_hash_initialized = 0; free_hash(&istate->name_hash); cache_tree_free(&(istate->cache_tree)); free(istate->alloc); diff --git a/sha1_file.c b/sha1_file.c index 9ee1ed16a..aec81bbae 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2136,7 +2136,9 @@ static void write_sha1_file_prepare(const void *buf, unsigned long len, */ int move_temp_to_file(const char *tmpfile, const char *filename) { - int ret = link(tmpfile, filename); + int ret = 0; + if (link(tmpfile, filename)) + ret = errno; /* * Coda hack - coda doesn't like cross-directory links, diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index a841df2a9..5b5f28880 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -135,3 +135,20 @@ close $wr or die $!; close $rd or die $!; EOF } + +require_svnserve () { + if test -z "$SVNSERVE_PORT" + then + say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)' + test_done + exit + fi +} + +start_svnserve () { + svnserve --listen-port $SVNSERVE_PORT \ + --root "$rawsvnrepo" \ + --listen-once \ + --listen-host 127.0.0.1 & +} + diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh new file mode 100644 index 000000000..e5330395f --- /dev/null +++ b/t/t0024-crlf-archive.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +test_description='respect crlf in git archive' + +. ./test-lib.sh +UNZIP=${UNZIP:-unzip} + +test_expect_success setup ' + + git config core.autocrlf true + + printf "CRLF line ending\r\nAnd another\r\n" > sample && + git add sample && + + test_tick && + git commit -m Initial + +' + +test_expect_success 'tar archive' ' + + git archive --format=tar HEAD | + ( mkdir untarred && cd untarred && "$TAR" -xf - ) + + test_cmp sample untarred/sample + +' + +"$UNZIP" -v >/dev/null 2>&1 +if [ $? -eq 127 ]; then + echo "Skipping ZIP test, because unzip was not found" + test_done + exit +fi + +test_expect_success 'zip archive' ' + + git archive --format=zip HEAD >test.zip && + + ( mkdir unzipped && cd unzipped && unzip ../test.zip ) && + + test_cmp sample unzipped/sample + +' + +test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64567fb94..11b82f43d 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -741,4 +741,14 @@ test_expect_success 'symlinked configuration' ' ' +test_expect_success 'check split_cmdline return' " + git config alias.split-cmdline-fix 'echo \"' && + test_must_fail git split-cmdline-fix && + echo foo > foo && + git add foo && + git commit -m 'initial commit' && + git config branch.master.mergeoptions 'echo \"' && + test_must_fail git merge master + " + test_done diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index de0cdb1cf..0de613dc5 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -535,4 +535,15 @@ test_expect_success 'reset and bind merge' ' ' +test_expect_success 'merge removes empty directories' ' + + git reset --hard master && + git checkout -b rm && + git rm d/e && + git commit -mremoved-d/e && + git checkout master && + git merge -s recursive rm && + test_must_fail test -d d +' + test_done diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh index ae78e334a..c2b24a439 100755 --- a/t/t9113-git-svn-dcommit-new-file.sh +++ b/t/t9113-git-svn-dcommit-new-file.sh @@ -12,19 +12,7 @@ test_description='git-svn dcommit new files over svn:// test' . ./lib-git-svn.sh -if test -z "$SVNSERVE_PORT" -then - say 'skipping svnserve test. (set $SVNSERVE_PORT to enable)' - test_done - exit -fi - -start_svnserve () { - svnserve --listen-port $SVNSERVE_PORT \ - --root "$rawsvnrepo" \ - --listen-once \ - --listen-host 127.0.0.1 & -} +require_svnserve test_expect_success 'start tracking an empty repo' ' svn mkdir -m "empty dir" "$svnrepo"/empty-dir && diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 3281cbd34..43ceb75d5 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -6,6 +6,10 @@ test_description='git-svn funky branch names' . ./lib-git-svn.sh +# Abo-Uebernahme (Bug #994) +scary_uri='Abo-Uebernahme%20%28Bug%20%23994%29' +scary_ref='Abo-Uebernahme%20(Bug%20#994)' + test_expect_success 'setup svnrepo' ' mkdir project project/trunk project/branches project/tags && echo foo > project/trunk/foo && @@ -15,6 +19,8 @@ test_expect_success 'setup svnrepo' ' "$svnrepo/pr ject/branches/fun plugin" && svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \ "$svnrepo/pr ject/branches/more fun plugin!" && + svn cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \ + "$svnrepo/pr ject/branches/$scary_uri" && start_httpd ' @@ -23,6 +29,7 @@ test_expect_success 'test clone with funky branch names' ' cd project && git rev-parse "refs/remotes/fun%20plugin" && git rev-parse "refs/remotes/more%20fun%20plugin!" && + git rev-parse "refs/remotes/$scary_ref" && cd .. ' @@ -35,6 +42,15 @@ test_expect_success 'test dcommit to funky branch' " cd .. " +test_expect_success 'test dcommit to scary branch' ' + cd project && + git reset --hard "refs/remotes/$scary_ref" && + echo urls are scary >> foo && + git commit -m "eep" -- foo && + git svn dcommit && + cd .. + ' + stop_httpd test_done diff --git a/t/t9126-git-svn-follow-deleted-readded-directory.sh b/t/t9126-git-svn-follow-deleted-readded-directory.sh new file mode 100755 index 000000000..edec640e9 --- /dev/null +++ b/t/t9126-git-svn-follow-deleted-readded-directory.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Copyright (c) 2008 Alec Berryman + +test_description='git svn fetch repository with deleted and readded directory' + +. ./lib-git-svn.sh + +# Don't run this by default; it opens up a port. +require_svnserve + +test_expect_success 'load repository' ' + svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9126/follow-deleted-readded.dump + ' + +test_expect_success 'fetch repository' ' + start_svnserve && + git svn init svn://127.0.0.1:$SVNSERVE_PORT && + git svn fetch + ' + +test_done diff --git a/t/t9126/follow-deleted-readded.dump b/t/t9126/follow-deleted-readded.dump new file mode 100644 index 000000000..19da5d1dd --- /dev/null +++ b/t/t9126/follow-deleted-readded.dump @@ -0,0 +1,201 @@ +SVN-fs-dump-format-version: 2 + +UUID: 1807dc6f-c693-4cda-9710-00e1be8c1f21 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2008-09-14T19:53:13.006748Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 111 +Content-length: 111 + +K 7 +svn:log +V 12 +Create trunk +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:13.239689Z +PROPS-END + +Node-path: trunk +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 2 +Prop-content-length: 119 +Content-length: 119 + +K 7 +svn:log +V 20 +Create trunk/project +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:13.548860Z +PROPS-END + +Node-path: trunk/project +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Revision-number: 3 +Prop-content-length: 111 +Content-length: 111 + +K 7 +svn:log +V 12 +add new file +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:15.433630Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 4 +Text-content-md5: d3b07384d113edec49eaa6238ad5ff00 +Content-length: 14 + +PROPS-END +foo + + +Revision-number: 4 +Prop-content-length: 116 +Content-length: 116 + +K 7 +svn:log +V 17 +change foo to bar +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:17.339884Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: c157a79031e1c40f85931829bc5fc552 +Content-length: 4 + +bar + + +Revision-number: 5 +Prop-content-length: 114 +Content-length: 114 + +K 7 +svn:log +V 15 +don't like that +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:19.335001Z +PROPS-END + +Node-path: trunk/project +Node-action: delete + + +Revision-number: 6 +Prop-content-length: 110 +Content-length: 110 + +K 7 +svn:log +V 11 +reset trunk +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:19.845897Z +PROPS-END + +Node-path: trunk/project +Node-kind: dir +Node-action: add +Node-copyfrom-rev: 4 +Node-copyfrom-path: trunk/project + + +Revision-number: 7 +Prop-content-length: 113 +Content-length: 113 + +K 7 +svn:log +V 14 +change to quux +K 10 +svn:author +V 4 +alec +K 8 +svn:date +V 27 +2008-09-14T19:53:21.367947Z +PROPS-END + +Node-path: trunk/project/foo +Node-kind: file +Node-action: change +Text-content-length: 5 +Text-content-md5: d3b07a382ec010c01889250fce66fb13 +Content-length: 5 + +quux + + diff --git a/templates/Makefile b/templates/Makefile index 0722a926f..a12c6e214 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -31,9 +31,11 @@ boilerplates.made : $(bpsrc) dir=`expr "$$dst" : '\(.*\)/'` && \ mkdir -p blt/$$dir && \ case "$$boilerplate" in \ - *--) ;; \ - *) cp -p $$boilerplate blt/$$dst ;; \ - esac || exit; \ + *--) continue;; \ + esac && \ + cp $$boilerplate blt/$$dst && \ + if test -x "blt/$$dst"; then rx=rx; else rx=r; fi && \ + chmod a+$$rx "blt/$$dst" || exit; \ done && \ date >$@ diff --git a/unpack-trees.c b/unpack-trees.c index ef21c6219..e59d144d2 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -941,8 +941,17 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o) return -1; } } - else if (newtree) + else if (newtree) { + if (oldtree && !o->initial_checkout) { + /* + * deletion of the path was staged; + */ + if (same(oldtree, newtree)) + return 1; + return reject_merge(oldtree, o); + } return merged_entry(newtree, current, o); + } return deleted_entry(oldtree, current, o); } diff --git a/unpack-trees.h b/unpack-trees.h index 94e567265..0d26f3d73 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -26,6 +26,7 @@ struct unpack_trees_options { verbose_update:1, aggressive:1, skip_unmerged:1, + initial_checkout:1, gently:1; const char *prefix; int pos; |