diff options
Diffstat (limited to 'builtin')
39 files changed, 699 insertions, 393 deletions
diff --git a/builtin/add.c b/builtin/add.c index e57abddf52..c59b0c98fe 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -242,7 +242,7 @@ int run_add_interactive(const char *revision, const char *patch_mode, return status; } -int interactive_add(int argc, const char **argv, const char *prefix) +int interactive_add(int argc, const char **argv, const char *prefix, int patch) { const char **pathspec = NULL; @@ -253,7 +253,7 @@ int interactive_add(int argc, const char **argv, const char *prefix) } return run_add_interactive(NULL, - patch_interactive ? "--patch" : NULL, + patch ? "--patch" : NULL, pathspec); } @@ -378,7 +378,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (patch_interactive) add_interactive = 1; if (add_interactive) - exit(interactive_add(argc - 1, argv + 1, prefix)); + exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive)); if (edit_interactive) return(edit_patch(argc, argv, prefix)); diff --git a/builtin/apply.c b/builtin/apply.c index 530d4bb7e7..f2edc52818 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -1634,7 +1634,7 @@ static inline int metadata_changes(struct patch *patch) static char *inflate_it(const void *data, unsigned long size, unsigned long inflated_size) { - z_stream stream; + git_zstream stream; void *out; int st; diff --git a/builtin/archive.c b/builtin/archive.c index b14eaba159..883c0092ad 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -24,7 +24,8 @@ static void create_output_file(const char *output_file) } static int run_remote_archiver(int argc, const char **argv, - const char *remote, const char *exec) + const char *remote, const char *exec, + const char *name_hint) { char buf[LARGE_PACKET_MAX]; int fd[2], i, len, rv; @@ -37,6 +38,17 @@ static int run_remote_archiver(int argc, const char **argv, transport = transport_get(_remote, _remote->url[0]); transport_connect(transport, "git-upload-archive", exec, fd); + /* + * Inject a fake --format field at the beginning of the + * arguments, with the format inferred from our output + * filename. This way explicit --format options can override + * it. + */ + if (name_hint) { + const char *format = archive_format_from_filename(name_hint); + if (format) + packet_write(fd[1], "argument --format=%s\n", format); + } for (i = 1; i < argc; i++) packet_write(fd[1], "argument %s\n", argv[i]); packet_flush(fd[1]); @@ -63,17 +75,6 @@ static int run_remote_archiver(int argc, const char **argv, return !!rv; } -static const char *format_from_name(const char *filename) -{ - const char *ext = strrchr(filename, '.'); - if (!ext) - return NULL; - ext++; - if (!strcasecmp(ext, "zip")) - return "--format=zip"; - return NULL; -} - #define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | \ PARSE_OPT_KEEP_ARGV0 | \ PARSE_OPT_KEEP_UNKNOWN | \ @@ -84,7 +85,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix) const char *exec = "git-upload-archive"; const char *output = NULL; const char *remote = NULL; - const char *format_option = NULL; struct option local_opts[] = { OPT_STRING('o', "output", &output, "file", "write the archive to this file"), @@ -98,32 +98,13 @@ int cmd_archive(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, local_opts, NULL, PARSE_OPT_KEEP_ALL); - if (output) { + if (output) create_output_file(output); - format_option = format_from_name(output); - } - - /* - * We have enough room in argv[] to muck it in place, because - * --output must have been given on the original command line - * if we get to this point, and parse_options() must have eaten - * it, i.e. we can add back one element to the array. - * - * We add a fake --format option at the beginning, with the - * format inferred from our output filename. This way explicit - * --format options can override it, and the fake option is - * inserted before any "--" that might have been given. - */ - if (format_option) { - memmove(argv + 2, argv + 1, sizeof(*argv) * argc); - argv[1] = format_option; - argv[++argc] = NULL; - } if (remote) - return run_remote_archiver(argc, argv, remote, exec); + return run_remote_archiver(argc, argv, remote, exec, output); setvbuf(stderr, NULL, _IOLBF, BUFSIZ); - return write_archive(argc, argv, prefix, 1); + return write_archive(argc, argv, prefix, 1, output, 0); } diff --git a/builtin/blame.c b/builtin/blame.c index 4242e4b513..26a5d424b8 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1484,13 +1484,14 @@ static void write_filename_info(const char *path) /* * Porcelain/Incremental format wants to show a lot of details per * commit. Instead of repeating this every line, emit it only once, - * the first time each commit appears in the output. + * the first time each commit appears in the output (unless the + * user has specifically asked for us to repeat). */ -static int emit_one_suspect_detail(struct origin *suspect) +static int emit_one_suspect_detail(struct origin *suspect, int repeat) { struct commit_info ci; - if (suspect->commit->object.flags & METAINFO_SHOWN) + if (!repeat && (suspect->commit->object.flags & METAINFO_SHOWN)) return 0; suspect->commit->object.flags |= METAINFO_SHOWN; @@ -1529,7 +1530,7 @@ static void found_guilty_entry(struct blame_entry *ent) printf("%s %d %d %d\n", sha1_to_hex(suspect->commit->object.sha1), ent->s_lno + 1, ent->lno + 1, ent->num_lines); - emit_one_suspect_detail(suspect); + emit_one_suspect_detail(suspect, 0); write_filename_info(suspect->path); maybe_flush_or_die(stdout, "stdout"); } @@ -1618,9 +1619,19 @@ static const char *format_time(unsigned long time, const char *tz_str, #define OUTPUT_SHOW_SCORE 0100 #define OUTPUT_NO_AUTHOR 0200 #define OUTPUT_SHOW_EMAIL 0400 +#define OUTPUT_LINE_PORCELAIN 01000 -static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) +static void emit_porcelain_details(struct origin *suspect, int repeat) { + if (emit_one_suspect_detail(suspect, repeat) || + (suspect->commit->object.flags & MORE_THAN_ONE_PATH)) + write_filename_info(suspect->path); +} + +static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, + int opt) +{ + int repeat = opt & OUTPUT_LINE_PORCELAIN; int cnt; const char *cp; struct origin *suspect = ent->suspect; @@ -1633,17 +1644,18 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) ent->s_lno + 1, ent->lno + 1, ent->num_lines); - if (emit_one_suspect_detail(suspect) || - (suspect->commit->object.flags & MORE_THAN_ONE_PATH)) - write_filename_info(suspect->path); + emit_porcelain_details(suspect, repeat); cp = nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; - if (cnt) + if (cnt) { printf("%s %d %d\n", hex, ent->s_lno + 1 + cnt, ent->lno + 1 + cnt); + if (repeat) + emit_porcelain_details(suspect, 1); + } putchar('\t'); do { ch = *cp++; @@ -1756,7 +1768,7 @@ static void output(struct scoreboard *sb, int option) for (ent = sb->ent; ent; ent = ent->next) { if (option & OUTPUT_PORCELAIN) - emit_porcelain(sb, ent); + emit_porcelain(sb, ent, option); else { emit_other(sb, ent, option); } @@ -2300,6 +2312,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME), OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER), OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN), + OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN), OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT), OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP), OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME), diff --git a/builtin/branch.c b/builtin/branch.c index 9cca1b9afc..3142daa57a 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -19,7 +19,7 @@ static const char * const builtin_branch_usage[] = { "git branch [options] [-r | -a] [--merged | --no-merged]", "git branch [options] [-l] [-f] <branchname> [<start-point>]", - "git branch [options] [-r] (-d | -D) <branchname>", + "git branch [options] [-r] (-d | -D) <branchname>...", "git branch [options] (-m | -M) [<oldbranch>] <newbranch>", NULL }; @@ -399,9 +399,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item, struct commit *commit = item->commit; if (commit && !parse_commit(commit)) { - struct pretty_print_context ctx = {0}; - pretty_print_commit(CMIT_FMT_ONELINE, commit, - &subject, &ctx); + pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject); sub = subject.buf; } diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 94632dbdb4..07bd984084 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -187,6 +187,8 @@ static int batch_one_object(const char *obj_name, int print_contents) if (type <= 0) { printf("%s missing\n", obj_name); fflush(stdout); + if (print_contents == BATCH) + free(contents); return 0; } diff --git a/builtin/checkout.c b/builtin/checkout.c index 4761769512..d647a31303 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -306,9 +306,8 @@ static void show_local_changes(struct object *head, struct diff_options *opts) static void describe_detached_head(const char *msg, struct commit *commit) { struct strbuf sb = STRBUF_INIT; - struct pretty_print_context ctx = {0}; parse_commit(commit); - pretty_print_commit(CMIT_FMT_ONELINE, commit, &sb, &ctx); + pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb); fprintf(stderr, "%s %s... %s\n", msg, find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV), sb.buf); strbuf_release(&sb); @@ -623,14 +622,12 @@ static int clear_commit_marks_from_one_ref(const char *refname, static void describe_one_orphan(struct strbuf *sb, struct commit *commit) { - struct pretty_print_context ctx = { 0 }; - parse_commit(commit); strbuf_addstr(sb, " "); strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV)); strbuf_addch(sb, ' '); - pretty_print_commit(CMIT_FMT_ONELINE, commit, sb, &ctx); + pp_commit_easy(CMIT_FMT_ONELINE, commit, sb); strbuf_addch(sb, '\n'); } @@ -660,24 +657,25 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs) "Warning: you are leaving %d commit behind, " "not connected to\n" "any of your branches:\n\n" - "%s\n" - "If you want to keep it by creating a new branch, " - "this may be a good time\nto do so with:\n\n" - " git branch new_branch_name %s\n\n", + "%s\n", /* The plural version */ "Warning: you are leaving %d commits behind, " "not connected to\n" "any of your branches:\n\n" - "%s\n" - "If you want to keep them by creating a new branch, " - "this may be a good time\nto do so with:\n\n" - " git branch new_branch_name %s\n\n", + "%s\n", /* Give ngettext() the count */ lost), lost, - sb.buf, - sha1_to_hex(commit->object.sha1)); + sb.buf); strbuf_release(&sb); + + if (advice_detached_head) + fprintf(stderr, + _( + "If you want to keep them by creating a new branch, " + "this may be a good time\nto do so with:\n\n" + " git branch new_branch_name %s\n\n"), + sha1_to_hex(commit->object.sha1)); } /* @@ -718,10 +716,12 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) unsigned char rev[20]; int flag; memset(&old, 0, sizeof(old)); - old.path = resolve_ref("HEAD", rev, 0, &flag); + old.path = xstrdup(resolve_ref("HEAD", rev, 0, &flag)); old.commit = lookup_commit_reference_gently(rev, 1); - if (!(flag & REF_ISSYMREF)) + if (!(flag & REF_ISSYMREF)) { + free((char *)old.path); old.path = NULL; + } if (old.path && !prefixcmp(old.path, "refs/heads/")) old.name = old.path + strlen("refs/heads/"); @@ -744,6 +744,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) update_refs_for_switch(opts, &old, new); ret = post_checkout_hook(old.commit, new->commit, 1); + free((char *)old.path); return ret || opts->writeout_error; } @@ -1074,7 +1075,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (strbuf_check_branch_ref(&buf, opts.new_branch)) die(_("git checkout: we do not like '%s' as a branch name."), opts.new_branch); - if (!get_sha1(buf.buf, rev)) { + if (ref_exists(buf.buf)) { opts.branch_exists = 1; if (!opts.new_branch_force) die(_("git checkout: branch %s already exists"), diff --git a/builtin/clone.c b/builtin/clone.c index 49c838fd3f..a15784a7b8 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -46,6 +46,7 @@ static const char *real_git_dir; static char *option_upload_pack = "git-upload-pack"; static int option_verbosity; static int option_progress; +static struct string_list option_config; static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), @@ -81,9 +82,10 @@ static struct option builtin_clone_options[] = { "path to git-upload-pack on the remote"), OPT_STRING(0, "depth", &option_depth, "depth", "create a shallow clone of that depth"), - OPT_STRING('L', "separate-git-dir", &real_git_dir, "gitdir", + OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir", "separate git dir from working tree"), - + OPT_STRING_LIST('c', "config", &option_config, "key=value", + "set config inside the new repository"), OPT_END() }; @@ -364,6 +366,22 @@ static void write_remote_refs(const struct ref *local_refs) clear_extra_refs(); } +static int write_one_config(const char *key, const char *value, void *data) +{ + return git_config_set_multivar(key, value ? value : "true", "^$", 0); +} + +static void write_config(struct string_list *config) +{ + int i; + + for (i = 0; i < config->nr; i++) { + if (git_config_parse_parameter(config->items[i].string, + write_one_config, NULL) < 0) + die("unable to write parameters to config file"); + } +} + int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; @@ -482,6 +500,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) printf(_("Cloning into %s...\n"), dir); } init_db(option_template, INIT_DB_QUIET); + write_config(&option_config); /* * At this point, the config exists, so we do not need the diff --git a/builtin/commit.c b/builtin/commit.c index 411d5e4153..e1af9b19f0 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -83,7 +83,7 @@ static const char *template_file; static const char *author_message, *author_message_buffer; static char *edit_message, *use_message; static char *fixup_message, *squash_message; -static int all, edit_flag, also, interactive, only, amend, signoff; +static int all, edit_flag, also, interactive, patch_interactive, only, amend, signoff; static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; static int no_post_rewrite, allow_empty_message; static char *untracked_files_arg, *force_date, *ignore_submodule_arg; @@ -152,6 +152,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('a', "all", &all, "commit all changed files"), OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"), OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"), + OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"), OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"), @@ -336,18 +337,11 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int int fd; struct string_list partial; const char **pathspec = NULL; + char *old_index_env = NULL; int refresh_flags = REFRESH_QUIET; if (is_status) refresh_flags |= REFRESH_UNMERGED; - if (interactive) { - if (interactive_add(argc, argv, prefix) != 0) - die(_("interactive add failed")); - if (read_cache_preload(NULL) < 0) - die(_("index file corrupt")); - commit_style = COMMIT_AS_IS; - return get_index_file(); - } if (*argv) pathspec = get_pathspec(prefix, argv); @@ -355,6 +349,33 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int if (read_cache_preload(pathspec) < 0) die(_("index file corrupt")); + if (interactive) { + fd = hold_locked_index(&index_lock, 1); + + refresh_cache_or_die(refresh_flags); + + if (write_cache(fd, active_cache, active_nr) || + close_lock_file(&index_lock)) + die(_("unable to create temporary index")); + + old_index_env = getenv(INDEX_ENVIRONMENT); + setenv(INDEX_ENVIRONMENT, index_lock.filename, 1); + + if (interactive_add(argc, argv, prefix, patch_interactive) != 0) + die(_("interactive add failed")); + + if (old_index_env && *old_index_env) + setenv(INDEX_ENVIRONMENT, old_index_env, 1); + else + unsetenv(INDEX_ENVIRONMENT); + + discard_cache(); + read_cache_from(index_lock.filename); + + commit_style = COMMIT_NORMAL; + return index_lock.filename; + } + /* * Non partial, non as-is commit. * @@ -1043,8 +1064,11 @@ static int parse_and_validate_options(int argc, const char *argv[], author_message_buffer = read_commit_message(author_message); } + if (patch_interactive) + interactive = 1; + if (!!also + !!only + !!all + !!interactive > 1) - die(_("Only one of --include/--only/--all/--interactive can be used.")); + die(_("Only one of --include/--only/--all/--interactive/--patch can be used.")); if (argc == 0 && (also || (only && !amend))) die(_("No paths with --include/--only does not make sense.")); if (argc == 0 && only && amend) @@ -1066,8 +1090,6 @@ static int parse_and_validate_options(int argc, const char *argv[], if (all && argc > 0) die(_("Paths with -a does not make sense.")); - else if (interactive && argc > 0) - die(_("Paths with --interactive does not make sense.")); if (null_termination && status_format == STATUS_FORMAT_LONG) status_format = STATUS_FORMAT_PORCELAIN; @@ -1185,9 +1207,6 @@ int cmd_status(int argc, const char **argv, const char *prefix) if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_status_usage, builtin_status_options); - if (null_termination && status_format == STATUS_FORMAT_LONG) - status_format = STATUS_FORMAT_PORCELAIN; - wt_status_prepare(&s); gitmodules_config(); git_config(git_status_config, &s); @@ -1195,6 +1214,10 @@ int cmd_status(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_status_options, builtin_status_usage, 0); + + if (null_termination && status_format == STATUS_FORMAT_LONG) + status_format = STATUS_FORMAT_PORCELAIN; + handle_untracked_files_arg(&s); if (show_ignored_in_status) s.show_ignored_files = 1; diff --git a/builtin/config.c b/builtin/config.c index 3e3c528497..211e118d57 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -436,9 +436,14 @@ int cmd_config(int argc, const char **argv, const char *prefix) NULL, NULL); } else if (actions == ACTION_SET) { + int ret; check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); - return git_config_set(argv[0], value); + ret = git_config_set(argv[0], value); + if (ret == CONFIG_NOTHING_SET) + error("cannot overwrite multiple values with a single value\n" + " Use a regexp, --add or --set-all to change %s.", argv[0]); + return ret; } else if (actions == ACTION_SET_ALL) { check_argc(argc, 2, 3); diff --git a/builtin/diff.c b/builtin/diff.c index 14bd14fce0..69cd5eed78 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -182,6 +182,7 @@ static int builtin_diff_combined(struct rev_info *revs, hashcpy((unsigned char *)(parent + i), ent[i].item->sha1); diff_tree_combined(parent[0], parent + 1, ents - 1, revs->dense_combined_merges, revs); + free(parent); return 0; } diff --git a/builtin/fast-export.c b/builtin/fast-export.c index daf19451ba..becef85782 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -26,6 +26,7 @@ static int progress; static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT; static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT; static int fake_missing_tagger; +static int use_done_feature; static int no_data; static int full_tree; @@ -627,6 +628,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) "Fake a tagger when tags lack one"), OPT_BOOLEAN(0, "full-tree", &full_tree, "Output full tree for each commit"), + OPT_BOOLEAN(0, "use-done-feature", &use_done_feature, + "Use the done feature to terminate the stream"), { OPTION_NEGBIT, 0, "data", &no_data, NULL, "Skip output of blob data", PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 }, @@ -648,6 +651,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (argc > 1) usage_with_options (fast_export_usage, options); + if (use_done_feature) + printf("feature done\n"); + if (import_filename) import_marks(import_filename); @@ -675,5 +681,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (export_filename) export_marks(export_filename); + if (use_done_feature) + printf("done\n"); + return 0; } diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 85aff029b2..4367984102 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -226,7 +226,7 @@ static void insert_one_alternate_ref(const struct ref *ref, void *unused) static void insert_alternate_refs(void) { - foreach_alt_odb(refs_from_alternate_cb, insert_one_alternate_ref); + for_each_alternate_ref(insert_one_alternate_ref, NULL); } #define INITIAL_FLUSH 16 @@ -472,8 +472,10 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag, } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; - commit->object.flags |= COMPLETE; - commit_list_insert_by_date(commit, &complete); + if (!(commit->object.flags & COMPLETE)) { + commit->object.flags |= COMPLETE; + commit_list_insert_by_date(commit, &complete); + } } return 0; } diff --git a/builtin/fetch.c b/builtin/fetch.c index f9c41da475..93c99385a9 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -875,6 +875,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv) { int i; static const char **refs = NULL; + struct refspec *refspec; int ref_nr = 0; int exit_code; @@ -915,8 +916,9 @@ static int fetch_one(struct remote *remote, int argc, const char **argv) sigchain_push_common(unlock_pack_on_signal); atexit(unlock_pack); - exit_code = do_fetch(transport, - parse_fetch_refspec(ref_nr, refs), ref_nr); + refspec = parse_fetch_refspec(ref_nr, refs); + exit_code = do_fetch(transport, refspec, ref_nr); + free(refspec); transport_disconnect(transport); transport = NULL; return exit_code; diff --git a/builtin/gc.c b/builtin/gc.c index ff5f73ba87..0498094711 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -225,7 +225,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) fprintf(stderr, _("Auto packing the repository for optimum performance. You may also\n" "run \"git gc\" manually. See " - "\"git help gc\" for more information.")); + "\"git help gc\" for more information.\n")); } else append_option(argv_repack, prune_expire && !strcmp(prune_expire, "now") diff --git a/builtin/grep.c b/builtin/grep.c index 3ee2ec51de..cccf8da6d2 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -93,8 +93,7 @@ static pthread_cond_t cond_write; /* Signalled when we are finished with everything. */ static pthread_cond_t cond_result; -static int print_hunk_marks_between_files; -static int printed_something; +static int skip_first_line; static void add_work(enum work_type type, char *name, void *id) { @@ -160,10 +159,20 @@ static void work_done(struct work_item *w) todo_done = (todo_done+1) % ARRAY_SIZE(todo)) { w = &todo[todo_done]; if (w->out.len) { - if (print_hunk_marks_between_files && printed_something) - write_or_die(1, "--\n", 3); - write_or_die(1, w->out.buf, w->out.len); - printed_something = 1; + const char *p = w->out.buf; + size_t len = w->out.len; + + /* Skip the leading hunk mark of the first file. */ + if (skip_first_line) { + while (len) { + len--; + if (*p++ == '\n') + break; + } + skip_first_line = 0; + } + + write_or_die(1, p, len); } free(w->name); free(w->identifier); @@ -753,6 +762,15 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int i; int dummy; int use_index = 1; + enum { + pattern_type_unspecified = 0, + pattern_type_bre, + pattern_type_ere, + pattern_type_fixed, + pattern_type_pcre, + }; + int pattern_type = pattern_type_unspecified; + struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, "search in index instead of in the work tree"), @@ -774,13 +792,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) "descend at most <depth> levels", PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), - OPT_BIT('E', "extended-regexp", &opt.regflags, - "use extended POSIX regular expressions", REG_EXTENDED), - OPT_NEGBIT('G', "basic-regexp", &opt.regflags, - "use basic POSIX regular expressions (default)", - REG_EXTENDED), - OPT_BOOLEAN('F', "fixed-strings", &opt.fixed, - "interpret patterns as fixed strings"), + OPT_SET_INT('E', "extended-regexp", &pattern_type, + "use extended POSIX regular expressions", + pattern_type_ere), + OPT_SET_INT('G', "basic-regexp", &pattern_type, + "use basic POSIX regular expressions (default)", + pattern_type_bre), + OPT_SET_INT('F', "fixed-strings", &pattern_type, + "interpret patterns as fixed strings", + pattern_type_fixed), + OPT_SET_INT('P', "perl-regexp", &pattern_type, + "use Perl-compatible regular expressions", + pattern_type_pcre), OPT_GROUP(""), OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"), OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1), @@ -799,6 +822,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN('c', "count", &opt.count, "show the number of matches instead of matching lines"), OPT__COLOR(&opt.color, "highlight matches"), + OPT_BOOLEAN(0, "break", &opt.file_break, + "print empty line between matches from different files"), + OPT_BOOLEAN(0, "heading", &opt.heading, + "show filename only once above matches from same file"), OPT_GROUP(""), OPT_CALLBACK('C', NULL, &opt, "n", "show <n> context lines before and after matches", @@ -886,6 +913,28 @@ int cmd_grep(int argc, const char **argv, const char *prefix) PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION | PARSE_OPT_NO_INTERNAL_HELP); + switch (pattern_type) { + case pattern_type_fixed: + opt.fixed = 1; + opt.pcre = 0; + break; + case pattern_type_bre: + opt.fixed = 0; + opt.pcre = 0; + opt.regflags &= ~REG_EXTENDED; + break; + case pattern_type_ere: + opt.fixed = 0; + opt.pcre = 0; + opt.regflags |= REG_EXTENDED; + break; + case pattern_type_pcre: + opt.fixed = 0; + opt.pcre = 1; + break; + default: + break; /* nothing */ + } if (use_index && !startup_info->have_repository) /* die the same way as if we did it at the beginning */ @@ -925,16 +974,14 @@ int cmd_grep(int argc, const char **argv, const char *prefix) die(_("no pattern given.")); if (!opt.fixed && opt.ignore_case) opt.regflags |= REG_ICASE; - if ((opt.regflags != REG_NEWLINE) && opt.fixed) - die(_("cannot mix --fixed-strings and regexp")); #ifndef NO_PTHREADS if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; if (use_threads) { - if (opt.pre_context || opt.post_context) - print_hunk_marks_between_files = 1; + if (opt.pre_context || opt.post_context || opt.file_break) + skip_first_line = 1; start_threads(&opt); } #else @@ -969,13 +1016,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) verify_filename(prefix, argv[j]); } - if (i < argc) - paths = get_pathspec(prefix, argv + i); - else if (prefix) { - paths = xcalloc(2, sizeof(const char *)); - paths[0] = prefix; - paths[1] = NULL; - } + paths = get_pathspec(prefix, argv + i); init_pathspec(&pathspec, paths); pathspec.max_depth = opt.max_depth; pathspec.recursive = 1; diff --git a/builtin/index-pack.c b/builtin/index-pack.c index e40451ffb4..0945adbb3b 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -11,7 +11,7 @@ #include "exec_cmd.h" static const char index_pack_usage[] = -"git index-pack [-v] [-o <index-file>] [ --keep | --keep=<msg> ] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])"; +"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])"; struct object_entry { struct pack_idx_entry idx; @@ -19,6 +19,8 @@ struct object_entry { unsigned int hdr_size; enum object_type type; enum object_type real_type; + unsigned delta_depth; + int base_object_no; }; union delta_base { @@ -66,6 +68,7 @@ static struct progress *progress; static unsigned char input_buffer[4096]; static unsigned int input_offset, input_len; static off_t consumed_bytes; +static unsigned deepest_delta; static git_SHA_CTX input_ctx; static uint32_t input_crc32; static int input_fd, output_fd, pack_fd; @@ -265,7 +268,7 @@ static void unlink_base_data(struct base_data *c) static void *unpack_entry_data(unsigned long offset, unsigned long size) { int status; - z_stream stream; + git_zstream stream; void *buf = xmalloc(size); memset(&stream, 0, sizeof(stream)); @@ -355,7 +358,7 @@ static void *get_data_from_pack(struct object_entry *obj) off_t from = obj[0].idx.offset + obj[0].hdr_size; unsigned long len = obj[1].idx.offset - from; unsigned char *data, *inbuf; - z_stream stream; + git_zstream stream; int status; data = xmalloc(obj->size); @@ -389,7 +392,18 @@ static void *get_data_from_pack(struct object_entry *obj) return data; } -static int find_delta(const union delta_base *base) +static int compare_delta_bases(const union delta_base *base1, + const union delta_base *base2, + enum object_type type1, + enum object_type type2) +{ + int cmp = type1 - type2; + if (cmp) + return cmp; + return memcmp(base1, base2, UNION_BASE_SZ); +} + +static int find_delta(const union delta_base *base, enum object_type type) { int first = 0, last = nr_deltas; @@ -398,7 +412,8 @@ static int find_delta(const union delta_base *base) struct delta_entry *delta = &deltas[next]; int cmp; - cmp = memcmp(base, &delta->base, UNION_BASE_SZ); + cmp = compare_delta_bases(base, &delta->base, + type, objects[delta->obj_no].type); if (!cmp) return next; if (cmp < 0) { @@ -411,9 +426,10 @@ static int find_delta(const union delta_base *base) } static void find_delta_children(const union delta_base *base, - int *first_index, int *last_index) + int *first_index, int *last_index, + enum object_type type) { - int first = find_delta(base); + int first = find_delta(base, type); int last = first; int end = nr_deltas - 1; @@ -483,12 +499,17 @@ static void sha1_object(const void *data, unsigned long size, } } +static int is_delta_type(enum object_type type) +{ + return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA); +} + static void *get_base_data(struct base_data *c) { if (!c->data) { struct object_entry *obj = c->obj; - if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) { + if (is_delta_type(obj->type)) { void *base = get_base_data(c->base); void *raw = get_data_from_pack(obj); c->data = patch_delta( @@ -515,6 +536,10 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data, *delta_data; delta_obj->real_type = base->obj->real_type; + delta_obj->delta_depth = base->obj->delta_depth + 1; + if (deepest_delta < delta_obj->delta_depth) + deepest_delta = delta_obj->delta_depth; + delta_obj->base_object_no = base->obj - objects; delta_data = get_data_from_pack(delta_obj); base_data = get_base_data(base); result->obj = delta_obj; @@ -541,11 +566,13 @@ static void find_unresolved_deltas(struct base_data *base, union delta_base base_spec; hashcpy(base_spec.sha1, base->obj->idx.sha1); - find_delta_children(&base_spec, &ref_first, &ref_last); + find_delta_children(&base_spec, + &ref_first, &ref_last, OBJ_REF_DELTA); memset(&base_spec, 0, sizeof(base_spec)); base_spec.offset = base->obj->idx.offset; - find_delta_children(&base_spec, &ofs_first, &ofs_last); + find_delta_children(&base_spec, + &ofs_first, &ofs_last, OBJ_OFS_DELTA); } if (ref_last == -1 && ofs_last == -1) { @@ -557,24 +584,24 @@ static void find_unresolved_deltas(struct base_data *base, for (i = ref_first; i <= ref_last; i++) { struct object_entry *child = objects + deltas[i].obj_no; - if (child->real_type == OBJ_REF_DELTA) { - struct base_data result; - resolve_delta(child, base, &result); - if (i == ref_last && ofs_last == -1) - free_base_data(base); - find_unresolved_deltas(&result, base); - } + struct base_data result; + + assert(child->real_type == OBJ_REF_DELTA); + resolve_delta(child, base, &result); + if (i == ref_last && ofs_last == -1) + free_base_data(base); + find_unresolved_deltas(&result, base); } for (i = ofs_first; i <= ofs_last; i++) { struct object_entry *child = objects + deltas[i].obj_no; - if (child->real_type == OBJ_OFS_DELTA) { - struct base_data result; - resolve_delta(child, base, &result); - if (i == ofs_last) - free_base_data(base); - find_unresolved_deltas(&result, base); - } + struct base_data result; + + assert(child->real_type == OBJ_OFS_DELTA); + resolve_delta(child, base, &result); + if (i == ofs_last) + free_base_data(base); + find_unresolved_deltas(&result, base); } unlink_base_data(base); @@ -584,7 +611,11 @@ static int compare_delta_entry(const void *a, const void *b) { const struct delta_entry *delta_a = a; const struct delta_entry *delta_b = b; - return memcmp(&delta_a->base, &delta_b->base, UNION_BASE_SZ); + + /* group by type (ref vs ofs) and then by value (sha-1 or offset) */ + return compare_delta_bases(&delta_a->base, &delta_b->base, + objects[delta_a->obj_no].type, + objects[delta_b->obj_no].type); } /* Parse all objects and return the pack content SHA1 hash */ @@ -608,7 +639,7 @@ static void parse_pack_objects(unsigned char *sha1) struct object_entry *obj = &objects[i]; void *data = unpack_raw_entry(obj, &delta->base); obj->real_type = obj->type; - if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) { + if (is_delta_type(obj->type)) { nr_deltas++; delta->obj_no = i; delta++; @@ -655,7 +686,7 @@ static void parse_pack_objects(unsigned char *sha1) struct object_entry *obj = &objects[i]; struct base_data base_obj; - if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) + if (is_delta_type(obj->type)) continue; base_obj.obj = obj; base_obj.data = NULL; @@ -666,26 +697,26 @@ static void parse_pack_objects(unsigned char *sha1) static int write_compressed(struct sha1file *f, void *in, unsigned int size) { - z_stream stream; + git_zstream stream; int status; unsigned char outbuf[4096]; memset(&stream, 0, sizeof(stream)); - deflateInit(&stream, zlib_compression_level); + git_deflate_init(&stream, zlib_compression_level); stream.next_in = in; stream.avail_in = size; do { stream.next_out = outbuf; stream.avail_out = sizeof(outbuf); - status = deflate(&stream, Z_FINISH); + status = git_deflate(&stream, Z_FINISH); sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out); } while (status == Z_OK); if (status != Z_STREAM_END) die("unable to deflate appended object (%d)", status); size = stream.total_out; - deflateEnd(&stream); + git_deflate_end(&stream); return size; } @@ -859,24 +890,137 @@ static void final(const char *final_pack_name, const char *curr_pack_name, static int git_index_pack_config(const char *k, const char *v, void *cb) { + struct pack_idx_option *opts = cb; + if (!strcmp(k, "pack.indexversion")) { - pack_idx_default_version = git_config_int(k, v); - if (pack_idx_default_version > 2) - die("bad pack.indexversion=%"PRIu32, - pack_idx_default_version); + opts->version = git_config_int(k, v); + if (opts->version > 2) + die("bad pack.indexversion=%"PRIu32, opts->version); return 0; } return git_default_config(k, v, cb); } +static int cmp_uint32(const void *a_, const void *b_) +{ + uint32_t a = *((uint32_t *)a_); + uint32_t b = *((uint32_t *)b_); + + return (a < b) ? -1 : (a != b); +} + +static void read_v2_anomalous_offsets(struct packed_git *p, + struct pack_idx_option *opts) +{ + const uint32_t *idx1, *idx2; + uint32_t i; + + /* The address of the 4-byte offset table */ + idx1 = (((const uint32_t *)p->index_data) + + 2 /* 8-byte header */ + + 256 /* fan out */ + + 5 * p->num_objects /* 20-byte SHA-1 table */ + + p->num_objects /* CRC32 table */ + ); + + /* The address of the 8-byte offset table */ + idx2 = idx1 + p->num_objects; + + for (i = 0; i < p->num_objects; i++) { + uint32_t off = ntohl(idx1[i]); + if (!(off & 0x80000000)) + continue; + off = off & 0x7fffffff; + if (idx2[off * 2]) + continue; + /* + * The real offset is ntohl(idx2[off * 2]) in high 4 + * octets, and ntohl(idx2[off * 2 + 1]) in low 4 + * octets. But idx2[off * 2] is Zero!!! + */ + ALLOC_GROW(opts->anomaly, opts->anomaly_nr + 1, opts->anomaly_alloc); + opts->anomaly[opts->anomaly_nr++] = ntohl(idx2[off * 2 + 1]); + } + + if (1 < opts->anomaly_nr) + qsort(opts->anomaly, opts->anomaly_nr, sizeof(uint32_t), cmp_uint32); +} + +static void read_idx_option(struct pack_idx_option *opts, const char *pack_name) +{ + struct packed_git *p = add_packed_git(pack_name, strlen(pack_name), 1); + + if (!p) + die("Cannot open existing pack file '%s'", pack_name); + if (open_pack_index(p)) + die("Cannot open existing pack idx file for '%s'", pack_name); + + /* Read the attributes from the existing idx file */ + opts->version = p->index_version; + + if (opts->version == 2) + read_v2_anomalous_offsets(p, opts); + + /* + * Get rid of the idx file as we do not need it anymore. + * NEEDSWORK: extract this bit from free_pack_by_name() in + * sha1_file.c, perhaps? It shouldn't matter very much as we + * know we haven't installed this pack (hence we never have + * read anything from it). + */ + close_pack_index(p); + free(p); +} + +static void show_pack_info(int stat_only) +{ + int i, baseobjects = nr_objects - nr_deltas; + unsigned long *chain_histogram = NULL; + + if (deepest_delta) + chain_histogram = xcalloc(deepest_delta, sizeof(unsigned long)); + + for (i = 0; i < nr_objects; i++) { + struct object_entry *obj = &objects[i]; + + if (is_delta_type(obj->type)) + chain_histogram[obj->delta_depth - 1]++; + if (stat_only) + continue; + printf("%s %-6s %lu %lu %"PRIuMAX, + sha1_to_hex(obj->idx.sha1), + typename(obj->real_type), obj->size, + (unsigned long)(obj[1].idx.offset - obj->idx.offset), + (uintmax_t)obj->idx.offset); + if (is_delta_type(obj->type)) { + struct object_entry *bobj = &objects[obj->base_object_no]; + printf(" %u %s", obj->delta_depth, sha1_to_hex(bobj->idx.sha1)); + } + putchar('\n'); + } + + if (baseobjects) + printf("non delta: %d object%s\n", + baseobjects, baseobjects > 1 ? "s" : ""); + for (i = 0; i < deepest_delta; i++) { + if (!chain_histogram[i]) + continue; + printf("chain length = %d: %lu object%s\n", + i + 1, + chain_histogram[i], + chain_histogram[i] > 1 ? "s" : ""); + } +} + int cmd_index_pack(int argc, const char **argv, const char *prefix) { - int i, fix_thin_pack = 0; + int i, fix_thin_pack = 0, verify = 0, stat_only = 0, stat = 0; const char *curr_pack, *curr_index; const char *index_name = NULL, *pack_name = NULL; const char *keep_name = NULL, *keep_msg = NULL; char *index_name_buf = NULL, *keep_name_buf = NULL; struct pack_idx_entry **idx_objects; + struct pack_idx_option opts; unsigned char pack_sha1[20]; if (argc == 2 && !strcmp(argv[1], "-h")) @@ -884,7 +1028,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) read_replace_refs = 0; - git_config(git_index_pack_config, NULL); + reset_pack_idx_option(&opts); + git_config(git_index_pack_config, &opts); if (prefix && chdir(prefix)) die("Cannot come back to cwd"); @@ -898,6 +1043,15 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) fix_thin_pack = 1; } else if (!strcmp(arg, "--strict")) { strict = 1; + } else if (!strcmp(arg, "--verify")) { + verify = 1; + } else if (!strcmp(arg, "--verify-stat")) { + verify = 1; + stat = 1; + } else if (!strcmp(arg, "--verify-stat-only")) { + verify = 1; + stat = 1; + stat_only = 1; } else if (!strcmp(arg, "--keep")) { keep_msg = ""; } else if (!prefixcmp(arg, "--keep=")) { @@ -923,12 +1077,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) index_name = argv[++i]; } else if (!prefixcmp(arg, "--index-version=")) { char *c; - pack_idx_default_version = strtoul(arg + 16, &c, 10); - if (pack_idx_default_version > 2) + opts.version = strtoul(arg + 16, &c, 10); + if (opts.version > 2) die("bad %s", arg); if (*c == ',') - pack_idx_off32_limit = strtoul(c+1, &c, 0); - if (*c || pack_idx_off32_limit & 0x80000000) + opts.off32_limit = strtoul(c+1, &c, 0); + if (*c || opts.off32_limit & 0x80000000) die("bad %s", arg); } else usage(index_pack_usage); @@ -964,11 +1118,17 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) strcpy(keep_name_buf + len - 5, ".keep"); keep_name = keep_name_buf; } + if (verify) { + if (!index_name) + die("--verify with no packfile name given"); + read_idx_option(&opts, index_name); + opts.flags |= WRITE_IDX_VERIFY; + } curr_pack = open_pack_file(pack_name); parse_pack_header(); - objects = xmalloc((nr_objects + 1) * sizeof(struct object_entry)); - deltas = xmalloc(nr_objects * sizeof(struct delta_entry)); + objects = xcalloc(nr_objects + 1, sizeof(struct object_entry)); + deltas = xcalloc(nr_objects, sizeof(struct delta_entry)); parse_pack_objects(pack_sha1); if (nr_deltas == nr_resolved_deltas) { stop_progress(&progress); @@ -1008,16 +1168,22 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) if (strict) check_objects(); + if (stat) + show_pack_info(stat_only); + idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *)); for (i = 0; i < nr_objects; i++) idx_objects[i] = &objects[i].idx; - curr_index = write_idx_file(index_name, idx_objects, nr_objects, pack_sha1); + curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1); free(idx_objects); - final(pack_name, curr_pack, - index_name, curr_index, - keep_name, keep_msg, - pack_sha1); + if (!verify) + final(pack_name, curr_pack, + index_name, curr_index, + keep_name, keep_msg, + pack_sha1); + else + close(input_fd); free(objects); free(index_name_buf); free(keep_name_buf); diff --git a/builtin/init-db.c b/builtin/init-db.c index ba13a54793..025aa47c80 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -490,7 +490,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) "specify that the git repository is to be shared amongst several users", PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0}, OPT_BIT('q', "quiet", &flags, "be quiet", INIT_DB_QUIET), - OPT_STRING('L', "separate-git-dir", &real_git_dir, "gitdir", + OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir", "separate git dir from working tree"), OPT_END() }; diff --git a/builtin/log.c b/builtin/log.c index f6219909a7..5c2af59004 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -23,6 +23,7 @@ /* Set a default date-time format for git log ("log.date" config variable) */ static const char *default_date_mode = NULL; +static int default_abbrev_commit; static int default_show_root = 1; static int decoration_style; static int decoration_given; @@ -77,6 +78,7 @@ static void cmd_log_init_defaults(struct rev_info *rev) get_commit_format(fmt_pretty, rev); rev->verbose_header = 1; DIFF_OPT_SET(&rev->diffopt, RECURSIVE); + rev->abbrev_commit = default_abbrev_commit; rev->show_root_diff = default_show_root; rev->subject_prefix = fmt_patch_subject_prefix; DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV); @@ -92,7 +94,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, int quiet = 0, source = 0; const struct option builtin_log_options[] = { - OPT_BOOLEAN(0, "quiet", &quiet, "supress diff output"), + OPT_BOOLEAN(0, "quiet", &quiet, "suppress diff output"), OPT_BOOLEAN(0, "source", &source, "show source"), { OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options", PARSE_OPT_OPTARG, decorate_callback}, @@ -105,6 +107,8 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, PARSE_OPT_KEEP_DASHDASH); argc = setup_revisions(argc, argv, rev, opt); + if (quiet) + rev->diffopt.output_format |= DIFF_FORMAT_NO_OUTPUT; /* Any arguments at this point are not recognized */ if (argc > 1) @@ -129,13 +133,16 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, if (source) rev->show_source = 1; - /* - * defeat log.decorate configuration interacting with --pretty=raw - * from the command line. - */ - if (!decoration_given && rev->pretty_given - && rev->commit_format == CMIT_FMT_RAW) - decoration_style = 0; + if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) { + /* + * "log --pretty=raw" is special; ignore UI oriented + * configuration variables such as decoration. + */ + if (!decoration_given) + decoration_style = 0; + if (!rev->abbrev_commit_given) + rev->abbrev_commit = 0; + } if (decoration_style) { rev->show_decorations = 1; @@ -323,6 +330,10 @@ static int git_log_config(const char *var, const char *value, void *cb) return git_config_string(&fmt_pretty, var, value); if (!strcmp(var, "format.subjectprefix")) return git_config_string(&fmt_patch_subject_prefix, var, value); + if (!strcmp(var, "log.abbrevcommit")) { + default_abbrev_commit = git_config_bool(var, value); + return 0; + } if (!strcmp(var, "log.date")) return git_config_string(&default_date_mode, var, value); if (!strcmp(var, "log.decorate")) { @@ -365,9 +376,11 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix) static void show_tagger(char *buf, int len, struct rev_info *rev) { struct strbuf out = STRBUF_INIT; + struct pretty_print_context pp = {0}; - pp_user_info("Tagger", rev->commit_format, &out, buf, rev->date_mode, - get_log_output_encoding()); + pp.fmt = rev->commit_format; + pp.date_mode = rev->date_mode; + pp_user_info(&pp, "Tagger", &out, buf, get_log_output_encoding()); printf("%s", out.buf); strbuf_release(&out); } @@ -516,11 +529,11 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix) init_revisions(&rev, prefix); init_reflog_walk(&rev.reflog_info); - rev.abbrev_commit = 1; rev.verbose_header = 1; memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; cmd_log_init_defaults(&rev); + rev.abbrev_commit = 1; rev.commit_format = CMIT_FMT_ONELINE; rev.use_terminator = 1; rev.always_show_header = 1; @@ -751,10 +764,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, int quiet) { const char *committer; - const char *subject_start = NULL; const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n"; const char *msg; - const char *extra_headers = rev->extra_headers; struct shortlog log; struct strbuf sb = STRBUF_INIT; int i; @@ -762,6 +773,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, struct diff_options opts; int need_8bit_cte = 0; struct commit *commit = NULL; + struct pretty_print_context pp = {0}; if (rev->commit_format != CMIT_FMT_EMAIL) die(_("Cover letter needs email format")); @@ -793,7 +805,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, free(commit); } - log_write_email_headers(rev, head, &subject_start, &extra_headers, + log_write_email_headers(rev, head, &pp.subject, &pp.after_subject, &need_8bit_cte); for (i = 0; !need_8bit_cte && i < nr; i++) @@ -801,11 +813,11 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, need_8bit_cte = 1; msg = body; - pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822, - encoding); - pp_title_line(CMIT_FMT_EMAIL, &msg, &sb, subject_start, extra_headers, - encoding, need_8bit_cte); - pp_remainder(CMIT_FMT_EMAIL, &msg, &sb, 0); + pp.fmt = CMIT_FMT_EMAIL; + pp.date_mode = DATE_RFC2822; + pp_user_info(&pp, NULL, &sb, committer, encoding); + pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte); + pp_remainder(&pp, &msg, &sb, 0); printf("%s\n", sb.buf); strbuf_release(&sb); @@ -1169,6 +1181,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) die (_("-n and -k are mutually exclusive.")); if (keep_subject && subject_prefix) die (_("--subject-prefix and -k are mutually exclusive.")); + rev.preserve_subject = keep_subject; argc = setup_revisions(argc, argv, &rev, &s_r_opt); if (argc > 1) @@ -1399,8 +1412,7 @@ static void print_commit(char sign, struct commit *commit, int verbose, find_unique_abbrev(commit->object.sha1, abbrev)); } else { struct strbuf buf = STRBUF_INIT; - struct pretty_print_context ctx = {0}; - pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx); + pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf); printf("%c %s %s\n", sign, find_unique_abbrev(commit->object.sha1, abbrev), buf.buf); diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 1a1ff87e8f..10223092a9 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -5,7 +5,7 @@ static const char ls_remote_usage[] = "git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>]\n" -" [-q|--quiet] [<repository> [<refs>...]]"; +" [-q|--quiet] [--exit-code] [<repository> [<refs>...]]"; /* * Is there one among the list of patterns that match the tail part @@ -35,6 +35,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) unsigned flags = 0; int get_url = 0; int quiet = 0; + int status = 0; const char *uploadpack = NULL; const char **pattern = NULL; @@ -74,6 +75,11 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) get_url = 1; continue; } + if (!strcmp("--exit-code", arg)) { + /* return this code if no refs are reported */ + status = 2; + continue; + } usage(ls_remote_usage); } dest = arg; @@ -121,6 +127,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) if (!tail_match(pattern, ref->name)) continue; printf("%s %s\n", sha1_to_hex(ref->old_sha1), ref->name); + status = 0; /* we found something */ } - return 0; + return status; } diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c index 71e6262a87..bfb32b7233 100644 --- a/builtin/mailinfo.c +++ b/builtin/mailinfo.c @@ -400,7 +400,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in) break; if (strbuf_getline(&continuation, in, '\n')) break; - continuation.buf[0] = '\n'; + continuation.buf[0] = ' '; strbuf_rtrim(&continuation); strbuf_addbuf(line, &continuation); } diff --git a/builtin/merge.c b/builtin/merge.c index 9661c8f425..325891edb6 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -339,13 +339,14 @@ static void squash_message(void) ctx.abbrev = rev.abbrev; ctx.date_mode = rev.date_mode; + ctx.fmt = rev.commit_format; strbuf_addstr(&out, "Squashed commit of the following:\n"); while ((commit = get_revision(&rev)) != NULL) { strbuf_addch(&out, '\n'); strbuf_addf(&out, "commit %s\n", sha1_to_hex(commit->object.sha1)); - pretty_print_commit(rev.commit_format, commit, &out, &ctx); + pretty_print_commit(&ctx, commit, &out); } if (write(fd, out.buf, out.len) < 0) die_errno(_("Writing SQUASH_MSG")); @@ -550,6 +551,15 @@ static int git_merge_config(const char *k, const char *v, void *cb) if (is_bool && shortlog_len) shortlog_len = DEFAULT_MERGE_LOG_LEN; return 0; + } else if (!strcmp(k, "merge.ff")) { + int boolval = git_config_maybe_bool(k, v); + if (0 <= boolval) { + allow_fast_forward = boolval; + } else if (v && !strcmp(v, "only")) { + allow_fast_forward = 1; + fast_forward_only = 1; + } /* do not barf on values from future versions of git */ + return 0; } else if (!strcmp(k, "merge.defaulttoupstream")) { default_to_upstream = git_config_bool(k, v); return 0; @@ -599,6 +609,14 @@ static void write_tree_trivial(unsigned char *sha1) die(_("git write-tree failed to write a tree")); } +static const char *merge_argument(struct commit *commit) +{ + if (commit) + return sha1_to_hex(commit->object.sha1); + else + return EMPTY_TREE_SHA1_HEX; +} + int try_merge_command(const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes) @@ -619,11 +637,11 @@ int try_merge_command(const char *strategy, size_t xopts_nr, args[i++] = s; } for (j = common; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i++] = xstrdup(merge_argument(j->item)); args[i++] = "--"; args[i++] = head_arg; for (j = remotes; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i++] = xstrdup(merge_argument(j->item)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); diff --git a/builtin/notes.c b/builtin/notes.c index 1fb1f73439..f8e437db01 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -29,7 +29,7 @@ static const char * const git_notes_usage[] = { "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>", "git notes merge --commit [-v | -q]", "git notes merge --abort [-v | -q]", - "git notes [--ref <notes_ref>] remove [<object>]", + "git notes [--ref <notes_ref>] remove [<object>...]", "git notes [--ref <notes_ref>] prune [-n | -v]", "git notes [--ref <notes_ref>] get-ref", NULL @@ -953,40 +953,60 @@ static int merge(int argc, const char **argv, const char *prefix) return result < 0; /* return non-zero on conflicts */ } +#define IGNORE_MISSING 1 + +static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag) +{ + int status; + unsigned char sha1[20]; + if (get_sha1(name, sha1)) + return error(_("Failed to resolve '%s' as a valid ref."), name); + status = remove_note(t, sha1); + if (status) + fprintf(stderr, _("Object %s has no note\n"), name); + else + fprintf(stderr, _("Removing note for object %s\n"), name); + return (flag & IGNORE_MISSING) ? 0 : status; +} + static int remove_cmd(int argc, const char **argv, const char *prefix) { + unsigned flag = 0; + int from_stdin = 0; struct option options[] = { + OPT_BIT(0, "ignore-missing", &flag, + "attempt to remove non-existent note is not an error", + IGNORE_MISSING), + OPT_BOOLEAN(0, "stdin", &from_stdin, + "read object names from the standard input"), OPT_END() }; - const char *object_ref; struct notes_tree *t; - unsigned char object[20]; - int retval; + int retval = 0; argc = parse_options(argc, argv, prefix, options, git_notes_remove_usage, 0); - if (1 < argc) { - error(_("too many parameters")); - usage_with_options(git_notes_remove_usage, options); - } - - object_ref = argc ? argv[0] : "HEAD"; - - if (get_sha1(object_ref, object)) - die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check("remove"); - retval = remove_note(t, object); - if (retval) - fprintf(stderr, _("Object %s has no note\n"), sha1_to_hex(object)); - else { - fprintf(stderr, _("Removing note for object %s\n"), - sha1_to_hex(object)); - - commit_notes(t, "Notes removed by 'git notes remove'"); + if (!argc && !from_stdin) { + retval = remove_one_note(t, "HEAD", flag); + } else { + while (*argv) { + retval |= remove_one_note(t, *argv, flag); + argv++; + } } + if (from_stdin) { + struct strbuf sb = STRBUF_INIT; + while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) { + strbuf_rtrim(&sb); + retval |= remove_one_note(t, sb.buf, flag); + } + strbuf_release(&sb); + } + if (!retval) + commit_notes(t, "Notes removed by 'git notes remove'"); free_notes(t); return retval; } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index f402a843bb..84e6dafb12 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -70,6 +70,7 @@ static int local; static int incremental; static int ignore_packed_keep; static int allow_ofs_delta; +static struct pack_idx_option pack_idx_opts; static const char *base_name; static int progress = 1; static int window = 10; @@ -126,13 +127,13 @@ static void *get_delta(struct object_entry *entry) static unsigned long do_compress(void **pptr, unsigned long size) { - z_stream stream; + git_zstream stream; void *in, *out; unsigned long maxsize; memset(&stream, 0, sizeof(stream)); - deflateInit(&stream, pack_compression_level); - maxsize = deflateBound(&stream, size); + git_deflate_init(&stream, pack_compression_level); + maxsize = git_deflate_bound(&stream, size); in = *pptr; out = xmalloc(maxsize); @@ -142,9 +143,9 @@ static unsigned long do_compress(void **pptr, unsigned long size) stream.avail_in = size; stream.next_out = out; stream.avail_out = maxsize; - while (deflate(&stream, Z_FINISH) == Z_OK) + while (git_deflate(&stream, Z_FINISH) == Z_OK) ; /* nothing */ - deflateEnd(&stream); + git_deflate_end(&stream); free(in); return stream.total_out; @@ -160,7 +161,7 @@ static int check_pack_inflate(struct packed_git *p, off_t len, unsigned long expect) { - z_stream stream; + git_zstream stream; unsigned char fakebuf[4096], *in; int st; @@ -187,12 +188,12 @@ static void copy_pack_data(struct sha1file *f, off_t len) { unsigned char *in; - unsigned int avail; + unsigned long avail; while (len) { in = use_pack(p, w_curs, offset, &avail); if (avail > len) - avail = (unsigned int)len; + avail = (unsigned long)len; sha1write(f, in, avail); offset += avail; len -= avail; @@ -493,8 +494,8 @@ static void write_pack_file(void) const char *idx_tmp_name; char tmpname[PATH_MAX]; - idx_tmp_name = write_idx_file(NULL, written_list, - nr_written, sha1); + idx_tmp_name = write_idx_file(NULL, written_list, nr_written, + &pack_idx_opts, sha1); snprintf(tmpname, sizeof(tmpname), "%s-%s.pack", base_name, sha1_to_hex(sha1)); @@ -994,7 +995,7 @@ static void check_object(struct object_entry *entry) const unsigned char *base_ref = NULL; struct object_entry *base_entry; unsigned long used, used_0; - unsigned int avail; + unsigned long avail; off_t ofs; unsigned char *buf, c; @@ -1884,10 +1885,10 @@ static int git_pack_config(const char *k, const char *v, void *cb) return 0; } if (!strcmp(k, "pack.indexversion")) { - pack_idx_default_version = git_config_int(k, v); - if (pack_idx_default_version > 2) + pack_idx_opts.version = git_config_int(k, v); + if (pack_idx_opts.version > 2) die("bad pack.indexversion=%"PRIu32, - pack_idx_default_version); + pack_idx_opts.version); return 0; } if (!strcmp(k, "pack.packsizelimit")) { @@ -2134,6 +2135,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) rp_av[1] = "--objects"; /* --thin will make it --objects-edge */ rp_ac = 2; + reset_pack_idx_option(&pack_idx_opts); git_config(git_pack_config, NULL); if (!pack_compression_seen && core_compression_seen) pack_compression_level = core_compression_level; @@ -2278,12 +2280,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) } if (!prefixcmp(arg, "--index-version=")) { char *c; - pack_idx_default_version = strtoul(arg + 16, &c, 10); - if (pack_idx_default_version > 2) + pack_idx_opts.version = strtoul(arg + 16, &c, 10); + if (pack_idx_opts.version > 2) die("bad %s", arg); if (*c == ',') - pack_idx_off32_limit = strtoul(c+1, &c, 0); - if (*c || pack_idx_off32_limit & 0x80000000) + pack_idx_opts.off32_limit = strtoul(c+1, &c, 0); + if (*c || pack_idx_opts.off32_limit & 0x80000000) die("bad %s", arg); continue; } diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 93c92814cf..df6c4c8819 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -130,6 +130,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) PARSE_OPT_NONEG, exclude_per_directory_cb }, OPT_SET_INT('i', NULL, &opts.index_only, "don't check the working tree after merging", 1), + OPT__DRY_RUN(&opts.dry_run, "don't update the index or the work tree"), OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout, "skip applying sparse checkout filter", 1), OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack, @@ -219,7 +220,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) if (unpack_trees(nr_trees, t, &opts)) return 128; - if (opts.debug_unpack) + if (opts.debug_unpack || opts.dry_run) return 0; /* do not write the index out */ /* diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e1ba4dc697..e1a687ad07 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -10,6 +10,7 @@ #include "remote.h" #include "transport.h" #include "string-list.h" +#include "sha1-array.h" static const char receive_pack_usage[] = "git receive-pack <git-dir>"; @@ -731,14 +732,23 @@ static int delete_only(struct command *commands) return 1; } -static void add_one_alternate_ref(const struct ref *ref, void *unused) +static void add_one_alternate_sha1(const unsigned char sha1[20], void *unused) { - add_extra_ref(".have", ref->old_sha1, 0); + add_extra_ref(".have", sha1, 0); +} + +static void collect_one_alternate_ref(const struct ref *ref, void *data) +{ + struct sha1_array *sa = data; + sha1_array_append(sa, ref->old_sha1); } static void add_alternate_refs(void) { - foreach_alt_odb(refs_from_alternate_cb, add_one_alternate_ref); + struct sha1_array sa = SHA1_ARRAY_INIT; + for_each_alternate_ref(collect_one_alternate_ref, &sa); + sha1_array_for_each_unique(&sa, add_one_alternate_sha1, NULL); + sha1_array_clear(&sa); } int cmd_receive_pack(int argc, const char **argv, const char *prefix) diff --git a/builtin/remote.c b/builtin/remote.c index 8424152269..05b1f5b76d 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -88,16 +88,6 @@ static inline int postfixcmp(const char *string, const char *postfix) return strcmp(string + len1 - len2, postfix); } -static int opt_parse_track(const struct option *opt, const char *arg, int not) -{ - struct string_list *list = opt->value; - if (not) - string_list_clear(list, 0); - else - string_list_append(list, arg); - return 0; -} - static int fetch_remote(const char *name) { const char *argv[] = { "fetch", name, NULL, NULL }; @@ -176,8 +166,8 @@ static int add(int argc, const char **argv) TAGS_SET), OPT_SET_INT(0, NULL, &fetch_tags, "or do not fetch any tag at all (--no-tags)", TAGS_UNSET), - OPT_CALLBACK('t', "track", &track, "branch", - "branch(es) to track", opt_parse_track), + OPT_STRING_LIST('t', "track", &track, "branch", + "branch(es) to track"), OPT_STRING('m', "master", &master, "branch", "master branch"), { OPTION_CALLBACK, 0, "mirror", &mirror, "push|fetch", "set up remote as a mirror to push to or fetch from", @@ -193,8 +183,8 @@ static int add(int argc, const char **argv) if (mirror && master) die("specifying a master branch makes no sense with --mirror"); - if (mirror && track.nr) - die("specifying branches to track makes no sense with --mirror"); + if (mirror && !(mirror & MIRROR_FETCH) && track.nr) + die("specifying branches to track makes sense only with fetch mirrors"); name = argv[0]; url = argv[1]; diff --git a/builtin/reset.c b/builtin/reset.c index 98bca044c1..777e7c6129 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -162,7 +162,7 @@ static void update_index_from_diff(struct diff_queue_struct *q, for (i = 0; i < q->nr; i++) { struct diff_filespec *one = q->queue[i]->one; - if (one->mode) { + if (one->mode && !is_null_sha1(one->sha1)) { struct cache_entry *ce; ce = make_cache_entry(one->mode, one->sha1, one->path, 0, 0); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 4be66998f6..56727e8c1d 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -104,7 +104,8 @@ static void show_commit(struct commit *commit, void *data) struct pretty_print_context ctx = {0}; ctx.abbrev = revs->abbrev; ctx.date_mode = revs->date_mode; - pretty_print_commit(revs->commit_format, commit, &buf, &ctx); + ctx.fmt = revs->commit_format; + pretty_print_commit(&ctx, commit, &buf); if (revs->graph) { if (buf.len) { if (revs->commit_format != CMIT_FMT_ONELINE) diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index adb1cae4f2..4c19f844a9 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -44,6 +44,7 @@ static int is_rev_argument(const char *arg) "--branches=", "--branches", "--header", + "--ignore-missing", "--max-age=", "--max-count=", "--min-age=", diff --git a/builtin/revert.c b/builtin/revert.c index f697e66953..1f27c63343 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -408,8 +408,6 @@ static int do_pick_commit(void) discard_cache(); if (!commit->parents) { - if (action == REVERT) - die (_("Cannot revert a root commit")); parent = NULL; } else if (commit->parents->next) { @@ -467,7 +465,7 @@ static int do_pick_commit(void) strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit "); strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1)); - if (commit->parents->next) { + if (commit->parents && commit->parents->next) { strbuf_addstr(&msgbuf, ", reversing\nchanges made to "); strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1)); } diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 4ac2ca984f..c1f6ddd927 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -228,11 +228,11 @@ static void print_helper_status(struct ref *ref) static int sideband_demux(int in, int out, void *data) { - int *fd = data; + int *fd = data, ret; #ifdef NO_PTHREADS close(fd[1]); #endif - int ret = recv_sideband("send-pack", fd[0], out); + ret = recv_sideband("send-pack", fd[0], out); close(out); return ret; } @@ -344,6 +344,8 @@ int send_pack(struct send_pack_args *args, ref->status = REF_STATUS_NONE; if (args->stateless_rpc) close(out); + if (git_connection_is_socket(conn)) + shutdown(fd[0], SHUT_WR); if (use_sideband) finish_async(&demux); return -1; diff --git a/builtin/shortlog.c b/builtin/shortlog.c index b6f4b0eb03..37f3193a33 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -138,9 +138,8 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) const char *author = NULL, *buffer; struct strbuf buf = STRBUF_INIT; struct strbuf ufbuf = STRBUF_INIT; - struct pretty_print_context ctx = {0}; - pretty_print_commit(CMIT_FMT_RAW, commit, &buf, &ctx); + pp_commit_easy(CMIT_FMT_RAW, commit, &buf); buffer = buf.buf; while (*buffer && *buffer != '\n') { const char *eol = strchr(buffer, '\n'); @@ -159,11 +158,12 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) sha1_to_hex(commit->object.sha1)); if (log->user_format) { struct pretty_print_context ctx = {0}; + ctx.fmt = CMIT_FMT_USERFORMAT; ctx.abbrev = log->abbrev; ctx.subject = ""; ctx.after_subject = ""; ctx.date_mode = DATE_NORMAL; - pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &ufbuf, &ctx); + pretty_print_commit(&ctx, commit, &ufbuf); buffer = ufbuf.buf; } else if (*buffer) { buffer++; diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 1abcd9e02e..facc63a79e 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -283,8 +283,7 @@ static void show_one_commit(struct commit *commit, int no_name) struct commit_name *name = commit->util; if (commit->object.parsed) { - struct pretty_print_context ctx = {0}; - pretty_print_commit(CMIT_FMT_ONELINE, commit, &pretty, &ctx); + pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty); pretty_str = pretty.buf; } if (!prefixcmp(pretty_str, "[PATCH] ")) diff --git a/builtin/tag.c b/builtin/tag.c index b66b34a182..667515e527 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -12,11 +12,13 @@ #include "tag.h" #include "run-command.h" #include "parse-options.h" +#include "diff.h" +#include "revision.h" static const char * const git_tag_usage[] = { "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]", "git tag -d <tagname>...", - "git tag -l [-n[<num>]] [<pattern>]", + "git tag -l [-n[<num>]] [<pattern>...]", "git tag -v <tagname>...", NULL }; @@ -24,17 +26,70 @@ static const char * const git_tag_usage[] = { static char signingkey[1000]; struct tag_filter { - const char *pattern; + const char **patterns; int lines; struct commit_list *with_commit; }; +static int match_pattern(const char **patterns, const char *ref) +{ + /* no pattern means match everything */ + if (!*patterns) + return 1; + for (; *patterns; patterns++) + if (!fnmatch(*patterns, ref, 0)) + return 1; + return 0; +} + +static int in_commit_list(const struct commit_list *want, struct commit *c) +{ + for (; want; want = want->next) + if (!hashcmp(want->item->object.sha1, c->object.sha1)) + return 1; + return 0; +} + +static int contains_recurse(struct commit *candidate, + const struct commit_list *want) +{ + struct commit_list *p; + + /* was it previously marked as containing a want commit? */ + if (candidate->object.flags & TMP_MARK) + return 1; + /* or marked as not possibly containing a want commit? */ + if (candidate->object.flags & UNINTERESTING) + return 0; + /* or are we it? */ + if (in_commit_list(want, candidate)) + return 1; + + if (parse_commit(candidate) < 0) + return 0; + + /* Otherwise recurse and mark ourselves for future traversals. */ + for (p = candidate->parents; p; p = p->next) { + if (contains_recurse(p->item, want)) { + candidate->object.flags |= TMP_MARK; + return 1; + } + } + candidate->object.flags |= UNINTERESTING; + return 0; +} + +static int contains(struct commit *candidate, const struct commit_list *want) +{ + return contains_recurse(candidate, want); +} + static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct tag_filter *filter = cb_data; - if (!fnmatch(filter->pattern, refname, 0)) { + if (match_pattern(filter->patterns, refname)) { int i; unsigned long size; enum object_type type; @@ -47,7 +102,7 @@ static int show_reference(const char *refname, const unsigned char *sha1, commit = lookup_commit_reference_gently(sha1, 1); if (!commit) return 0; - if (!is_descendant_of(commit, filter->with_commit)) + if (!contains(commit, filter->with_commit)) return 0; } @@ -88,15 +143,12 @@ static int show_reference(const char *refname, const unsigned char *sha1, return 0; } -static int list_tags(const char *pattern, int lines, +static int list_tags(const char **patterns, int lines, struct commit_list *with_commit) { struct tag_filter filter; - if (pattern == NULL) - pattern = "*"; - - filter.pattern = pattern; + filter.patterns = patterns; filter.lines = lines; filter.with_commit = with_commit; @@ -352,11 +404,22 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset) return 0; } +static int strbuf_check_tag_ref(struct strbuf *sb, const char *name) +{ + if (name[0] == '-') + return CHECK_REF_FORMAT_ERROR; + + strbuf_reset(sb); + strbuf_addf(sb, "refs/tags/%s", name); + + return check_ref_format(sb->buf); +} + int cmd_tag(int argc, const char **argv, const char *prefix) { struct strbuf buf = STRBUF_INIT; + struct strbuf ref = STRBUF_INIT; unsigned char object[20], prev[20]; - char ref[PATH_MAX]; const char *object_ref, *tag; struct ref_lock *lock; @@ -414,7 +477,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (list + delete + verify > 1) usage_with_options(git_tag_usage, options); if (list) - return list_tags(argv[0], lines == -1 ? 0 : lines, + return list_tags(argv, lines == -1 ? 0 : lines, with_commit); if (lines != -1) die(_("-n option is only allowed with -l.")); @@ -452,12 +515,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - if (snprintf(ref, sizeof(ref), "refs/tags/%s", tag) > sizeof(ref) - 1) - die(_("tag name too long: %.*s..."), 50, tag); - if (check_ref_format(ref)) + if (strbuf_check_tag_ref(&ref, tag)) die(_("'%s' is not a valid tag name."), tag); - if (!resolve_ref(ref, prev, 1, NULL)) + if (!resolve_ref(ref.buf, prev, 1, NULL)) hashclr(prev); else if (!force) die(_("tag '%s' already exists"), tag); @@ -466,14 +527,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix) create_tag(object, tag, &buf, msg.given || msgfile, sign, prev, object); - lock = lock_any_ref_for_update(ref, prev, 0); + lock = lock_any_ref_for_update(ref.buf, prev, 0); if (!lock) - die(_("%s: cannot lock the ref"), ref); + die(_("%s: cannot lock the ref"), ref.buf); if (write_ref_sha1(lock, object, NULL) < 0) - die(_("%s: cannot update the ref"), ref); + die(_("%s: cannot update the ref"), ref.buf); if (force && hashcmp(prev, object)) printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV)); strbuf_release(&buf); + strbuf_release(&ref); return 0; } diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index f63973c914..14e04e6795 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -90,7 +90,7 @@ static void use(int bytes) static void *get_data(unsigned long size) { - z_stream stream; + git_zstream stream; void *buf = xmalloc(size); memset(&stream, 0, sizeof(stream)); diff --git a/builtin/update-index.c b/builtin/update-index.c index f14bc90830..a6a23fa1f3 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -100,8 +100,10 @@ static int add_one_path(struct cache_entry *old, const char *path, int len, stru ce->ce_mode = ce_mode_from_stat(old, st->st_mode); if (index_path(ce->sha1, path, st, - info_only ? 0 : HASH_WRITE_OBJECT)) + info_only ? 0 : HASH_WRITE_OBJECT)) { + free(ce); return -1; + } option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; if (add_cache_entry(ce, option)) diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c index 73f788ef24..2d0b38333e 100644 --- a/builtin/upload-archive.c +++ b/builtin/upload-archive.c @@ -64,7 +64,7 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix) sent_argv[sent_argc] = NULL; /* parse all options sent by the client */ - return write_archive(sent_argc, sent_argv, prefix, 0); + return write_archive(sent_argc, sent_argv, prefix, 0, NULL, 1); } __attribute__((format (printf, 1, 2))) diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c index 3a919b1707..e841b4a38d 100644 --- a/builtin/verify-pack.c +++ b/builtin/verify-pack.c @@ -1,134 +1,53 @@ #include "builtin.h" #include "cache.h" -#include "pack.h" -#include "pack-revindex.h" +#include "run-command.h" #include "parse-options.h" -#define MAX_CHAIN 50 - #define VERIFY_PACK_VERBOSE 01 #define VERIFY_PACK_STAT_ONLY 02 -static void show_pack_info(struct packed_git *p, unsigned int flags) -{ - uint32_t nr_objects, i; - int cnt; - int stat_only = flags & VERIFY_PACK_STAT_ONLY; - unsigned long chain_histogram[MAX_CHAIN+1], baseobjects; - - nr_objects = p->num_objects; - memset(chain_histogram, 0, sizeof(chain_histogram)); - baseobjects = 0; - - for (i = 0; i < nr_objects; i++) { - const unsigned char *sha1; - unsigned char base_sha1[20]; - const char *type; - unsigned long size; - unsigned long store_size; - off_t offset; - unsigned int delta_chain_length; - - sha1 = nth_packed_object_sha1(p, i); - if (!sha1) - die("internal error pack-check nth-packed-object"); - offset = nth_packed_object_offset(p, i); - type = typename(packed_object_info_detail(p, offset, &size, &store_size, - &delta_chain_length, - base_sha1)); - if (!stat_only) - printf("%s ", sha1_to_hex(sha1)); - if (!delta_chain_length) { - if (!stat_only) - printf("%-6s %lu %lu %"PRIuMAX"\n", - type, size, store_size, (uintmax_t)offset); - baseobjects++; - } - else { - if (!stat_only) - printf("%-6s %lu %lu %"PRIuMAX" %u %s\n", - type, size, store_size, (uintmax_t)offset, - delta_chain_length, sha1_to_hex(base_sha1)); - if (delta_chain_length <= MAX_CHAIN) - chain_histogram[delta_chain_length]++; - else - chain_histogram[0]++; - } - } - - if (baseobjects) - printf("non delta: %lu object%s\n", - baseobjects, baseobjects > 1 ? "s" : ""); - - for (cnt = 1; cnt <= MAX_CHAIN; cnt++) { - if (!chain_histogram[cnt]) - continue; - printf("chain length = %d: %lu object%s\n", cnt, - chain_histogram[cnt], - chain_histogram[cnt] > 1 ? "s" : ""); - } - if (chain_histogram[0]) - printf("chain length > %d: %lu object%s\n", MAX_CHAIN, - chain_histogram[0], - chain_histogram[0] > 1 ? "s" : ""); -} - static int verify_one_pack(const char *path, unsigned int flags) { - char arg[PATH_MAX]; - int len; + struct child_process index_pack; + const char *argv[] = {"index-pack", NULL, NULL, NULL }; + struct strbuf arg = STRBUF_INIT; int verbose = flags & VERIFY_PACK_VERBOSE; int stat_only = flags & VERIFY_PACK_STAT_ONLY; - struct packed_git *pack; int err; - len = strlcpy(arg, path, PATH_MAX); - if (len >= PATH_MAX) - return error("name too long: %s", path); - - /* - * In addition to "foo.idx" we accept "foo.pack" and "foo"; - * normalize these forms to "foo.idx" for add_packed_git(). - */ - if (has_extension(arg, ".pack")) { - strcpy(arg + len - 5, ".idx"); - len--; - } else if (!has_extension(arg, ".idx")) { - if (len + 4 >= PATH_MAX) - return error("name too long: %s.idx", arg); - strcpy(arg + len, ".idx"); - len += 4; - } + if (stat_only) + argv[1] = "--verify-stat-only"; + else if (verbose) + argv[1] = "--verify-stat"; + else + argv[1] = "--verify"; /* - * add_packed_git() uses our buffer (containing "foo.idx") to - * build the pack filename ("foo.pack"). Make sure it fits. + * In addition to "foo.pack" we accept "foo.idx" and "foo"; + * normalize these forms to "foo.pack" for "index-pack --verify". */ - if (len + 1 >= PATH_MAX) { - arg[len - 4] = '\0'; - return error("name too long: %s.pack", arg); - } - - pack = add_packed_git(arg, len, 1); - if (!pack) - return error("packfile %s not found.", arg); + strbuf_addstr(&arg, path); + if (has_extension(arg.buf, ".idx")) + strbuf_splice(&arg, arg.len - 3, 3, "pack", 4); + else if (!has_extension(arg.buf, ".pack")) + strbuf_add(&arg, ".pack", 5); + argv[2] = arg.buf; - install_packed_git(pack); + memset(&index_pack, 0, sizeof(index_pack)); + index_pack.argv = argv; + index_pack.git_cmd = 1; - if (!stat_only) - err = verify_pack(pack); - else - err = open_pack_index(pack); + err = run_command(&index_pack); if (verbose || stat_only) { if (err) - printf("%s: bad\n", pack->pack_name); + printf("%s: bad\n", arg.buf); else { - show_pack_info(pack, flags); if (!stat_only) - printf("%s: ok\n", pack->pack_name); + printf("%s: ok\n", arg.buf); } } + strbuf_release(&arg); return err; } @@ -159,7 +78,6 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix) for (i = 0; i < argc; i++) { if (verify_one_pack(argv[i], flags)) err = 1; - discard_revindex(); } return err; |
