diff options
Diffstat (limited to 'builtin')
34 files changed, 758 insertions, 323 deletions
diff --git a/builtin/add.c b/builtin/add.c index 87d298031..17149cfee 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -261,12 +261,14 @@ static int edit_patch(int argc, const char **argv, const char *prefix) { char *file = xstrdup(git_path("ADD_EDIT.patch")); const char *apply_argv[] = { "apply", "--recount", "--cached", - file, NULL }; + NULL, NULL }; struct child_process child; struct rev_info rev; int out; struct stat st; + apply_argv[3] = file; + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ if (read_cache() < 0) diff --git a/builtin/apply.c b/builtin/apply.c index 8fc5ec31d..12ef9ea8a 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -56,7 +56,7 @@ static enum ws_error_action { nowarn_ws_error, warn_on_ws_error, die_on_ws_error, - correct_ws_error, + correct_ws_error } ws_error_action = warn_on_ws_error; static int whitespace_error; static int squelch_whitespace_errors = 5; @@ -64,7 +64,7 @@ static int applied_after_fixing_ws; static enum ws_ignore { ignore_ws_none, - ignore_ws_change, + ignore_ws_change } ws_ignore_action = ignore_ws_none; @@ -2628,7 +2628,7 @@ static struct patch *in_fn_table(const char *name) if (name == NULL) return NULL; - item = string_list_lookup(name, &fn_table); + item = string_list_lookup(&fn_table, name); if (item != NULL) return (struct patch *)item->util; @@ -2664,7 +2664,7 @@ static void add_to_fn_table(struct patch *patch) * file creations and copies */ if (patch->new_name != NULL) { - item = string_list_insert(patch->new_name, &fn_table); + item = string_list_insert(&fn_table, patch->new_name); item->util = patch; } @@ -2673,7 +2673,7 @@ static void add_to_fn_table(struct patch *patch) * later chunks shouldn't patch old names */ if ((patch->new_name == NULL) || (patch->is_rename)) { - item = string_list_insert(patch->old_name, &fn_table); + item = string_list_insert(&fn_table, patch->old_name); item->util = PATH_WAS_DELETED; } } @@ -2686,7 +2686,7 @@ static void prepare_fn_table(struct patch *patch) while (patch) { if ((patch->new_name == NULL) || (patch->is_rename)) { struct string_list_item *item; - item = string_list_insert(patch->old_name, &fn_table); + item = string_list_insert(&fn_table, patch->old_name); item->util = PATH_TO_BE_DELETED; } patch = patch->next; @@ -3394,7 +3394,7 @@ static void add_name_limit(const char *name, int exclude) { struct string_list_item *it; - it = string_list_append(name, &limit_by_name); + it = string_list_append(&limit_by_name, name); it->util = exclude ? NULL : (void *) 1; } diff --git a/builtin/blame.c b/builtin/blame.c index fc1586350..01e62fdeb 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -20,6 +20,7 @@ #include "mailmap.h" #include "parse-options.h" #include "utf8.h" +#include "userdiff.h" static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file"; @@ -39,7 +40,7 @@ static int show_root; static int reverse; static int blank_boundary; static int incremental; -static int xdl_opts = XDF_NEED_MINIMAL; +static int xdl_opts; static enum date_mode blame_date_mode = DATE_ISO8601; static size_t blame_date_width; @@ -86,16 +87,50 @@ struct origin { }; /* + * Prepare diff_filespec and convert it using diff textconv API + * if the textconv driver exists. + * Return 1 if the conversion succeeds, 0 otherwise. + */ +int textconv_object(const char *path, + const unsigned char *sha1, + char **buf, + unsigned long *buf_size) +{ + struct diff_filespec *df; + struct userdiff_driver *textconv; + + df = alloc_filespec(path); + fill_filespec(df, sha1, S_IFREG | 0664); + textconv = get_textconv(df); + if (!textconv) { + free_filespec(df); + return 0; + } + + *buf_size = fill_textconv(textconv, df, buf); + free_filespec(df); + return 1; +} + +/* * Given an origin, prepare mmfile_t structure to be used by the * diff machinery */ -static void fill_origin_blob(struct origin *o, mmfile_t *file) +static void fill_origin_blob(struct diff_options *opt, + struct origin *o, mmfile_t *file) { if (!o->file.ptr) { enum object_type type; + unsigned long file_size; + num_read_blob++; - file->ptr = read_sha1_file(o->blob_sha1, &type, - (unsigned long *)(&(file->size))); + if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && + textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size)) + ; + else + file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size); + file->size = file_size; + if (!file->ptr) die("Cannot read blob %s for path %s", sha1_to_hex(o->blob_sha1), @@ -282,7 +317,6 @@ static struct origin *get_origin(struct scoreboard *sb, static int fill_blob_sha1(struct origin *origin) { unsigned mode; - if (!is_null_sha1(origin->blob_sha1)) return 0; if (get_tree_entry(origin->commit->object.sha1, @@ -733,16 +767,17 @@ static int pass_blame_to_parent(struct scoreboard *sb, { int last_in_target; mmfile_t file_p, file_o; - struct blame_chunk_cb_data d = { sb, target, parent, 0, 0 }; + struct blame_chunk_cb_data d; xpparam_t xpp; xdemitconf_t xecfg; - + memset(&d, 0, sizeof(d)); + d.sb = sb; d.target = target; d.parent = parent; last_in_target = find_last_in_target(sb, target); if (last_in_target < 0) return 1; /* nothing remains for this target */ - fill_origin_blob(parent, &file_p); - fill_origin_blob(target, &file_o); + fill_origin_blob(&sb->revs->diffopt, parent, &file_p); + fill_origin_blob(&sb->revs->diffopt, target, &file_o); num_get_patch++; memset(&xpp, 0, sizeof(xpp)); @@ -875,10 +910,11 @@ static void find_copy_in_blob(struct scoreboard *sb, const char *cp; int cnt; mmfile_t file_o; - struct handle_split_cb_data d = { sb, ent, parent, split, 0, 0 }; + struct handle_split_cb_data d; xpparam_t xpp; xdemitconf_t xecfg; - + memset(&d, 0, sizeof(d)); + d.sb = sb; d.ent = ent; d.parent = parent; d.split = split; /* * Prepare mmfile that contains only the lines in ent. */ @@ -922,7 +958,7 @@ static int find_move_in_parent(struct scoreboard *sb, if (last_in_target < 0) return 1; /* nothing remains for this target */ - fill_origin_blob(parent, &file_p); + fill_origin_blob(&sb->revs->diffopt, parent, &file_p); if (!file_p.ptr) return 0; @@ -1063,7 +1099,7 @@ static int find_copy_in_parent(struct scoreboard *sb, norigin = get_origin(sb, parent, p->one->path); hashcpy(norigin->blob_sha1, p->one->sha1); - fill_origin_blob(norigin, &file_p); + fill_origin_blob(&sb->revs->diffopt, norigin, &file_p); if (!file_p.ptr) continue; @@ -1589,7 +1625,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) strcpy(hex, sha1_to_hex(suspect->commit->object.sha1)); printf("%s%c%d %d %d\n", hex, - ent->guilty ? ' ' : '*', // purely for debugging + ent->guilty ? ' ' : '*', /* purely for debugging */ ent->s_lno + 1, ent->lno + 1, ent->num_lines); @@ -1983,6 +2019,16 @@ static int git_blame_config(const char *var, const char *value, void *cb) blame_date_mode = parse_date_format(value); return 0; } + + switch (userdiff_config(var, value)) { + case 0: + break; + case -1: + return -1; + default: + return 0; + } + return git_default_config(var, value, cb); } @@ -1990,7 +2036,9 @@ static int git_blame_config(const char *var, const char *value, void *cb) * Prepare a dummy commit that represents the work tree (or staged) item. * Note that annotating work tree item never works in the reverse. */ -static struct commit *fake_working_tree_commit(const char *path, const char *contents_from) +static struct commit *fake_working_tree_commit(struct diff_options *opt, + const char *path, + const char *contents_from) { struct commit *commit; struct origin *origin; @@ -2018,6 +2066,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con if (!contents_from || strcmp("-", contents_from)) { struct stat st; const char *read_from; + unsigned long buf_len; if (contents_from) { if (stat(contents_from, &st) < 0) @@ -2030,9 +2079,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con read_from = path; } mode = canon_mode(st.st_mode); + switch (st.st_mode & S_IFMT) { case S_IFREG: - if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) + if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && + textconv_object(read_from, null_sha1, &buf.buf, &buf_len)) + buf.len = buf_len; + else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) die_errno("cannot open or read '%s'", read_from); break; case S_IFLNK: @@ -2248,6 +2301,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) git_config(git_blame_config, NULL); init_revisions(&revs, NULL); revs.date_mode = blame_date_mode; + DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV); save_commit_buffer = 0; dashdash_pos = 0; @@ -2384,7 +2438,8 @@ parse_done: * or "--contents". */ setup_work_tree(); - sb.final = fake_working_tree_commit(path, contents_from); + sb.final = fake_working_tree_commit(&sb.revs->diffopt, + path, contents_from); add_pending_object(&revs, &(sb.final->object), ":"); } else if (contents_from) @@ -2411,8 +2466,14 @@ parse_done: if (fill_blob_sha1(o)) die("no such path %s in %s", path, final_commit_name); - sb.final_buf = read_sha1_file(o->blob_sha1, &type, - &sb.final_buf_size); + if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) && + textconv_object(path, o->blob_sha1, (char **) &sb.final_buf, + &sb.final_buf_size)) + ; + else + sb.final_buf = read_sha1_file(o->blob_sha1, &type, + &sb.final_buf_size); + if (!sb.final_buf) die("Cannot read blob %s for path %s", sha1_to_hex(o->blob_sha1), diff --git a/builtin/branch.c b/builtin/branch.c index 6cf7e721e..87976f092 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -43,13 +43,13 @@ enum color_branch { BRANCH_COLOR_PLAIN = 1, BRANCH_COLOR_REMOTE = 2, BRANCH_COLOR_LOCAL = 3, - BRANCH_COLOR_CURRENT = 4, + BRANCH_COLOR_CURRENT = 4 }; static enum merge_filter { NO_FILTER = 0, SHOW_NOT_MERGED, - SHOW_MERGED, + SHOW_MERGED } merge_filter; static unsigned char merge_filter_ref[20]; @@ -257,9 +257,15 @@ static char *resolve_symref(const char *src, const char *prefix) return xstrdup(dst); } +struct append_ref_cb { + struct ref_list *ref_list; + int ret; +}; + static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { - struct ref_list *ref_list = (struct ref_list*)(cb_data); + struct append_ref_cb *cb = (struct append_ref_cb *)(cb_data); + struct ref_list *ref_list = cb->ref_list; struct ref_item *newitem; struct commit *commit; int kind, i; @@ -293,8 +299,10 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, commit = NULL; if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) { commit = lookup_commit_reference_gently(sha1, 1); - if (!commit) - return error("branch '%s' does not point at a commit", refname); + if (!commit) { + cb->ret = error("branch '%s' does not point at a commit", refname); + return 0; + } /* Filter with with_commit if specified */ if (!is_descendant_of(commit, ref_list->with_commit)) @@ -484,9 +492,10 @@ static void show_detached(struct ref_list *ref_list) } } -static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit) +static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit) { int i; + struct append_ref_cb cb; struct ref_list ref_list; memset(&ref_list, 0, sizeof(ref_list)); @@ -496,7 +505,9 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); - for_each_rawref(append_ref, &ref_list); + cb.ref_list = &ref_list; + cb.ret = 0; + for_each_rawref(append_ref, &cb); if (merge_filter != NO_FILTER) { struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); @@ -527,6 +538,11 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str } free_ref_list(&ref_list); + + if (cb.ret) + error("some refs could not be read"); + + return cb.ret; } static void rename_branch(const char *oldname, const char *newname, int force) @@ -679,7 +695,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (delete) return delete_branches(argc, argv, delete > 1, kinds); else if (argc == 0) - print_ref_list(kinds, detached, verbose, abbrev, with_commit); + return print_ref_list(kinds, detached, verbose, abbrev, with_commit); else if (rename && (argc == 1)) rename_branch(head, argv[0], rename > 1); else if (rename && (argc == 2)) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index a933eaa04..76ec3fec9 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -9,6 +9,8 @@ #include "tree.h" #include "builtin.h" #include "parse-options.h" +#include "diff.h" +#include "userdiff.h" #define BATCH 1 #define BATCH_CHECK 2 @@ -84,10 +86,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) { unsigned char sha1[20]; enum object_type type; - void *buf; + char *buf; unsigned long size; + struct object_context obj_context; - if (get_sha1(obj_name, sha1)) + if (get_sha1_with_context(obj_name, sha1, &obj_context)) die("Not a valid object name %s", obj_name); buf = NULL; @@ -118,7 +121,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) /* custom pretty-print here */ if (type == OBJ_TREE) { - const char *ls_args[3] = {"ls-tree", obj_name, NULL}; + const char *ls_args[3] = { NULL }; + ls_args[0] = "ls-tree"; + ls_args[1] = obj_name; return cmd_ls_tree(2, ls_args, NULL); } @@ -132,6 +137,17 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) /* otherwise just spit out the data */ break; + + case 'c': + if (!obj_context.path[0]) + die("git cat-file --textconv %s: <object> must be <sha1:path>", + obj_name); + + if (!textconv_object(obj_context.path, sha1, &buf, &size)) + die("git cat-file --textconv: unable to run textconv on %s", + obj_name); + break; + case 0: buf = read_object_with_reference(sha1, exp_type, &size, NULL); break; @@ -201,11 +217,25 @@ static int batch_objects(int print_contents) } static const char * const cat_file_usage[] = { - "git cat-file (-t|-s|-e|-p|<type>) <object>", + "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>", "git cat-file (--batch|--batch-check) < <list_of_objects>", NULL }; +static int git_cat_file_config(const char *var, const char *value, void *cb) +{ + switch (userdiff_config(var, value)) { + case 0: + break; + case -1: + return -1; + default: + return 0; + } + + return git_default_config(var, value, cb); +} + int cmd_cat_file(int argc, const char **argv, const char *prefix) { int opt = 0, batch = 0; @@ -218,6 +248,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) OPT_SET_INT('e', NULL, &opt, "exit with zero when there's no error", 'e'), OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'), + OPT_SET_INT(0, "textconv", &opt, + "for blob objects, run textconv on object's content", 'c'), OPT_SET_INT(0, "batch", &batch, "show info and content of objects fed from the standard input", BATCH), @@ -227,7 +259,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) OPT_END() }; - git_config(git_default_config, NULL); + git_config(git_cat_file_config, NULL); if (argc != 3 && argc != 2) usage_with_options(cat_file_usage, options); diff --git a/builtin/checkout.c b/builtin/checkout.c index c3825219c..1994be92c 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -493,7 +493,24 @@ static void update_refs_for_switch(struct checkout_opts *opts, struct strbuf msg = STRBUF_INIT; const char *old_desc; if (opts->new_branch) { - if (!opts->new_orphan_branch) + if (opts->new_orphan_branch) { + if (opts->new_branch_log && !log_all_ref_updates) { + int temp; + char log_file[PATH_MAX]; + char *ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch); + + temp = log_all_ref_updates; + log_all_ref_updates = 1; + if (log_ref_setup(ref_name, log_file, sizeof(log_file))) { + fprintf(stderr, "Can not do reflog for '%s'\n", + opts->new_orphan_branch); + log_all_ref_updates = temp; + return; + } + log_all_ref_updates = temp; + } + } + else create_branch(old->name, opts->new_branch, new->name, 0, opts->new_branch_log, opts->track); new->name = opts->new_branch; @@ -517,6 +534,14 @@ static void update_refs_for_switch(struct checkout_opts *opts, opts->new_branch ? " a new" : "", new->name); } + if (old->path && old->name) { + char log_file[PATH_MAX], ref_file[PATH_MAX]; + + git_snpath(log_file, sizeof(log_file), "logs/%s", old->path); + git_snpath(ref_file, sizeof(ref_file), "%s", old->path); + if (!file_exists(ref_file) && file_exists(log_file)) + remove_path(log_file); + } } else if (strcmp(new->name, "HEAD")) { update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL, REF_NODEREF, DIE_ON_ERR); @@ -611,7 +636,8 @@ static int check_tracking_name(const char *refname, const unsigned char *sha1, static const char *unique_tracking_name(const char *name) { - struct tracking_name_data cb_data = { name, NULL, 1 }; + struct tracking_name_data cb_data = { NULL, NULL, 1 }; + cb_data.name = name; for_each_ref(check_tracking_name, &cb_data); if (cb_data.unique) return cb_data.remote; @@ -684,8 +710,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (opts.new_orphan_branch) { if (opts.new_branch) die("--orphan and -b are mutually exclusive"); - if (opts.track > 0 || opts.new_branch_log) - die("--orphan cannot be used with -t or -l"); + if (opts.track > 0) + die("--orphan cannot be used with -t"); opts.new_branch = opts.new_orphan_branch; } diff --git a/builtin/clone.c b/builtin/clone.c index 445792242..efb1e6faa 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -464,7 +464,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) set_git_dir(make_absolute_path(git_dir)); if (0 <= option_verbosity) - printf("Cloning into %s...\n", get_git_dir()); + printf("Cloning into %s%s...\n", + option_bare ? "bare repository " : "", dir); init_db(option_template, INIT_DB_QUIET); /* diff --git a/builtin/commit.c b/builtin/commit.c index ddf77e48e..c6b053a50 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -48,6 +48,11 @@ static const char implicit_ident_advice[] = "\n" " git commit --amend --author='Your Name <you@example.com>'\n"; +static const char empty_amend_advice[] = +"You asked to amend the most recent commit, but doing so would make\n" +"it empty. You can repeat your command with --allow-empty, or you can\n" +"remove the commit entirely with \"git reset HEAD^\".\n"; + static unsigned char head_sha1[20]; static char *use_message_buffer; @@ -57,7 +62,7 @@ static struct lock_file false_lock; /* used only for partial commits */ static enum { COMMIT_AS_IS = 1, COMMIT_NORMAL, - COMMIT_PARTIAL, + COMMIT_PARTIAL } commit_style; static const char *logfile, *force_author; @@ -78,7 +83,7 @@ static char *untracked_files_arg, *force_date; static enum { CLEANUP_SPACE, CLEANUP_NONE, - CLEANUP_ALL, + CLEANUP_ALL } cleanup_mode; static char *cleanup_arg; @@ -91,8 +96,9 @@ static int null_termination; static enum { STATUS_FORMAT_LONG, STATUS_FORMAT_SHORT, - STATUS_FORMAT_PORCELAIN, + STATUS_FORMAT_PORCELAIN } status_format = STATUS_FORMAT_LONG; +static int status_show_branch; static int opt_parse_m(const struct option *opt, const char *arg, int unset) { @@ -134,6 +140,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"), OPT_SET_INT(0, "short", &status_format, "show status concisely", STATUS_FORMAT_SHORT), + OPT_BOOLEAN(0, "branch", &status_show_branch, "show branch information"), OPT_SET_INT(0, "porcelain", &status_format, "show porcelain output format", STATUS_FORMAT_PORCELAIN), OPT_BOOLEAN('z', "null", &null_termination, @@ -212,7 +219,7 @@ static int list_paths(struct string_list *list, const char *with_tree, continue; if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m)) continue; - item = string_list_insert(ce->name, list); + item = string_list_insert(list, ce->name); if (ce_skip_worktree(ce)) item->util = item; /* better a valid pointer than a fake one */ } @@ -424,7 +431,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int switch (status_format) { case STATUS_FORMAT_SHORT: - wt_shortstatus_print(s, null_termination); + wt_shortstatus_print(s, null_termination, status_show_branch); break; case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(s, null_termination); @@ -462,15 +469,21 @@ static void determine_author_info(void) if (!a) die("invalid commit: %s", use_message); - lb = strstr(a + 8, " <"); - rb = strstr(a + 8, "> "); - eol = strchr(a + 8, '\n'); - if (!lb || !rb || !eol) + lb = strchrnul(a + strlen("\nauthor "), '<'); + rb = strchrnul(lb, '>'); + eol = strchrnul(rb, '\n'); + if (!*lb || !*rb || !*eol) die("invalid commit: %s", use_message); - name = xstrndup(a + 8, lb - (a + 8)); - email = xstrndup(lb + 2, rb - (lb + 2)); - date = xstrndup(rb + 2, eol - (rb + 2)); + if (lb == a + strlen("\nauthor ")) + /* \nauthor <foo@example.com> */ + name = xcalloc(1, 1); + else + name = xmemdupz(a + strlen("\nauthor "), + (lb - strlen(" ") - + (a + strlen("\nauthor ")))); + email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<"))); + date = xmemdupz(rb + strlen("> "), eol - (rb + strlen("> "))); } if (force_author) { @@ -700,6 +713,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (!commitable && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix, 0, s); + if (amend) + fputs(empty_amend_advice, stderr); return 0; } @@ -724,7 +739,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (use_editor) { char index[PATH_MAX]; - const char *env[2] = { index, NULL }; + const char *env[2] = { NULL }; + env[0] = index; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); if (launch_editor(git_path(commit_editmsg), NULL, env)) { fprintf(stderr, @@ -1030,6 +1046,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT__VERBOSE(&verbose), OPT_SET_INT('s', "short", &status_format, "show status concisely", STATUS_FORMAT_SHORT), + OPT_BOOLEAN('b', "branch", &status_show_branch, + "show branch information"), OPT_SET_INT(0, "porcelain", &status_format, "show porcelain output format", STATUS_FORMAT_PORCELAIN), @@ -1082,7 +1100,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) switch (status_format) { case STATUS_FORMAT_SHORT: - wt_shortstatus_print(&s, null_termination); + wt_shortstatus_print(&s, null_termination, status_show_branch); break; case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(&s, null_termination); @@ -1157,13 +1175,11 @@ static void print_summary(const char *prefix, const unsigned char *sha1) initial_commit ? " (root-commit)" : ""); if (!log_tree_commit(&rev, commit)) { - struct pretty_print_context ctx = {0}; - struct strbuf buf = STRBUF_INIT; - ctx.date_mode = DATE_NORMAL; - format_commit_message(commit, format.buf + 7, &buf, &ctx); - printf("%s\n", buf.buf); - strbuf_release(&buf); + rev.always_show_header = 1; + rev.use_terminator = 1; + log_tree_commit(&rev, commit); } + strbuf_release(&format); } @@ -1251,13 +1267,16 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } /* Determine parents */ + reflog_msg = getenv("GIT_REFLOG_ACTION"); if (initial_commit) { - reflog_msg = "commit (initial)"; + if (!reflog_msg) + reflog_msg = "commit (initial)"; } else if (amend) { struct commit_list *c; struct commit *commit; - reflog_msg = "commit (amend)"; + if (!reflog_msg) + reflog_msg = "commit (amend)"; commit = lookup_commit(head_sha1); if (!commit || parse_commit(commit)) die("could not parse HEAD commit"); @@ -1268,7 +1287,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct strbuf m = STRBUF_INIT; FILE *fp; - reflog_msg = "commit (merge)"; + if (!reflog_msg) + reflog_msg = "commit (merge)"; pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) @@ -1291,7 +1311,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (allow_fast_forward) parents = reduce_heads(parents); } else { - reflog_msg = "commit"; + if (!reflog_msg) + reflog_msg = "commit"; pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; } diff --git a/builtin/fast-export.c b/builtin/fast-export.c index c6dd71a7b..9fe25ff0b 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -438,7 +438,7 @@ static void get_tags_and_duplicates(struct object_array *pending, /* handle nested tags */ while (tag && tag->object.type == OBJ_TAG) { parse_object(tag->object.sha1); - string_list_append(full_name, extra_refs)->util = tag; + string_list_append(extra_refs, full_name)->util = tag; tag = (struct tag *)tag->tagged; } if (!tag) @@ -464,7 +464,7 @@ static void get_tags_and_duplicates(struct object_array *pending, } if (commit->util) /* more than one name for the same object */ - string_list_append(full_name, extra_refs)->util = commit; + string_list_append(extra_refs, full_name)->util = commit; else commit->util = full_name; } diff --git a/builtin/fetch.c b/builtin/fetch.c index 847085041..6eb1dfea0 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -528,7 +528,7 @@ static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata) { struct string_list *list = (struct string_list *)cbdata; - struct string_list_item *item = string_list_insert(refname, list); + struct string_list_item *item = string_list_insert(list, refname); item->util = (void *)sha1; return 0; } @@ -574,9 +574,10 @@ static void find_non_local_tags(struct transport *transport, { struct string_list existing_refs = { NULL, 0, 0, 0 }; struct string_list remote_refs = { NULL, 0, 0, 0 }; - struct tag_data data = {head, tail}; + struct tag_data data; const struct ref *ref; struct string_list_item *item = NULL; + data.head = head; data.tail = tail; for_each_ref(add_existing, &existing_refs); for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) { @@ -616,7 +617,7 @@ static void find_non_local_tags(struct transport *transport, string_list_has_string(&existing_refs, ref->name)) continue; - item = string_list_insert(ref->name, &remote_refs); + item = string_list_insert(&remote_refs, ref->name); item->util = (void *)ref->old_sha1; } string_list_clear(&existing_refs, 0); @@ -633,7 +634,7 @@ static void find_non_local_tags(struct transport *transport, * For all the tags in the remote_refs string list, call * add_to_tail to add them to the list of refs to be fetched */ - for_each_string_list(add_to_tail, &remote_refs, &data); + for_each_string_list(&remote_refs, add_to_tail, &data); string_list_clear(&remote_refs, 0); } @@ -695,8 +696,8 @@ static int do_fetch(struct transport *transport, for (rm = ref_map; rm; rm = rm->next) { if (rm->peer_ref) { - peer_item = string_list_lookup(rm->peer_ref->name, - &existing_refs); + peer_item = string_list_lookup(&existing_refs, + rm->peer_ref->name); if (peer_item) hashcpy(rm->peer_ref->old_sha1, peer_item->util); @@ -745,7 +746,7 @@ static int get_one_remote_for_fetch(struct remote *remote, void *priv) { struct string_list *list = priv; if (!remote->skip_default_update) - string_list_append(remote->name, list); + string_list_append(list, remote->name); return 0; } @@ -764,8 +765,8 @@ static int get_remote_group(const char *key, const char *value, void *priv) int space = strcspn(value, " \t\n"); while (*value) { if (space > 1) { - string_list_append(xstrndup(value, space), - g->list); + string_list_append(g->list, + xstrndup(value, space)); } value += space + (value[space] != '\0'); space = strcspn(value, " \t\n"); @@ -778,7 +779,8 @@ static int get_remote_group(const char *key, const char *value, void *priv) static int add_remote_or_group(const char *name, struct string_list *list) { int prev_nr = list->nr; - struct remote_group_data g = { name, list }; + struct remote_group_data g; + g.name = name; g.list = list; git_config(get_remote_group, &g); if (list->nr == prev_nr) { @@ -786,7 +788,7 @@ static int add_remote_or_group(const char *name, struct string_list *list) if (!remote_is_configured(name)) return 0; remote = remote_get(name); - string_list_append(remote->name, list); + string_list_append(list, remote->name); } return 1; } diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 379a03131..bc3c5e6d3 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -82,7 +82,7 @@ static int handle_line(char *line) item = unsorted_string_list_lookup(&srcs, src); if (!item) { - item = string_list_append(src, &srcs); + item = string_list_append(&srcs, src); item->util = xcalloc(1, sizeof(struct src_data)); init_src_data(item->util); } @@ -93,19 +93,19 @@ static int handle_line(char *line) src_data->head_status |= 1; } else if (!prefixcmp(line, "branch ")) { origin = line + 7; - string_list_append(origin, &src_data->branch); + string_list_append(&src_data->branch, origin); src_data->head_status |= 2; } else if (!prefixcmp(line, "tag ")) { origin = line; - string_list_append(origin + 4, &src_data->tag); + string_list_append(&src_data->tag, origin + 4); src_data->head_status |= 2; } else if (!prefixcmp(line, "remote branch ")) { origin = line + 14; - string_list_append(origin, &src_data->r_branch); + string_list_append(&src_data->r_branch, origin); src_data->head_status |= 2; } else { origin = src; - string_list_append(line, &src_data->generic); + string_list_append(&src_data->generic, line); src_data->head_status |= 2; } @@ -118,7 +118,7 @@ static int handle_line(char *line) sprintf(new_origin, "%s of %s", origin, src); origin = new_origin; } - string_list_append(origin, &origins)->util = sha1; + string_list_append(&origins, origin)->util = sha1; return 0; } @@ -176,10 +176,10 @@ static void shortlog(const char *name, unsigned char *sha1, strbuf_ltrim(&sb); if (!sb.len) - string_list_append(sha1_to_hex(commit->object.sha1), - &subjects); + string_list_append(&subjects, + sha1_to_hex(commit->object.sha1)); else - string_list_append(strbuf_detach(&sb, NULL), &subjects); + string_list_append(&subjects, strbuf_detach(&sb, NULL)); } if (count > limit) @@ -202,35 +202,10 @@ static void shortlog(const char *name, unsigned char *sha1, string_list_clear(&subjects, 0); } -int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { - int limit = 20, i = 0, pos = 0; +static void do_fmt_merge_msg_title(struct strbuf *out, + const char *current_branch) { + int i = 0; char *sep = ""; - unsigned char head_sha1[20]; - const char *current_branch; - - /* get current branch */ - current_branch = resolve_ref("HEAD", head_sha1, 1, NULL); - if (!current_branch) - die("No current branch"); - if (!prefixcmp(current_branch, "refs/heads/")) - current_branch += 11; - - /* get a line */ - while (pos < in->len) { - int len; - char *newline, *p = in->buf + pos; - - newline = strchr(p, '\n'); - len = newline ? newline - p : strlen(p); - pos += len + !!newline; - i++; - p[len] = 0; - if (handle_line(p)) - die ("Error in line %d: %.*s", i, len, p); - } - - if (!srcs.nr) - return 0; strbuf_addstr(out, "Merge "); for (i = 0; i < srcs.nr; i++) { @@ -278,6 +253,40 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { strbuf_addch(out, '\n'); else strbuf_addf(out, " into %s\n", current_branch); +} + +static int do_fmt_merge_msg(int merge_title, int merge_summary, + struct strbuf *in, struct strbuf *out) { + int limit = 20, i = 0, pos = 0; + unsigned char head_sha1[20]; + const char *current_branch; + + /* get current branch */ + current_branch = resolve_ref("HEAD", head_sha1, 1, NULL); + if (!current_branch) + die("No current branch"); + if (!prefixcmp(current_branch, "refs/heads/")) + current_branch += 11; + + /* get a line */ + while (pos < in->len) { + int len; + char *newline, *p = in->buf + pos; + + newline = strchr(p, '\n'); + len = newline ? newline - p : strlen(p); + pos += len + !!newline; + i++; + p[len] = 0; + if (handle_line(p)) + die ("Error in line %d: %.*s", i, len, p); + } + + if (!srcs.nr) + return 0; + + if (merge_title) + do_fmt_merge_msg_title(out, current_branch); if (merge_summary) { struct commit *head; @@ -289,6 +298,9 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { rev.ignore_merges = 1; rev.limited = 1; + if (suffixcmp(out->buf, "\n")) + strbuf_addch(out, '\n'); + for (i = 0; i < origins.nr; i++) shortlog(origins.items[i].string, origins.items[i].util, head, &rev, limit, out); @@ -296,6 +308,14 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { return 0; } +int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { + return do_fmt_merge_msg(1, merge_summary, in, out); +} + +int fmt_merge_msg_shortlog(struct strbuf *in, struct strbuf *out) { + return do_fmt_merge_msg(0, 1, in, out); +} + int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) { const char *inpath = NULL; diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 3a9795317..a2b28c696 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -552,10 +552,10 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v grab_person("committer", val, deref, obj, buf, sz); break; case OBJ_TREE: - // grab_tree_values(val, deref, obj, buf, sz); + /* grab_tree_values(val, deref, obj, buf, sz); */ break; case OBJ_BLOB: - // grab_blob_values(val, deref, obj, buf, sz); + /* grab_blob_values(val, deref, obj, buf, sz); */ break; default: die("Eh? Object of type %d?", obj->type); diff --git a/builtin/grep.c b/builtin/grep.c index b194ea3ce..232cd1ce0 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -11,6 +11,8 @@ #include "tree-walk.h" #include "builtin.h" #include "parse-options.h" +#include "string-list.h" +#include "run-command.h" #include "userdiff.h" #include "grep.h" #include "quote.h" @@ -556,6 +558,33 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(const char *)data == '\0') + return; + string_list_append(path_list, xstrndup(data, len)); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + const char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i, status; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix && chdir(prefix)) + die("Failed to chdir: %s", prefix); + status = run_command_v_opt(argv, RUN_USING_SHELL); + if (status) + exit(status); + free(argv); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -590,7 +619,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -675,6 +703,25 @@ static int grep_object(struct grep_opt *opt, const char **paths, die("unable to grep from object of type %s", typename(obj->type)); } +static int grep_objects(struct grep_opt *opt, const char **paths, + const struct object_array *list) +{ + unsigned int i; + int hit = 0; + const unsigned int nr = list->nr; + + for (i = 0; i < nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list->objects[i].item, NULL, 0); + if (grep_object(opt, paths, real_obj, list->objects[i].name)) { + hit = 1; + if (opt->status_only) + break; + } + } + return hit; +} + static int grep_directory(struct grep_opt *opt, const char **paths) { struct dir_struct dir; @@ -689,7 +736,6 @@ static int grep_directory(struct grep_opt *opt, const char **paths) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -724,11 +770,15 @@ static int file_callback(const struct option *opt, const char *arg, int unset) if (!patterns) die_errno("cannot open '%s'", arg); while (strbuf_getline(&sb, patterns, '\n') == 0) { + char *s; + size_t len; + /* ignore empty line like grep does */ if (sb.len == 0) continue; - append_grep_pattern(grep_opt, strbuf_detach(&sb, NULL), arg, - ++lno, GREP_PATTERN); + + s = strbuf_detach(&sb, &len); + append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN); } fclose(patterns); strbuf_release(&sb); @@ -782,9 +832,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -868,6 +920,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -943,6 +998,17 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager == default_pager) + show_in_pager = git_pager(1); + if (show_in_pager) { + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(&path_list, show_in_pager); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -999,44 +1065,51 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[1] = NULL; } + if (show_in_pager && (cached || list.nr)) + die("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(&path_list, buf.buf); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + + if (!use_index) { - int hit; if (cached) die("--cached cannot be used with --no-index."); if (list.nr) die("--no-index cannot be used with revs."); hit = grep_directory(&opt, paths); - if (use_threads) - hit |= wait_all(); - return !hit; - } - - if (!list.nr) { - int hit; + } else if (!list.nr) { if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; - } - - if (cached) - die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; - } + } else { + if (cached) + die("both --cached and trees are given."); + hit = grep_objects(&opt, paths, &list); } if (use_threads) hit |= wait_all(); + if (hit && show_in_pager) + run_pager(&opt, prefix); free_grep_patterns(&opt); return !hit; } diff --git a/builtin/help.c b/builtin/help.c index 3182a2bec..a9836b00a 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -26,7 +26,7 @@ enum help_format { HELP_FORMAT_NONE, HELP_FORMAT_MAN, HELP_FORMAT_INFO, - HELP_FORMAT_WEB, + HELP_FORMAT_WEB }; static int show_all = 0; diff --git a/builtin/log.c b/builtin/log.c index 976e16f9f..7cb9317af 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -535,13 +535,13 @@ static void add_header(const char *value) len--; if (!strncasecmp(value, "to: ", 4)) { - item = string_list_append(value + 4, &extra_to); + item = string_list_append(&extra_to, value + 4); len -= 4; } else if (!strncasecmp(value, "cc: ", 4)) { - item = string_list_append(value + 4, &extra_cc); + item = string_list_append(&extra_cc, value + 4); len -= 4; } else { - item = string_list_append(value, &extra_hdr); + item = string_list_append(&extra_hdr, value); } item->string[len] = '\0'; @@ -549,8 +549,9 @@ static void add_header(const char *value) #define THREAD_SHALLOW 1 #define THREAD_DEEP 2 -static int thread = 0; -static int do_signoff = 0; +static int thread; +static int do_signoff; +static const char *signature = git_version_string; static int git_format_config(const char *var, const char *value, void *cb) { @@ -565,13 +566,13 @@ static int git_format_config(const char *var, const char *value, void *cb) if (!strcmp(var, "format.to")) { if (!value) return config_error_nonbool(var); - string_list_append(value, &extra_to); + string_list_append(&extra_to, value); return 0; } if (!strcmp(var, "format.cc")) { if (!value) return config_error_nonbool(var); - string_list_append(value, &extra_cc); + string_list_append(&extra_cc, value); return 0; } if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { @@ -609,6 +610,8 @@ static int git_format_config(const char *var, const char *value, void *cb) do_signoff = git_config_bool(var, value); return 0; } + if (!strcmp(var, "format.signature")) + return git_config_string(&signature, var, value); return git_log_config(var, value, cb); } @@ -703,6 +706,12 @@ static void gen_message_id(struct rev_info *info, char *base) info->message_id = strbuf_detach(&buf, NULL); } +static void print_signature(void) +{ + if (signature && *signature) + printf("-- \n%s\n\n", signature); +} + static void make_cover_letter(struct rev_info *rev, int use_stdout, int numbered, int numbered_files, struct commit *origin, @@ -796,6 +805,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, diff_flush(&opts); printf("\n"); + print_signature(); } static const char *clean_message_id(const char *msg_id) @@ -949,7 +959,7 @@ static int to_callback(const struct option *opt, const char *arg, int unset) if (unset) string_list_clear(&extra_to, 0); else - string_list_append(arg, &extra_to); + string_list_append(&extra_to, arg); return 0; } @@ -958,7 +968,7 @@ static int cc_callback(const struct option *opt, const char *arg, int unset) if (unset) string_list_clear(&extra_cc, 0); else - string_list_append(arg, &extra_cc); + string_list_append(&extra_cc, arg); return 0; } @@ -1035,6 +1045,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) { OPTION_CALLBACK, 0, "thread", &thread, "style", "enable message threading, styles: shallow, deep", PARSE_OPT_OPTARG, thread_callback }, + OPT_STRING(0, "signature", &signature, "signature", + "add a signature"), OPT_END() }; @@ -1239,7 +1251,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.ref_message_ids = xcalloc(1, sizeof(struct string_list)); if (in_reply_to) { const char *msgid = clean_message_id(in_reply_to); - string_list_append(msgid, rev.ref_message_ids); + string_list_append(rev.ref_message_ids, msgid); } rev.numbered_files = numbered_files; rev.patch_suffix = fmt_patch_suffix; @@ -1286,8 +1298,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) && (!cover_letter || rev.nr > 1)) free(rev.message_id); else - string_list_append(rev.message_id, - rev.ref_message_ids); + string_list_append(rev.ref_message_ids, + rev.message_id); } gen_message_id(&rev, sha1_to_hex(commit->object.sha1)); } @@ -1313,7 +1325,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) mime_boundary_leader, rev.mime_boundary); else - printf("-- \n%s\n\n", git_version_string); + print_signature(); } if (!use_stdout) fclose(stdout); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index c0fbcdcf4..1b9b8a8b4 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -26,8 +26,9 @@ static int show_killed; static int show_valid_bit; static int line_terminator = '\n'; +static const char *prefix; +static int max_prefix_len; static int prefix_len; -static int prefix_offset; static const char **pathspec; static int error_unmatch; static char *ps_matched; @@ -43,10 +44,15 @@ static const char *tag_modified = ""; static const char *tag_skip_worktree = ""; static const char *tag_resolve_undo = ""; +static void write_name(const char* name, size_t len) +{ + write_name_quoted_relative(name, len, prefix, prefix_len, stdout, + line_terminator); +} + static void show_dir_entry(const char *tag, struct dir_entry *ent) { - int len = prefix_len; - int offset = prefix_offset; + int len = max_prefix_len; if (len >= ent->len) die("git ls-files: internal error - directory entry not superset of prefix"); @@ -55,7 +61,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent) return; fputs(tag, stdout); - write_name_quoted(ent->name + offset, stdout, line_terminator); + write_name(ent->name, ent->len); } static void show_other_files(struct dir_struct *dir) @@ -121,8 +127,7 @@ static void show_killed_files(struct dir_struct *dir) static void show_ce_entry(const char *tag, struct cache_entry *ce) { - int len = prefix_len; - int offset = prefix_offset; + int len = max_prefix_len; if (len >= ce_namelen(ce)) die("git ls-files: internal error - cache entry not superset of prefix"); @@ -156,20 +161,19 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) find_unique_abbrev(ce->sha1,abbrev), ce_stage(ce)); } - write_name_quoted(ce->name + offset, stdout, line_terminator); + write_name(ce->name, ce_namelen(ce)); } static int show_one_ru(struct string_list_item *item, void *cbdata) { - int offset = prefix_offset; const char *path = item->string; struct resolve_undo_info *ui = item->util; int i, len; len = strlen(path); - if (len < prefix_len) + if (len < max_prefix_len) return 0; /* outside of the prefix */ - if (!match_pathspec(pathspec, path, len, prefix_len, ps_matched)) + if (!match_pathspec(pathspec, path, len, max_prefix_len, ps_matched)) return 0; /* uninterested */ for (i = 0; i < 3; i++) { if (!ui->mode[i]) @@ -177,19 +181,19 @@ static int show_one_ru(struct string_list_item *item, void *cbdata) printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i], find_unique_abbrev(ui->sha1[i], abbrev), i + 1); - write_name_quoted(path + offset, stdout, line_terminator); + write_name(path, len); } return 0; } -static void show_ru_info(const char *prefix) +static void show_ru_info(void) { if (!the_index.resolve_undo) return; - for_each_string_list(show_one_ru, the_index.resolve_undo, NULL); + for_each_string_list(the_index.resolve_undo, show_one_ru, NULL); } -static void show_files(struct dir_struct *dir, const char *prefix) +static void show_files(struct dir_struct *dir) { int i; @@ -243,7 +247,7 @@ static void show_files(struct dir_struct *dir, const char *prefix) */ static void prune_cache(const char *prefix) { - int pos = cache_name_pos(prefix, prefix_len); + int pos = cache_name_pos(prefix, max_prefix_len); unsigned int first, last; if (pos < 0) @@ -256,7 +260,7 @@ static void prune_cache(const char *prefix) while (last > first) { int next = (last + first) >> 1; struct cache_entry *ce = active_cache[next]; - if (!strncmp(ce->name, prefix, prefix_len)) { + if (!strncmp(ce->name, prefix, max_prefix_len)) { first = next+1; continue; } @@ -265,11 +269,16 @@ static void prune_cache(const char *prefix) active_nr = last; } -static const char *verify_pathspec(const char *prefix) +static const char *pathspec_prefix(const char *prefix) { const char **p, *n, *prev; unsigned long max; + if (!pathspec) { + max_prefix_len = prefix ? strlen(prefix) : 0; + return prefix; + } + prev = NULL; max = PATH_MAX; for (p = pathspec; (n = *p) != NULL; p++) { @@ -291,10 +300,7 @@ static const char *verify_pathspec(const char *prefix) } } - if (prefix_offset > max || memcmp(prev, prefix, prefix_offset)) - die("git ls-files: cannot generate relative filenames containing '..'"); - - prefix_len = max; + max_prefix_len = max; return max ? xmemdupz(prev, max) : NULL; } @@ -374,7 +380,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) } } -int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset) +int report_path_error(const char *ps_matched, const char **pathspec, int prefix_len) { /* * Make sure all pathspec matched; otherwise it is an error. @@ -404,7 +410,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_ continue; error("pathspec '%s' did not match any file(s) known to git.", - pathspec[num] + prefix_offset); + pathspec[num] + prefix_len); errors++; } return errors; @@ -456,9 +462,10 @@ static int option_parse_exclude_standard(const struct option *opt, return 0; } -int cmd_ls_files(int argc, const char **argv, const char *prefix) +int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) { int require_work_tree = 0, show_tag = 0; + const char *max_prefix; struct dir_struct dir; struct option builtin_ls_files_options[] = { { OPTION_CALLBACK, 'z', NULL, NULL, NULL, @@ -504,7 +511,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL, "add the standard git exclusions", PARSE_OPT_NOARG, option_parse_exclude_standard }, - { OPTION_SET_INT, 0, "full-name", &prefix_offset, NULL, + { OPTION_SET_INT, 0, "full-name", &prefix_len, NULL, "make the output relative to the project top directory", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL }, OPT_BOOLEAN(0, "error-unmatch", &error_unmatch, @@ -516,8 +523,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) }; memset(&dir, 0, sizeof(dir)); + prefix = cmd_prefix; if (prefix) - prefix_offset = strlen(prefix); + prefix_len = strlen(prefix); git_config(git_default_config, NULL); if (read_cache() < 0) @@ -555,9 +563,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) if (pathspec) strip_trailing_slash_from_submodules(); - /* Verify that the pathspec matches the prefix */ - if (pathspec) - prefix = verify_pathspec(prefix); + /* Find common prefix for all pathspec's */ + max_prefix = pathspec_prefix(prefix); /* Treat unmatching pathspec elements as errors */ if (pathspec && error_unmatch) { @@ -575,8 +582,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) show_killed | show_modified | show_resolve_undo)) show_cached = 1; - if (prefix) - prune_cache(prefix); + if (max_prefix) + prune_cache(max_prefix); if (with_tree) { /* * Basic sanity check; show-stages and show-unmerged @@ -584,15 +591,15 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) */ if (show_stage || show_unmerged) die("ls-files --with-tree is incompatible with -s or -u"); - overlay_tree_on_cache(with_tree, prefix); + overlay_tree_on_cache(with_tree, max_prefix); } - show_files(&dir, prefix); + show_files(&dir); if (show_resolve_undo) - show_ru_info(prefix); + show_ru_info(); if (ps_matched) { int bad; - bad = report_path_error(ps_matched, pathspec, prefix_offset); + bad = report_path_error(ps_matched, pathspec, prefix_len); if (bad) fprintf(stderr, "Did you forget to 'git add'?\n"); diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 8ee91eb54..34480cfad 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" -" [<repository> [<refs>...]]"; +" [-q|--quiet] [<repository> [<refs>...]]"; /* * Is there one among the list of patterns that match the tail part @@ -34,6 +34,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) const char *dest = NULL; int nongit; unsigned flags = 0; + int quiet = 0; const char *uploadpack = NULL; const char **pattern = NULL; @@ -67,6 +68,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) flags |= REF_NORMAL; continue; } + if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) { + quiet = 1; + continue; + } usage(ls_remote_usage); } dest = arg; @@ -99,6 +104,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) ref = transport_get_remote_refs(transport); if (transport_disconnect(transport)) return 1; + + if (!dest && !quiet) + fprintf(stderr, "From %s\n", *remote->url); for ( ; ref; ref = ref->next) { if (!check_ref_type(ref, flags)) continue; diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c index 4a9729b9b..2320d981c 100644 --- a/builtin/mailinfo.c +++ b/builtin/mailinfo.c @@ -17,10 +17,10 @@ static struct strbuf name = STRBUF_INIT; static struct strbuf email = STRBUF_INIT; static enum { - TE_DONTCARE, TE_QP, TE_BASE64, + TE_DONTCARE, TE_QP, TE_BASE64 } transfer_encoding; static enum { - TYPE_TEXT, TYPE_OTHER, + TYPE_TEXT, TYPE_OTHER } message_type; static struct strbuf charset = STRBUF_INIT; diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c index cdfc1b704..e4560da19 100644 --- a/builtin/mailsplit.c +++ b/builtin/mailsplit.c @@ -121,7 +121,7 @@ static int populate_maildir_list(struct string_list *list, const char *path) if (dent->d_name[0] == '.') continue; snprintf(name, sizeof(name), "%s/%s", *sub, dent->d_name); - string_list_insert(name, list); + string_list_insert(list, name); } closedir(dir); diff --git a/builtin/merge-file.c b/builtin/merge-file.c index 610849a65..b8e9e5ba0 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -25,7 +25,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) const char *names[3] = { NULL, NULL, NULL }; mmfile_t mmfs[3]; mmbuffer_t result = {NULL, 0}; - xmparam_t xmp = {{XDF_NEED_MINIMAL}}; + xmparam_t xmp = {{0}}; int ret = 0, i = 0, to_stdout = 0; int quiet = 0; int nongit; diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index a4a4f2ce4..fc00d794d 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -106,7 +106,7 @@ static void show_diff(struct merge_list *entry) xdemitconf_t xecfg; xdemitcb_t ecb; - xpp.flags = XDF_NEED_MINIMAL; + xpp.flags = 0; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; ecb.outf = show_outf; diff --git a/builtin/merge.c b/builtin/merge.c index 37d414b3b..37ce4f589 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -982,7 +982,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) reset_hard(remote_head->sha1, 0); return 0; } else { - struct strbuf msg = STRBUF_INIT; + struct strbuf merge_names = STRBUF_INIT; /* We are invoked directly as the first-class UI. */ head_arg = "HEAD"; @@ -995,13 +995,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * codepath so we discard the error in this * loop. */ - if (!have_message) { - for (i = 0; i < argc; i++) - merge_name(argv[i], &msg); - fmt_merge_msg(option_log, &msg, &merge_msg); - if (merge_msg.len) - strbuf_setlen(&merge_msg, merge_msg.len-1); - } + for (i = 0; i < argc; i++) + merge_name(argv[i], &merge_names); + + if (have_message && option_log) + fmt_merge_msg_shortlog(&merge_names, &merge_msg); + else if (!have_message) + fmt_merge_msg(option_log, &merge_names, &merge_msg); + + + if (!(have_message && !option_log) && merge_msg.len) + strbuf_setlen(&merge_msg, merge_msg.len-1); } if (head_invalid || !argc) diff --git a/builtin/mv.c b/builtin/mv.c index c07f53b34..38574b89f 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -180,7 +180,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) } else if (string_list_has_string(&src_for_dst, dst)) bad = "multiple sources for the same target"; else - string_list_insert(dst, &src_for_dst); + string_list_insert(&src_for_dst, dst); if (bad) { if (ignore_errors) { diff --git a/builtin/notes.c b/builtin/notes.c index 52b72fca6..190005f3c 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -26,7 +26,7 @@ static const char * const git_notes_usage[] = { "git notes [--ref <notes_ref>] edit [<object>]", "git notes [--ref <notes_ref>] show [<object>]", "git notes [--ref <notes_ref>] remove [<object>]", - "git notes [--ref <notes_ref>] prune", + "git notes [--ref <notes_ref>] prune [-n | -v]", NULL }; @@ -67,7 +67,7 @@ static const char * const git_notes_remove_usage[] = { }; static const char * const git_notes_prune_usage[] = { - "git notes prune", + "git notes prune [<options>]", NULL }; @@ -313,7 +313,7 @@ int commit_notes(struct notes_tree *t, const char *msg) return 0; } -combine_notes_fn *parse_combine_notes_fn(const char *v) +combine_notes_fn parse_combine_notes_fn(const char *v) { if (!strcasecmp(v, "overwrite")) return combine_notes_overwrite; @@ -416,7 +416,7 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd) { struct strbuf buf = STRBUF_INIT; struct notes_rewrite_cfg *c = NULL; - struct notes_tree *t; + struct notes_tree *t = NULL; int ret = 0; if (rewrite_cmd) { @@ -614,6 +614,10 @@ static int copy(int argc, const char **argv, const char *prefix) } } + if (argc < 2) { + error("too few parameters"); + usage_with_options(git_notes_copy_usage, options); + } if (2 < argc) { error("too many parameters"); usage_with_options(git_notes_copy_usage, options); @@ -792,7 +796,10 @@ static int remove_cmd(int argc, const char **argv, const char *prefix) static int prune(int argc, const char **argv, const char *prefix) { struct notes_tree *t; + int show_only = 0, verbose = 0; struct option options[] = { + OPT_BOOLEAN('n', NULL, &show_only, "do not remove, show only"), + OPT_BOOLEAN('v', NULL, &verbose, "report pruned notes"), OPT_END() }; @@ -806,8 +813,10 @@ static int prune(int argc, const char **argv, const char *prefix) t = init_notes_check("prune"); - prune_notes(t); - commit_notes(t, "Notes removed by 'git notes prune'"); + prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) | + (show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) ); + if (!show_only) + commit_notes(t, "Notes removed by 'git notes prune'"); free_notes(t); return 0; } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 214d7ef2b..0e8167311 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1529,6 +1529,8 @@ static void try_to_free_from_threads(size_t size) read_unlock(); } +try_to_free_t old_try_to_free_routine; + /* * The main thread waits on the condition that (at least) one of the workers * has stopped working (which is indicated in the .working member of @@ -1563,12 +1565,12 @@ static void init_threaded_search(void) pthread_mutex_init(&cache_mutex, NULL); pthread_mutex_init(&progress_mutex, NULL); pthread_cond_init(&progress_cond, NULL); - set_try_to_free_routine(try_to_free_from_threads); + old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads); } static void cleanup_threaded_search(void) { - set_try_to_free_routine(NULL); + set_try_to_free_routine(old_try_to_free_routine); pthread_cond_destroy(&progress_cond); pthread_mutex_destroy(&read_mutex); pthread_mutex_destroy(&cache_mutex); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index bb34757d2..d634b5a3d 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,7 +17,7 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE, + DENY_REFUSE }; static int deny_deletes; @@ -501,7 +501,7 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) if (!(flag & REF_ISSYMREF)) return; - if ((item = string_list_lookup(dst_name, list)) == NULL) + if ((item = string_list_lookup(list, dst_name)) == NULL) return; cmd->skip_update = 1; @@ -515,9 +515,9 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) dst_cmd->skip_update = 1; strcpy(cmd_oldh, find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV)); - strcat(cmd_newh, find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV)); + strcpy(cmd_newh, find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV)); strcpy(dst_oldh, find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV)); - strcat(dst_newh, find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV)); + strcpy(dst_newh, find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV)); rp_error("refusing inconsistent update between symref '%s' (%s..%s) and" " its target '%s' (%s..%s)", cmd->ref_name, cmd_oldh, cmd_newh, @@ -534,7 +534,7 @@ static void check_aliased_updates(struct command *commands) for (cmd = commands; cmd; cmd = cmd->next) { struct string_list_item *item = - string_list_append(cmd->ref_name, &ref_list); + string_list_append(&ref_list, cmd->ref_name); item->util = (void *)cmd; } sort_string_list(&ref_list); diff --git a/builtin/remote.c b/builtin/remote.c index 0e99a9957..6699bc571 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -16,6 +16,7 @@ static const char * const builtin_remote_usage[] = { "git remote [-v | --verbose] show [-n] <name>", "git remote prune [-n | --dry-run] <name>", "git remote [-v | --verbose] update [-p | --prune] [group | remote]", + "git remote set-branches <name> [--add] <branch>...", "git remote set-url <name> <newurl> [<oldurl>]", "git remote set-url --add <name> <newurl>", "git remote set-url --delete <name> <url>", @@ -42,6 +43,12 @@ static const char * const builtin_remote_sethead_usage[] = { NULL }; +static const char * const builtin_remote_setbranches_usage[] = { + "git remote set-branches <name> <branch>...", + "git remote set-branches --add <name> <branch>...", + NULL +}; + static const char * const builtin_remote_show_usage[] = { "git remote show [<options>] <name>", NULL @@ -87,7 +94,7 @@ static int opt_parse_track(const struct option *opt, const char *arg, int not) if (not) string_list_clear(list, 0); else - string_list_append(arg, list); + string_list_append(list, arg); return 0; } @@ -110,6 +117,20 @@ enum { TAGS_SET = 2 }; +static int add_branch(const char *key, const char *branchname, + const char *remotename, int mirror, struct strbuf *tmp) +{ + strbuf_reset(tmp); + strbuf_addch(tmp, '+'); + if (mirror) + strbuf_addf(tmp, "refs/%s:refs/%s", + branchname, branchname); + else + strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s", + branchname, remotename, branchname); + return git_config_set_multivar(key, tmp->buf, "^$", 0); +} + static int add(int argc, const char **argv) { int fetch = 0, mirror = 0, fetch_tags = TAGS_DEFAULT; @@ -160,19 +181,10 @@ static int add(int argc, const char **argv) strbuf_addf(&buf, "remote.%s.fetch", name); if (track.nr == 0) - string_list_append("*", &track); + string_list_append(&track, "*"); for (i = 0; i < track.nr; i++) { - struct string_list_item *item = track.items + i; - - strbuf_reset(&buf2); - strbuf_addch(&buf2, '+'); - if (mirror) - strbuf_addf(&buf2, "refs/%s:refs/%s", - item->string, item->string); - else - strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s", - item->string, name, item->string); - if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0)) + if (add_branch(buf.buf, track.items[i].string, + name, mirror, &buf2)) return 1; } @@ -251,7 +263,7 @@ static int config_read_branches(const char *key, const char *value, void *cb) } else return 0; - item = string_list_insert(name, &branch_list); + item = string_list_insert(&branch_list, name); if (!item->util) item->util = xcalloc(sizeof(struct branch_info), 1); @@ -266,11 +278,11 @@ static int config_read_branches(const char *key, const char *value, void *cb) while (space) { char *merge; merge = xstrndup(value, space - value); - string_list_append(merge, &info->merge); + string_list_append(&info->merge, merge); value = abbrev_branch(space + 1); space = strchr(value, ' '); } - string_list_append(xstrdup(value), &info->merge); + string_list_append(&info->merge, xstrdup(value)); } else info->rebase = git_config_bool(orig_key, value); } @@ -307,14 +319,14 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat for (ref = fetch_map; ref; ref = ref->next) { unsigned char sha1[20]; if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1)) - string_list_append(abbrev_branch(ref->name), &states->new); + string_list_append(&states->new, abbrev_branch(ref->name)); else - string_list_append(abbrev_branch(ref->name), &states->tracked); + string_list_append(&states->tracked, abbrev_branch(ref->name)); } stale_refs = get_stale_heads(states->remote, fetch_map); for (ref = stale_refs; ref; ref = ref->next) { struct string_list_item *item = - string_list_append(abbrev_branch(ref->name), &states->stale); + string_list_append(&states->stale, abbrev_branch(ref->name)); item->util = xstrdup(ref->name); } free_refs(stale_refs); @@ -336,7 +348,7 @@ struct push_info { PUSH_STATUS_UPTODATE, PUSH_STATUS_FASTFORWARD, PUSH_STATUS_OUTOFDATE, - PUSH_STATUS_NOTQUERIED, + PUSH_STATUS_NOTQUERIED } status; }; @@ -363,8 +375,8 @@ static int get_push_ref_states(const struct ref *remote_refs, continue; hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); - item = string_list_append(abbrev_branch(ref->peer_ref->name), - &states->push); + item = string_list_append(&states->push, + abbrev_branch(ref->peer_ref->name)); item->util = xcalloc(sizeof(struct push_info), 1); info = item->util; info->forced = ref->force; @@ -399,7 +411,7 @@ static int get_push_ref_states_noquery(struct ref_states *states) states->push.strdup_strings = 1; if (!remote->push_refspec_nr) { - item = string_list_append("(matching)", &states->push); + item = string_list_append(&states->push, "(matching)"); info = item->util = xcalloc(sizeof(struct push_info), 1); info->status = PUSH_STATUS_NOTQUERIED; info->dest = xstrdup(item->string); @@ -407,11 +419,11 @@ static int get_push_ref_states_noquery(struct ref_states *states) for (i = 0; i < remote->push_refspec_nr; i++) { struct refspec *spec = remote->push + i; if (spec->matching) - item = string_list_append("(matching)", &states->push); + item = string_list_append(&states->push, "(matching)"); else if (strlen(spec->src)) - item = string_list_append(spec->src, &states->push); + item = string_list_append(&states->push, spec->src); else - item = string_list_append("(delete)", &states->push); + item = string_list_append(&states->push, "(delete)"); info = item->util = xcalloc(sizeof(struct push_info), 1); info->forced = spec->force; @@ -435,7 +447,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), fetch_map, 1); for (ref = matches; ref; ref = ref->next) - string_list_append(abbrev_branch(ref->name), &states->heads); + string_list_append(&states->heads, abbrev_branch(ref->name)); free_refs(fetch_map); free_refs(matches); @@ -499,8 +511,8 @@ static int add_branch_for_removal(const char *refname, if (prefixcmp(refname, "refs/remotes")) { /* advise user how to delete local branches */ if (!prefixcmp(refname, "refs/heads/")) - string_list_append(abbrev_branch(refname), - branches->skipped); + string_list_append(branches->skipped, + abbrev_branch(refname)); /* silently skip over other non-remote refs */ return 0; } @@ -509,7 +521,7 @@ static int add_branch_for_removal(const char *refname, if (flags & REF_ISSYMREF) return unlink(git_path("%s", refname)); - item = string_list_append(refname, branches->branches); + item = string_list_append(branches->branches, refname); item->util = xmalloc(20); hashcpy(item->util, sha1); @@ -534,7 +546,7 @@ static int read_remote_branches(const char *refname, strbuf_addf(&buf, "refs/remotes/%s", rename->old); if (!prefixcmp(refname, buf.buf)) { - item = string_list_append(xstrdup(refname), rename->remote_branches); + item = string_list_append(rename->remote_branches, xstrdup(refname)); symref = resolve_ref(refname, orig_sha1, 1, &flag); if (flag & REF_ISSYMREF) item->util = xstrdup(symref); @@ -724,11 +736,14 @@ static int rm(int argc, const char **argv) struct known_remotes known_remotes = { NULL, NULL }; struct string_list branches = { NULL, 0, 0, 1 }; struct string_list skipped = { NULL, 0, 0, 1 }; - struct branches_for_remote cb_data = { - NULL, &branches, &skipped, &known_remotes - }; + struct branches_for_remote cb_data; int i, result; + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.branches = &branches; + cb_data.skipped = &skipped; + cb_data.keep = &known_remotes; + if (argc != 2) usage_with_options(builtin_remote_rm_usage, options); @@ -817,7 +832,7 @@ static int append_ref_to_tracked_list(const char *refname, memset(&refspec, 0, sizeof(refspec)); refspec.dst = (char *)refname; if (!remote_find_tracking(states->remote, &refspec)) - string_list_append(abbrev_branch(refspec.src), &states->tracked); + string_list_append(&states->tracked, abbrev_branch(refspec.src)); return 0; } @@ -870,7 +885,7 @@ static int add_remote_to_show_info(struct string_list_item *item, void *cb_data) int n = strlen(item->string); if (n > info->width) info->width = n; - string_list_insert(item->string, info->list); + string_list_insert(info->list, item->string); return 0; } @@ -917,7 +932,7 @@ static int add_local_to_show_info(struct string_list_item *branch_item, void *cb if (branch_info->rebase) show_info->any_rebase = 1; - item = string_list_insert(branch_item->string, show_info->list); + item = string_list_insert(show_info->list, branch_item->string); item->util = branch_info; return 0; @@ -965,7 +980,7 @@ static int add_push_to_show_info(struct string_list_item *push_item, void *cb_da show_info->width = n; if ((n = strlen(push_info->dest)) > show_info->width2) show_info->width2 = n; - item = string_list_append(push_item->string, show_info->list); + item = string_list_append(show_info->list, push_item->string); item->util = push_item->util; return 0; } @@ -1081,24 +1096,24 @@ static int show(int argc, const char **argv) /* remote branch info */ info.width = 0; - for_each_string_list(add_remote_to_show_info, &states.new, &info); - for_each_string_list(add_remote_to_show_info, &states.tracked, &info); - for_each_string_list(add_remote_to_show_info, &states.stale, &info); + for_each_string_list(&states.new, add_remote_to_show_info, &info); + for_each_string_list(&states.tracked, add_remote_to_show_info, &info); + for_each_string_list(&states.stale, add_remote_to_show_info, &info); if (info.list->nr) printf(" Remote branch%s:%s\n", info.list->nr > 1 ? "es" : "", no_query ? " (status not queried)" : ""); - for_each_string_list(show_remote_info_item, info.list, &info); + for_each_string_list(info.list, show_remote_info_item, &info); string_list_clear(info.list, 0); /* git pull info */ info.width = 0; info.any_rebase = 0; - for_each_string_list(add_local_to_show_info, &branch_list, &info); + for_each_string_list(&branch_list, add_local_to_show_info, &info); if (info.list->nr) printf(" Local branch%s configured for 'git pull':\n", info.list->nr > 1 ? "es" : ""); - for_each_string_list(show_local_info_item, info.list, &info); + for_each_string_list(info.list, show_local_info_item, &info); string_list_clear(info.list, 0); /* git push info */ @@ -1106,14 +1121,14 @@ static int show(int argc, const char **argv) printf(" Local refs will be mirrored by 'git push'\n"); info.width = info.width2 = 0; - for_each_string_list(add_push_to_show_info, &states.push, &info); + for_each_string_list(&states.push, add_push_to_show_info, &info); qsort(info.list->items, info.list->nr, sizeof(*info.list->items), cmp_string_with_push); if (info.list->nr) printf(" Local ref%s configured for 'git push'%s:\n", info.list->nr > 1 ? "s" : "", no_query ? " (status not queried)" : ""); - for_each_string_list(show_push_info_item, info.list, &info); + for_each_string_list(info.list, show_push_info_item, &info); string_list_clear(info.list, 0); free_remote_ref_states(&states); @@ -1284,6 +1299,72 @@ static int update(int argc, const char **argv) return run_command_v_opt(fetch_argv, RUN_GIT_CMD); } +static int remove_all_fetch_refspecs(const char *remote, const char *key) +{ + return git_config_set_multivar(key, NULL, NULL, 1); +} + +static int add_branches(struct remote *remote, const char **branches, + const char *key) +{ + const char *remotename = remote->name; + int mirror = remote->mirror; + struct strbuf refspec = STRBUF_INIT; + + for (; *branches; branches++) + if (add_branch(key, *branches, remotename, mirror, &refspec)) { + strbuf_release(&refspec); + return 1; + } + + strbuf_release(&refspec); + return 0; +} + +static int set_remote_branches(const char *remotename, const char **branches, + int add_mode) +{ + struct strbuf key = STRBUF_INIT; + struct remote *remote; + + strbuf_addf(&key, "remote.%s.fetch", remotename); + + if (!remote_is_configured(remotename)) + die("No such remote '%s'", remotename); + remote = remote_get(remotename); + + if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) { + strbuf_release(&key); + return 1; + } + if (add_branches(remote, branches, key.buf)) { + strbuf_release(&key); + return 1; + } + + strbuf_release(&key); + return 0; +} + +static int set_branches(int argc, const char **argv) +{ + int add_mode = 0; + struct option options[] = { + OPT_BOOLEAN('\0', "add", &add_mode, "add branch"), + OPT_END() + }; + + argc = parse_options(argc, argv, NULL, options, + builtin_remote_setbranches_usage, 0); + if (argc == 0) { + error("no remote specified"); + usage_with_options(builtin_remote_seturl_usage, options); + } + argv[argc] = NULL; + + return set_remote_branches(argv[0], argv + 1, add_mode); +} + static int set_url(int argc, const char **argv) { int i, push_mode = 0, add_mode = 0, delete_mode = 0; @@ -1379,10 +1460,10 @@ static int get_one_entry(struct remote *remote, void *priv) if (remote->url_nr > 0) { strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]); - string_list_append(remote->name, list)->util = + string_list_append(list, remote->name)->util = strbuf_detach(&url_buf, NULL); } else - string_list_append(remote->name, list)->util = NULL; + string_list_append(list, remote->name)->util = NULL; if (remote->pushurl_nr) { url = remote->pushurl; url_nr = remote->pushurl_nr; @@ -1393,7 +1474,7 @@ static int get_one_entry(struct remote *remote, void *priv) for (i = 0; i < url_nr; i++) { strbuf_addf(&url_buf, "%s (push)", url[i]); - string_list_append(remote->name, list)->util = + string_list_append(list, remote->name)->util = strbuf_detach(&url_buf, NULL); } @@ -1449,6 +1530,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix) result = rm(argc, argv); else if (!strcmp(argv[0], "set-head")) result = set_head(argc, argv); + else if (!strcmp(argv[0], "set-branches")) + result = set_branches(argc, argv); else if (!strcmp(argv[0], "set-url")) result = set_url(argc, argv); else if (!strcmp(argv[0], "show")) diff --git a/builtin/rerere.c b/builtin/rerere.c index 34f9acee9..980d5421e 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -59,7 +59,7 @@ static void garbage_collect(struct string_list *rr) cutoff = (has_rerere_resolution(e->d_name) ? cutoff_resolve : cutoff_noresolve); if (then < now - cutoff * 86400) - string_list_append(e->d_name, &to_remove); + string_list_append(&to_remove, e->d_name); } for (i = 0; i < to_remove.nr; i++) unlink_rr_item(to_remove.items[i].string); @@ -89,7 +89,7 @@ static int diff_two(const char *file1, const char *label1, printf("--- a/%s\n+++ b/%s\n", label1, label2); fflush(stdout); memset(&xpp, 0, sizeof(xpp)); - xpp.flags = XDF_NEED_MINIMAL; + xpp.flags = 0; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; ecb.outf = outf; diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 51ceb19d8..efe9360e2 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -50,6 +50,15 @@ static void show_commit(struct commit *commit, void *data) graph_show_commit(revs->graph); + if (revs->count) { + if (commit->object.flags & SYMMETRIC_LEFT) + revs->count_left++; + else + revs->count_right++; + finish_commit(commit, data); + return; + } + if (info->show_timestamp) printf("%lu ", commit->date); if (info->header_prefix) @@ -400,5 +409,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) quiet ? finish_object : show_object, &info); + if (revs.count) { + if (revs.left_right) + printf("%d\t%d\n", revs.count_left, revs.count_right); + else + printf("%d\n", revs.count_left + revs.count_right); + } + return 0; } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 8fbf9d0db..b676e2963 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -408,7 +408,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) memset(opts + onb, 0, sizeof(opts[onb])); argc = parse_options(argc, argv, prefix, opts, usage, keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0 | - stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0); + stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0 | + PARSE_OPT_SHELL_EVAL); strbuf_addf(&parsed, " --"); sq_quote_argv(&parsed, argv, 0); diff --git a/builtin/revert.c b/builtin/revert.c index 7976b5a32..853e9e406 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -39,7 +39,8 @@ static const char * const cherry_pick_usage[] = { static int edit, no_replay, no_commit, mainline, signoff, allow_ff; static enum { REVERT, CHERRY_PICK } action; static struct commit *commit; -static const char *commit_name; +static int commit_argc; +static const char **commit_argv; static int allow_rerere_auto; static const char *me; @@ -53,12 +54,10 @@ static void parse_args(int argc, const char **argv) { const char * const * usage_str = action == REVERT ? revert_usage : cherry_pick_usage; - unsigned char sha1[20]; int noop; struct option options[] = { OPT_BOOLEAN('n', "no-commit", &no_commit, "don't automatically commit"), OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"), - OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"), OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"), OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"), OPT_INTEGER('m', "mainline", &mainline, "parent number"), @@ -71,6 +70,7 @@ static void parse_args(int argc, const char **argv) if (action == CHERRY_PICK) { struct option cp_extra[] = { + OPT_BOOLEAN('x', NULL, &no_replay, "append commit name"), OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"), OPT_END(), }; @@ -78,15 +78,11 @@ static void parse_args(int argc, const char **argv) die("program error"); } - if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1) + commit_argc = parse_options(argc, argv, NULL, options, usage_str, 0); + if (commit_argc < 1) usage_with_options(usage_str, options); - commit_name = argv[0]; - if (get_sha1(commit_name, sha1)) - die ("Cannot find '%s'", commit_name); - commit = lookup_commit_reference(sha1); - if (!commit) - exit(1); + commit_argv = argv; } struct commit_message { @@ -239,7 +235,7 @@ static void set_author_ident_env(const char *message) sha1_to_hex(commit->object.sha1)); } -static char *help_msg(const char *name) +static char *help_msg(void) { struct strbuf helpbuf = STRBUF_INIT; char *msg = getenv("GIT_CHERRY_PICK_HELP"); @@ -255,7 +251,7 @@ static char *help_msg(const char *name) strbuf_addf(&helpbuf, " with: \n" "\n" " git commit -c %s\n", - name); + sha1_to_hex(commit->object.sha1)); } else strbuf_addch(&helpbuf, '.'); @@ -357,7 +353,7 @@ static void do_recursive_merge(struct commit *base, struct commit *next, } write_message(msgbuf, defmsg); fprintf(stderr, "Automatic %s failed.%s\n", - me, help_msg(commit_name)); + me, help_msg()); rerere(allow_rerere_auto); exit(1); } @@ -365,7 +361,7 @@ static void do_recursive_merge(struct commit *base, struct commit *next, fprintf(stderr, "Finished one %s.\n", me); } -static int revert_or_cherry_pick(int argc, const char **argv) +static int do_pick_commit(void) { unsigned char head[20]; struct commit *base, *next, *parent; @@ -374,28 +370,6 @@ static int revert_or_cherry_pick(int argc, const char **argv) char *defmsg = NULL; struct strbuf msgbuf = STRBUF_INIT; - git_config(git_default_config, NULL); - me = action == REVERT ? "revert" : "cherry-pick"; - setenv(GIT_REFLOG_ACTION, me, 0); - parse_args(argc, argv); - - /* this is copied from the shell script, but it's never triggered... */ - if (action == REVERT && !no_replay) - die("revert is incompatible with replay"); - - if (allow_ff) { - if (signoff) - die("cherry-pick --ff cannot be used with --signoff"); - if (no_commit) - die("cherry-pick --ff cannot be used with --no-commit"); - if (no_replay) - die("cherry-pick --ff cannot be used with -x"); - if (edit) - die("cherry-pick --ff cannot be used with --edit"); - } - - if (read_cache() < 0) - die("git %s: failed to read the index", me); if (no_commit) { /* * We do not intend to commit immediately. We just want to @@ -506,12 +480,14 @@ static int revert_or_cherry_pick(int argc, const char **argv) free_commit_list(remotes); if (res) { fprintf(stderr, "Automatic %s with strategy %s failed.%s\n", - me, strategy, help_msg(commit_name)); + me, strategy, help_msg()); rerere(allow_rerere_auto); exit(1); } } + free_message(&msg); + /* * * If we are cherry-pick, and if the merge did not result in @@ -524,7 +500,9 @@ static int revert_or_cherry_pick(int argc, const char **argv) if (!no_commit) { /* 6 is max possible length of our args array including NULL */ const char *args[6]; + int res; int i = 0; + args[i++] = "commit"; args[i++] = "-n"; if (signoff) @@ -534,26 +512,86 @@ static int revert_or_cherry_pick(int argc, const char **argv) args[i++] = defmsg; } args[i] = NULL; - return execv_git_cmd(args); + res = run_command_v_opt(args, RUN_GIT_CMD); + free(defmsg); + + return res; } - free_message(&msg); + free(defmsg); return 0; } +static void prepare_revs(struct rev_info *revs) +{ + int argc = 0; + int i; + const char **argv = xmalloc((commit_argc + 4) * sizeof(*argv)); + + argv[argc++] = NULL; + argv[argc++] = "--no-walk"; + if (action != REVERT) + argv[argc++] = "--reverse"; + for (i = 0; i < commit_argc; i++) + argv[argc++] = commit_argv[i]; + argv[argc++] = NULL; + + init_revisions(revs, NULL); + setup_revisions(argc - 1, argv, revs, NULL); + if (prepare_revision_walk(revs)) + die("revision walk setup failed"); + + if (!revs->commits) + die("empty commit set passed"); + + free(argv); +} + +static int revert_or_cherry_pick(int argc, const char **argv) +{ + struct rev_info revs; + + git_config(git_default_config, NULL); + me = action == REVERT ? "revert" : "cherry-pick"; + setenv(GIT_REFLOG_ACTION, me, 0); + parse_args(argc, argv); + + if (allow_ff) { + if (signoff) + die("cherry-pick --ff cannot be used with --signoff"); + if (no_commit) + die("cherry-pick --ff cannot be used with --no-commit"); + if (no_replay) + die("cherry-pick --ff cannot be used with -x"); + if (edit) + die("cherry-pick --ff cannot be used with --edit"); + } + + if (read_cache() < 0) + die("git %s: failed to read the index", me); + + prepare_revs(&revs); + + while ((commit = get_revision(&revs))) { + int res = do_pick_commit(); + if (res) + return res; + } + + return 0; +} + int cmd_revert(int argc, const char **argv, const char *prefix) { if (isatty(0)) edit = 1; - no_replay = 1; action = REVERT; return revert_or_cherry_pick(argc, argv); } int cmd_cherry_pick(int argc, const char **argv, const char *prefix) { - no_replay = 0; action = CHERRY_PICK; return revert_or_cherry_pick(argc, argv); } diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 508950280..0a9681ba7 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -84,7 +84,7 @@ static void insert_one_record(struct shortlog *log, snprintf(namebuf + len, room, " <%.*s>", maillen, emailbuf); } - item = string_list_insert(namebuf, &log->list); + item = string_list_insert(&log->list, namebuf); if (item->util == NULL) item->util = xcalloc(1, sizeof(struct string_list)); @@ -115,7 +115,7 @@ static void insert_one_record(struct shortlog *log, } } - string_list_append(buffer, item->util); + string_list_append(item->util, buffer); } static void read_from_stdin(struct shortlog *log) diff --git a/builtin/show-branch.c b/builtin/show-branch.c index e20fcf3e9..e8719aa9e 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -313,7 +313,8 @@ static void show_one_commit(struct commit *commit, int no_name) } else printf("[%s] ", - find_unique_abbrev(commit->object.sha1, 7)); + find_unique_abbrev(commit->object.sha1, + DEFAULT_ABBREV)); } puts(pretty_str); strbuf_release(&pretty); diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 17ada88df..0b2a9ad1a 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -105,7 +105,7 @@ match: static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata) { struct string_list *list = (struct string_list *)cbdata; - string_list_insert(refname, list); + string_list_insert(list, refname); return 0; } |