diff options
Diffstat (limited to 'builtin')
| -rw-r--r-- | builtin/apply.c | 17 | ||||
| -rw-r--r-- | builtin/blame.c | 4 | ||||
| -rw-r--r-- | builtin/checkout.c | 3 | ||||
| -rw-r--r-- | builtin/clone.c | 6 | ||||
| -rw-r--r-- | builtin/commit.c | 15 | ||||
| -rw-r--r-- | builtin/describe.c | 49 | ||||
| -rw-r--r-- | builtin/fast-export.c | 2 | ||||
| -rw-r--r-- | builtin/fetch.c | 8 | ||||
| -rw-r--r-- | builtin/fmt-merge-msg.c | 159 | ||||
| -rw-r--r-- | builtin/for-each-ref.c | 4 | ||||
| -rw-r--r-- | builtin/grep.c | 17 | ||||
| -rw-r--r-- | builtin/index-pack.c | 91 | ||||
| -rw-r--r-- | builtin/init-db.c | 2 | ||||
| -rw-r--r-- | builtin/log.c | 54 | ||||
| -rw-r--r-- | builtin/ls-files.c | 7 | ||||
| -rw-r--r-- | builtin/ls-tree.c | 6 | ||||
| -rw-r--r-- | builtin/mailinfo.c | 3 | ||||
| -rw-r--r-- | builtin/merge-file.c | 8 | ||||
| -rw-r--r-- | builtin/merge-tree.c | 2 | ||||
| -rw-r--r-- | builtin/merge.c | 2 | ||||
| -rw-r--r-- | builtin/notes.c | 532 | ||||
| -rw-r--r-- | builtin/pack-objects.c | 13 | ||||
| -rw-r--r-- | builtin/push.c | 2 | ||||
| -rw-r--r-- | builtin/reflog.c | 2 | ||||
| -rw-r--r-- | builtin/rerere.c | 2 | ||||
| -rw-r--r-- | builtin/reset.c | 3 | ||||
| -rw-r--r-- | builtin/rev-list.c | 7 | ||||
| -rw-r--r-- | builtin/revert.c | 150 | ||||
| -rw-r--r-- | builtin/shortlog.c | 3 | ||||
| -rw-r--r-- | builtin/show-branch.c | 3 | ||||
| -rw-r--r-- | builtin/tag.c | 4 |
31 files changed, 752 insertions, 428 deletions
diff --git a/builtin/apply.c b/builtin/apply.c index 65a594c985..59bbcdb132 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -1864,13 +1864,13 @@ static int match_fragment(struct image *img, if (match_end && (preimage->nr + try_lno != img->nr)) return 0; } else if (ws_error_action == correct_ws_error && - (ws_rule & WS_BLANK_AT_EOF) && match_end) { + (ws_rule & WS_BLANK_AT_EOF)) { /* - * This hunk that matches at the end extends beyond - * the end of img, and we are removing blank lines - * at the end of the file. This many lines from the - * beginning of the preimage must match with img, and - * the remainder of the preimage must be blank. + * This hunk extends beyond the end of img, and we are + * removing blank lines at the end of the file. This + * many lines from the beginning of the preimage must + * match with img, and the remainder of the preimage + * must be blank. */ preimage_limit = img->nr - try_lno; } else { @@ -2824,11 +2824,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s if (stat_ret < 0) { struct checkout costate; /* checkout */ + memset(&costate, 0, sizeof(costate)); costate.base_dir = ""; - costate.base_dir_len = 0; - costate.force = 0; - costate.quiet = 0; - costate.not_new = 0; costate.refresh_cache = 1; if (checkout_entry(*ce, &costate, NULL) || lstat(old_name, st)) diff --git a/builtin/blame.c b/builtin/blame.c index fc1586350f..8506286dd2 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -39,7 +39,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; @@ -1589,7 +1589,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); diff --git a/builtin/checkout.c b/builtin/checkout.c index acefaaf41a..88b1f43e05 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -149,7 +149,7 @@ static int checkout_merged(int pos, struct checkout *state) read_mmblob(&ours, active_cache[pos+1]->sha1); read_mmblob(&theirs, active_cache[pos+2]->sha1); - status = ll_merge(&result_buf, path, &ancestor, + status = ll_merge(&result_buf, path, &ancestor, "base", &ours, "ours", &theirs, "theirs", 0); free(ancestor.ptr); free(ours.ptr); @@ -439,6 +439,7 @@ static int merge_working_tree(struct checkout_opts *opts, ret = reset_tree(new->commit->tree, opts, 1); if (ret) return ret; + o.ancestor = old->name; o.branch1 = new->name; o.branch2 = "local"; merge_trees(&o, new->commit->tree, work, diff --git a/builtin/clone.c b/builtin/clone.c index 05f8fb4771..0bedde41f0 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -302,6 +302,8 @@ static const struct ref *clone_local(const char *src_repo, transport = transport_get(remote, src_repo); ret = transport_get_remote_refs(transport); transport_disconnect(transport); + if (0 <= option_verbosity) + printf("done.\n"); return ret; } @@ -461,7 +463,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) die("could not create leading directories of '%s'", git_dir); set_git_dir(make_absolute_path(git_dir)); - init_db(option_template, (option_verbosity < 0) ? INIT_DB_QUIET : 0); + if (0 <= option_verbosity) + printf("Cloning into %s...\n", get_git_dir()); + init_db(option_template, INIT_DB_QUIET); /* * At this point, the config exists, so we do not need the diff --git a/builtin/commit.c b/builtin/commit.c index 8dd104ee0b..3c14ade9dd 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -307,7 +307,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int * (B) on failure, rollback the real index. */ if (all || (also && pathspec && *pathspec)) { - int fd = hold_locked_index(&index_lock, 1); + fd = hold_locked_index(&index_lock, 1); add_files_to_cache(also ? prefix : NULL, pathspec, 0); refresh_cache_or_die(refresh_flags); if (write_cache(fd, active_cache, active_nr) || @@ -322,8 +322,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int * * (1) return the name of the real index file. * - * The caller should run hooks on the real index, and run - * hooks on the real index, and create commit from the_index. + * The caller should run hooks on the real index, + * and create commit from the_index. * We still need to refresh the index here. */ if (!pathspec || !*pathspec) { @@ -1017,6 +1017,7 @@ static int git_status_config(const char *k, const char *v, void *cb) int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; + int fd; unsigned char sha1[20]; static struct option builtin_status_options[] = { OPT__VERBOSE(&verbose), @@ -1050,6 +1051,14 @@ int cmd_status(int argc, const char **argv, const char *prefix) read_cache_preload(s.pathspec); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL); + + fd = hold_locked_index(&index_lock, 0); + if (0 <= fd) { + if (!write_cache(fd, active_cache, active_nr)) + commit_locked_index(&index_lock); + rollback_lock_file(&index_lock); + } + s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; s.in_merge = in_merge; wt_status_collect(&s); diff --git a/builtin/describe.c b/builtin/describe.c index 71be2a9364..43caff2ffe 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -35,7 +35,8 @@ static const char *diff_index_args[] = { struct commit_name { struct tag *tag; - int prio; /* annotated tag = 2, tag = 1, head = 0 */ + unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */ + unsigned name_checked:1; unsigned char sha1[20]; char path[FLEX_ARRAY]; /* more */ }; @@ -43,18 +44,53 @@ static const char *prio_names[] = { "head", "lightweight", "annotated", }; +static int replace_name(struct commit_name *e, + int prio, + const unsigned char *sha1, + struct tag **tag) +{ + if (!e || e->prio < prio) + return 1; + + if (e->prio == 2 && prio == 2) { + /* Multiple annotated tags point to the same commit. + * Select one to keep based upon their tagger date. + */ + struct tag *t; + + if (!e->tag) { + t = lookup_tag(e->sha1); + if (!t || parse_tag(t)) + return 1; + e->tag = t; + } + + t = lookup_tag(sha1); + if (!t || parse_tag(t)) + return 0; + *tag = t; + + if (e->tag->date < t->date) + return 1; + } + + return 0; +} + static void add_to_known_names(const char *path, struct commit *commit, int prio, const unsigned char *sha1) { struct commit_name *e = commit->util; - if (!e || e->prio < prio) { + struct tag *tag = NULL; + if (replace_name(e, prio, sha1, &tag)) { size_t len = strlen(path)+1; free(e); e = xmalloc(sizeof(struct commit_name) + len); - e->tag = NULL; + e->tag = tag; e->prio = prio; + e->name_checked = 0; hashcpy(e->sha1, sha1); memcpy(e->path, path, len); commit->util = e; @@ -165,10 +201,15 @@ static void display_name(struct commit_name *n) { if (n->prio == 2 && !n->tag) { n->tag = lookup_tag(n->sha1); - if (!n->tag || parse_tag(n->tag) || !n->tag->tag) + if (!n->tag || parse_tag(n->tag)) die("annotated tag %s not available", n->path); + } + if (n->tag && !n->name_checked) { + if (!n->tag->tag) + die("annotated tag %s has no embedded name", n->path); if (strcmp(n->tag->tag, all ? n->path + 5 : n->path)) warning("tag '%s' is really '%s' here", n->tag->tag, n->path); + n->name_checked = 1; } if (n->tag) diff --git a/builtin/fast-export.c b/builtin/fast-export.c index b0a4029c94..c6dd71a7bc 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -503,7 +503,7 @@ static void export_marks(char *file) f = fopen(file, "w"); if (!f) - error("Unable to open marks file %s for writing.", file); + die_errno("Unable to open marks file %s for writing.", file); for (i = 0; i < idnums.size; i++) { if (deco->base && deco->base->type == 1) { diff --git a/builtin/fetch.c b/builtin/fetch.c index 957be9f926..8470850415 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -14,10 +14,10 @@ #include "transport.h" static const char * const builtin_fetch_usage[] = { - "git fetch [options] [<repository> <refspec>...]", - "git fetch [options] <group>", - "git fetch --multiple [options] [<repository> | <group>]...", - "git fetch --all [options]", + "git fetch [<options>] [<repository> [<refspec>...]]", + "git fetch [<options>] <group>", + "git fetch --multiple [<options>] [<repository> | <group>]...", + "git fetch --all [<options>]", NULL }; diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 9d524000b5..379a03131f 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -4,6 +4,7 @@ #include "diff.h" #include "revision.h" #include "tag.h" +#include "string-list.h" static const char * const fmt_merge_msg_usage[] = { "git fmt-merge-msg [--log|--no-log] [--file <file>]", @@ -24,58 +25,21 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb) return 0; } -struct list { - char **list; - void **payload; - unsigned nr, alloc; +struct src_data { + struct string_list branch, tag, r_branch, generic; + int head_status; }; -static void append_to_list(struct list *list, char *value, void *payload) -{ - if (list->nr == list->alloc) { - list->alloc += 32; - list->list = xrealloc(list->list, sizeof(char *) * list->alloc); - list->payload = xrealloc(list->payload, - sizeof(char *) * list->alloc); - } - list->payload[list->nr] = payload; - list->list[list->nr++] = value; -} - -static int find_in_list(struct list *list, char *value) -{ - int i; - - for (i = 0; i < list->nr; i++) - if (!strcmp(list->list[i], value)) - return i; - - return -1; -} - -static void free_list(struct list *list) +void init_src_data(struct src_data *data) { - int i; - - if (list->alloc == 0) - return; - - for (i = 0; i < list->nr; i++) { - free(list->list[i]); - free(list->payload[i]); - } - free(list->list); - free(list->payload); - list->nr = list->alloc = 0; + data->branch.strdup_strings = 1; + data->tag.strdup_strings = 1; + data->r_branch.strdup_strings = 1; + data->generic.strdup_strings = 1; } -struct src_data { - struct list branch, tag, r_branch, generic; - int head_status; -}; - -static struct list srcs = { NULL, NULL, 0, 0}; -static struct list origins = { NULL, NULL, 0, 0}; +static struct string_list srcs = { NULL, 0, 0, 1 }; +static struct string_list origins = { NULL, 0, 0, 1 }; static int handle_line(char *line) { @@ -83,6 +47,7 @@ static int handle_line(char *line) unsigned char *sha1; char *src, *origin; struct src_data *src_data; + struct string_list_item *item; int pulling_head = 0; if (len < 43 || line[40] != '\t') @@ -115,64 +80,62 @@ static int handle_line(char *line) pulling_head = 1; } - i = find_in_list(&srcs, src); - if (i < 0) { - i = srcs.nr; - append_to_list(&srcs, xstrdup(src), - xcalloc(1, sizeof(struct src_data))); + item = unsorted_string_list_lookup(&srcs, src); + if (!item) { + item = string_list_append(src, &srcs); + item->util = xcalloc(1, sizeof(struct src_data)); + init_src_data(item->util); } - src_data = srcs.payload[i]; + src_data = item->util; if (pulling_head) { - origin = xstrdup(src); + origin = src; src_data->head_status |= 1; } else if (!prefixcmp(line, "branch ")) { - origin = xstrdup(line + 7); - append_to_list(&src_data->branch, origin, NULL); + origin = line + 7; + string_list_append(origin, &src_data->branch); src_data->head_status |= 2; } else if (!prefixcmp(line, "tag ")) { origin = line; - append_to_list(&src_data->tag, xstrdup(origin + 4), NULL); + string_list_append(origin + 4, &src_data->tag); src_data->head_status |= 2; } else if (!prefixcmp(line, "remote branch ")) { - origin = xstrdup(line + 14); - append_to_list(&src_data->r_branch, origin, NULL); + origin = line + 14; + string_list_append(origin, &src_data->r_branch); src_data->head_status |= 2; } else { - origin = xstrdup(src); - append_to_list(&src_data->generic, xstrdup(line), NULL); + origin = src; + string_list_append(line, &src_data->generic); src_data->head_status |= 2; } if (!strcmp(".", src) || !strcmp(src, origin)) { int len = strlen(origin); - if (origin[0] == '\'' && origin[len - 1] == '\'') { + if (origin[0] == '\'' && origin[len - 1] == '\'') origin = xmemdupz(origin + 1, len - 2); - } else { - origin = xstrdup(origin); - } } else { char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5); sprintf(new_origin, "%s of %s", origin, src); origin = new_origin; } - append_to_list(&origins, origin, sha1); + string_list_append(origin, &origins)->util = sha1; return 0; } static void print_joined(const char *singular, const char *plural, - struct list *list, struct strbuf *out) + struct string_list *list, struct strbuf *out) { if (list->nr == 0) return; if (list->nr == 1) { - strbuf_addf(out, "%s%s", singular, list->list[0]); + strbuf_addf(out, "%s%s", singular, list->items[0].string); } else { int i; strbuf_addstr(out, plural); for (i = 0; i < list->nr - 1; i++) - strbuf_addf(out, "%s%s", i > 0 ? ", " : "", list->list[i]); - strbuf_addf(out, " and %s", list->list[list->nr - 1]); + strbuf_addf(out, "%s%s", i > 0 ? ", " : "", + list->items[i].string); + strbuf_addf(out, " and %s", list->items[list->nr - 1].string); } } @@ -183,8 +146,9 @@ static void shortlog(const char *name, unsigned char *sha1, int i, count = 0; struct commit *commit; struct object *branch; - struct list subjects = { NULL, NULL, 0, 0 }; + struct string_list subjects = { NULL, 0, 0, 1 }; int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED; + struct strbuf sb = STRBUF_INIT; branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40); if (!branch || branch->type != OBJ_COMMIT) @@ -198,7 +162,7 @@ static void shortlog(const char *name, unsigned char *sha1, if (prepare_revision_walk(rev)) die("revision walk setup failed"); while ((commit = get_revision(rev)) != NULL) { - char *oneline, *bol, *eol; + struct pretty_print_context ctx = {0}; /* ignore merges */ if (commit->parents && commit->parents->next) @@ -208,30 +172,14 @@ static void shortlog(const char *name, unsigned char *sha1, if (subjects.nr > limit) continue; - bol = strstr(commit->buffer, "\n\n"); - if (bol) { - unsigned char c; - do { - c = *++bol; - } while (isspace(c)); - if (!c) - bol = NULL; - } - - if (!bol) { - append_to_list(&subjects, xstrdup(sha1_to_hex( - commit->object.sha1)), - NULL); - continue; - } + format_commit_message(commit, "%s", &sb, &ctx); + strbuf_ltrim(&sb); - eol = strchr(bol, '\n'); - if (eol) { - oneline = xmemdupz(bol, eol - bol); - } else { - oneline = xstrdup(bol); - } - append_to_list(&subjects, oneline, NULL); + if (!sb.len) + string_list_append(sha1_to_hex(commit->object.sha1), + &subjects); + else + string_list_append(strbuf_detach(&sb, NULL), &subjects); } if (count > limit) @@ -243,7 +191,7 @@ static void shortlog(const char *name, unsigned char *sha1, if (i >= limit) strbuf_addf(out, " ...\n"); else - strbuf_addf(out, " %s\n", subjects.list[i]); + strbuf_addf(out, " %s\n", subjects.items[i].string); clear_commit_marks((struct commit *)branch, flags); clear_commit_marks(head, flags); @@ -251,7 +199,7 @@ static void shortlog(const char *name, unsigned char *sha1, rev->commits = NULL; rev->pending.nr = 0; - free_list(&subjects); + string_list_clear(&subjects, 0); } int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { @@ -281,16 +229,19 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { 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++) { - struct src_data *src_data = srcs.payload[i]; + struct src_data *src_data = srcs.items[i].util; const char *subsep = ""; strbuf_addstr(out, sep); sep = "; "; if (src_data->head_status == 1) { - strbuf_addstr(out, srcs.list[i]); + strbuf_addstr(out, srcs.items[i].string); continue; } if (src_data->head_status == 3) { @@ -319,8 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { print_joined("commit ", "commits ", &src_data->generic, out); } - if (strcmp(".", srcs.list[i])) - strbuf_addf(out, " of %s", srcs.list[i]); + if (strcmp(".", srcs.items[i].string)) + strbuf_addf(out, " of %s", srcs.items[i].string); } if (!strcmp("master", current_branch)) @@ -339,7 +290,7 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { rev.limited = 1; for (i = 0; i < origins.nr; i++) - shortlog(origins.list[i], origins.payload[i], + shortlog(origins.items[i].string, origins.items[i].util, head, &rev, limit, out); } return 0; @@ -350,7 +301,9 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) const char *inpath = NULL; struct option options[] = { OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"), - OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"), + { OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL, + "alias for --log (deprecated)", + PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_FILENAME('F', "file", &inpath, "file to read from"), OPT_END() }; diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 62be1bbfd6..7f5011f75e 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -549,10 +549,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 9d30ddb28d..b194ea3cea 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -17,8 +17,8 @@ #include "dir.h" #ifndef NO_PTHREADS -#include "thread-utils.h" #include <pthread.h> +#include "thread-utils.h" #endif static char const * const grep_usage[] = { @@ -96,6 +96,9 @@ 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 void add_work(enum work_type type, char *name, void *id) { grep_lock(); @@ -159,7 +162,12 @@ static void work_done(struct work_item *w) for(; todo[todo_done].done && todo_done != todo_start; todo_done = (todo_done+1) % ARRAY_SIZE(todo)) { w = &todo[todo_done]; - write_or_die(1, w->out.buf, w->out.len); + 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; + } free(w->name); free(w->identifier); } @@ -946,8 +954,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; - if (use_threads) + if (use_threads) { + if (opt.pre_context || opt.post_context) + print_hunk_marks_between_files = 1; start_threads(&opt); + } #else use_threads = 0; #endif diff --git a/builtin/index-pack.c b/builtin/index-pack.c index b4cf8c53e0..a89ae831dd 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> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }"; struct object_entry { @@ -266,26 +266,23 @@ 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; void *buf = xmalloc(size); memset(&stream, 0, sizeof(stream)); + git_inflate_init(&stream); stream.next_out = buf; stream.avail_out = size; - stream.next_in = fill(1); - stream.avail_in = input_len; - git_inflate_init(&stream); - for (;;) { - int ret = git_inflate(&stream, 0); - use(input_len - stream.avail_in); - if (stream.total_out == size && ret == Z_STREAM_END) - break; - if (ret != Z_OK) - bad_object(offset, "inflate returned %d", ret); + do { stream.next_in = fill(1); stream.avail_in = input_len; - } + status = git_inflate(&stream, 0); + use(input_len - stream.avail_in); + } while (status == Z_OK); + if (stream.total_out != size || status != Z_STREAM_END) + bad_object(offset, "inflate returned %d", status); git_inflate_end(&stream); return buf; } @@ -359,34 +356,38 @@ 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 long rdy = 0; - unsigned char *src, *data; + unsigned char *data, *inbuf; z_stream stream; - int st; + int status; - src = xmalloc(len); - data = src; - do { - ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy); - if (n < 0) - die_errno("cannot pread pack file"); - if (!n) - die("premature end of pack file, %lu bytes missing", - len - rdy); - rdy += n; - } while (rdy < len); data = xmalloc(obj->size); + inbuf = xmalloc((len < 64*1024) ? len : 64*1024); + memset(&stream, 0, sizeof(stream)); + git_inflate_init(&stream); stream.next_out = data; stream.avail_out = obj->size; - stream.next_in = src; - stream.avail_in = len; - git_inflate_init(&stream); - while ((st = git_inflate(&stream, Z_FINISH)) == Z_OK); - git_inflate_end(&stream); - if (st != Z_STREAM_END || stream.total_out != obj->size) + + do { + ssize_t n = (len < 64*1024) ? len : 64*1024; + n = pread(pack_fd, inbuf, n, from); + if (n < 0) + die_errno("cannot pread pack file"); + if (!n) + die("premature end of pack file, %lu bytes missing", len); + from += n; + len -= n; + stream.next_in = inbuf; + stream.avail_in = n; + status = git_inflate(&stream, 0); + } while (len && status == Z_OK && !stream.avail_in); + + /* This has been inflated OK when first encountered, so... */ + if (status != Z_STREAM_END || stream.total_out != obj->size) die("serious inflate inconsistency"); - free(src); + + git_inflate_end(&stream); + free(inbuf); return data; } @@ -668,25 +669,25 @@ static void parse_pack_objects(unsigned char *sha1) static int write_compressed(struct sha1file *f, void *in, unsigned int size) { z_stream stream; - unsigned long maxsize; - void *out; + int status; + unsigned char outbuf[4096]; memset(&stream, 0, sizeof(stream)); deflateInit(&stream, zlib_compression_level); - maxsize = deflateBound(&stream, size); - out = xmalloc(maxsize); - - /* Compress it */ stream.next_in = in; stream.avail_in = size; - stream.next_out = out; - stream.avail_out = maxsize; - while (deflate(&stream, Z_FINISH) == Z_OK); - deflateEnd(&stream); + do { + stream.next_out = outbuf; + stream.avail_out = sizeof(outbuf); + status = 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; - sha1write(f, out, size); - free(out); + deflateEnd(&stream); return size; } diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..0271285fad 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -463,7 +463,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) static char git_dir[PATH_MAX+1]; setenv(GIT_DIR_ENVIRONMENT, - getcwd(git_dir, sizeof(git_dir)), 0); + getcwd(git_dir, sizeof(git_dir)), argc > 0); } if (init_shared_repository != -1) diff --git a/builtin/log.c b/builtin/log.c index a8dd8c989c..6208703c06 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -36,6 +36,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, { int i; int decoration_style = 0; + struct userformat_want w; rev->abbrev = DEFAULT_ABBREV; rev->commit_format = CMIT_FMT_DEFAULT; @@ -58,7 +59,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, usage(builtin_log_usage); argc = setup_revisions(argc, argv, rev, opt); - if (!rev->show_notes_given && !rev->pretty_given) + memset(&w, 0, sizeof(w)); + userformat_find_requirements(NULL, &w); + + if (!rev->show_notes_given && (!rev->pretty_given || w.notes)) rev->show_notes = 1; if (rev->show_notes) init_display_notes(&rev->notes_opt); @@ -1157,8 +1161,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) return 0; } - if (ignore_if_in_upstream) + if (ignore_if_in_upstream) { + /* Don't say anything if head and upstream are the same. */ + if (rev.pending.nr == 2) { + struct object_array_entry *o = rev.pending.objects; + if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0) + return 0; + } get_patch_ids(&rev, &ids, prefix); + } if (!use_stdout) realstdout = xfdopen(xdup(1), "w"); @@ -1296,8 +1307,11 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags) return -1; } -static const char cherry_usage[] = -"git cherry [-v] [<upstream> [<head> [<limit>]]]"; +static const char * const cherry_usage[] = { + "git cherry [-v] [<upstream> [<head> [<limit>]]]", + NULL +}; + int cmd_cherry(int argc, const char **argv, const char *prefix) { struct rev_info revs; @@ -1308,26 +1322,25 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) const char *upstream; const char *head = "HEAD"; const char *limit = NULL; - int verbose = 0; + int verbose = 0, abbrev = 0; - if (argc > 1 && !strcmp(argv[1], "-v")) { - verbose = 1; - argc--; - argv++; - } + struct option options[] = { + OPT__ABBREV(&abbrev), + OPT__VERBOSE(&verbose), + OPT_END() + }; - if (argc > 1 && !strcmp(argv[1], "-h")) - usage(cherry_usage); + argc = parse_options(argc, argv, prefix, options, cherry_usage, 0); switch (argc) { - case 4: - limit = argv[3]; - /* FALLTHROUGH */ case 3: - head = argv[2]; + limit = argv[2]; /* FALLTHROUGH */ case 2: - upstream = argv[1]; + head = argv[1]; + /* FALLTHROUGH */ + case 1: + upstream = argv[0]; break; default: current_branch = branch_get(NULL); @@ -1337,7 +1350,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) fprintf(stderr, "Could not find a tracked" " remote branch, please" " specify <upstream> manually.\n"); - usage(cherry_usage); + usage_with_options(cherry_usage, options); } upstream = current_branch->merge[0]->dst; @@ -1390,12 +1403,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx); printf("%c %s %s\n", sign, - sha1_to_hex(commit->object.sha1), buf.buf); + find_unique_abbrev(commit->object.sha1, abbrev), + buf.buf); strbuf_release(&buf); } else { printf("%c %s\n", sign, - sha1_to_hex(commit->object.sha1)); + find_unique_abbrev(commit->object.sha1, abbrev)); } list = list->next; diff --git a/builtin/ls-files.c b/builtin/ls-files.c index b065061392..c0fbcdcf4f 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -153,8 +153,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) printf("%s%06o %s %d\t", tag, ce->ce_mode, - abbrev ? find_unique_abbrev(ce->sha1,abbrev) - : sha1_to_hex(ce->sha1), + find_unique_abbrev(ce->sha1,abbrev), ce_stage(ce)); } write_name_quoted(ce->name + offset, stdout, line_terminator); @@ -176,9 +175,7 @@ static int show_one_ru(struct string_list_item *item, void *cbdata) if (!ui->mode[i]) continue; printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i], - abbrev - ? find_unique_abbrev(ui->sha1[i], abbrev) - : sha1_to_hex(ui->sha1[i]), + find_unique_abbrev(ui->sha1[i], abbrev), i + 1); write_name_quoted(path + offset, stdout, line_terminator); } diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 4484185afc..dc86b0d9a9 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -103,13 +103,11 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, } else strcpy(size_text, "-"); printf("%06o %s %s %7s\t", mode, type, - abbrev ? find_unique_abbrev(sha1, abbrev) - : sha1_to_hex(sha1), + find_unique_abbrev(sha1, abbrev), size_text); } else printf("%06o %s %s\t", mode, type, - abbrev ? find_unique_abbrev(sha1, abbrev) - : sha1_to_hex(sha1)); + find_unique_abbrev(sha1, abbrev)); } write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix, pathname, stdout, line_termination); diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c index ce2ef6bede..4a9729b9b3 100644 --- a/builtin/mailinfo.c +++ b/builtin/mailinfo.c @@ -746,7 +746,8 @@ static int is_scissors_line(const struct strbuf *line) continue; } if (i + 1 < len && - (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2))) { + (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2) || + !memcmp(buf + i, ">%", 2) || !memcmp(buf + i, "%<", 2))) { in_perforation = 1; perforation += 2; scissors += 2; diff --git a/builtin/merge-file.c b/builtin/merge-file.c index 69cc683332..b8e9e5ba01 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; @@ -77,8 +77,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) argv[i]); } - ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2], - &xmp, &result); + xmp.ancestor = names[1]; + xmp.file1 = names[0]; + xmp.file2 = names[2]; + ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result); for (i = 0; i < 3; i++) free(mmfs[i].ptr); diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index a4a4f2ce4c..fc00d794d6 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 3aaec7bed7..c043066845 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -667,7 +667,7 @@ static int count_unmerged_entries(void) return ret; } -static int checkout_fast_forward(unsigned char *head, unsigned char *remote) +int checkout_fast_forward(const unsigned char *head, const unsigned char *remote) { struct tree *trees[MAX_UNPACK_TREES]; struct unpack_trees_options opts; diff --git a/builtin/notes.c b/builtin/notes.c index 4543d11311..26617546c8 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -19,13 +19,54 @@ #include "string-list.h" static const char * const git_notes_usage[] = { + "git notes [--ref <notes_ref>] [list [<object>]]", + "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]", + "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>", + "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]", + "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", + NULL +}; + +static const char * const git_notes_list_usage[] = { "git notes [list [<object>]]", - "git notes add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]", - "git notes copy [-f] <from-object> <to-object>", - "git notes append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]", + NULL +}; + +static const char * const git_notes_add_usage[] = { + "git notes add [<options>] [<object>]", + NULL +}; + +static const char * const git_notes_copy_usage[] = { + "git notes copy [<options>] <from-object> <to-object>", + "git notes copy --stdin [<from-object> <to-object>]...", + NULL +}; + +static const char * const git_notes_append_usage[] = { + "git notes append [<options>] [<object>]", + NULL +}; + +static const char * const git_notes_edit_usage[] = { "git notes edit [<object>]", + NULL +}; + +static const char * const git_notes_show_usage[] = { "git notes show [<object>]", + NULL +}; + +static const char * const git_notes_remove_usage[] = { "git notes remove [<object>]", + NULL +}; + +static const char * const git_notes_prune_usage[] = { "git notes prune", NULL }; @@ -272,7 +313,6 @@ int commit_notes(struct notes_tree *t, const char *msg) return 0; } - combine_notes_fn *parse_combine_notes_fn(const char *v) { if (!strcasecmp(v, "overwrite")) @@ -376,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) { @@ -427,22 +467,65 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd) return ret; } -int cmd_notes(int argc, const char **argv, const char *prefix) +static struct notes_tree *init_notes_check(const char *subcommand) { struct notes_tree *t; - unsigned char object[20], from_obj[20], new_note[20]; + init_notes(NULL, NULL, NULL, 0); + t = &default_notes_tree; + + if (prefixcmp(t->ref, "refs/notes/")) + die("Refusing to %s notes in %s (outside of refs/notes/)", + subcommand, t->ref); + return t; +} + +static int list(int argc, const char **argv, const char *prefix) +{ + struct notes_tree *t; + unsigned char object[20]; const unsigned char *note; + int retval = -1; + struct option options[] = { + OPT_END() + }; + + if (argc) + argc = parse_options(argc, argv, prefix, options, + git_notes_list_usage, 0); + + if (1 < argc) { + error("too many parameters"); + usage_with_options(git_notes_list_usage, options); + } + + t = init_notes_check("list"); + if (argc) { + if (get_sha1(argv[0], object)) + die("Failed to resolve '%s' as a valid ref.", argv[0]); + note = get_note(t, object); + if (note) { + puts(sha1_to_hex(note)); + retval = 0; + } else + retval = error("No note found for object %s.", + sha1_to_hex(object)); + } else + retval = for_each_note(t, 0, list_each_note, NULL); + + free_notes(t); + return retval; +} + +static int add(int argc, const char **argv, const char *prefix) +{ + int retval = 0, force = 0; const char *object_ref; + struct notes_tree *t; + unsigned char object[20], new_note[20]; char logmsg[100]; - - int list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0, - remove = 0, prune = 0, force = 0, from_stdin = 0; - int given_object = 0, i = 1, retval = 0; + const unsigned char *note; struct msg_arg msg = { 0, 0, STRBUF_INIT }; - const char *rewrite_cmd = NULL; - const char *override_notes_ref = NULL; struct option options[] = { - OPT_GROUP("Notes contents options"), { OPTION_CALLBACK, 'm', "message", &msg, "MSG", "note contents as a string", PARSE_OPT_NONEG, parse_msg_arg}, @@ -455,196 +538,325 @@ int cmd_notes(int argc, const char **argv, const char *prefix) { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT", "reuse specified note object", PARSE_OPT_NONEG, parse_reuse_arg}, - OPT_GROUP("Other options"), OPT_BOOLEAN('f', "force", &force, "replace existing notes"), - OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"), - OPT_STRING(0, "ref", &override_notes_ref, "notes_ref", - "use notes from <notes_ref>"), - OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command", - "load rewriting config for <command> (implies --stdin)"), OPT_END() }; - git_config(git_default_config, NULL); - - argc = parse_options(argc, argv, prefix, options, git_notes_usage, 0); + argc = parse_options(argc, argv, prefix, options, git_notes_add_usage, + 0); - if (override_notes_ref) { - struct strbuf sb = STRBUF_INIT; - if (!prefixcmp(override_notes_ref, "refs/notes/")) - /* we're happy */; - else if (!prefixcmp(override_notes_ref, "notes/")) - strbuf_addstr(&sb, "refs/"); - else - strbuf_addstr(&sb, "refs/notes/"); - strbuf_addstr(&sb, override_notes_ref); - setenv("GIT_NOTES_REF", sb.buf, 1); - strbuf_release(&sb); + if (1 < argc) { + error("too many parameters"); + usage_with_options(git_notes_add_usage, options); } - if (argc && !strcmp(argv[0], "list")) - list = 1; - else if (argc && !strcmp(argv[0], "add")) - add = 1; - else if (argc && !strcmp(argv[0], "copy")) - copy = 1; - else if (argc && !strcmp(argv[0], "append")) - append = 1; - else if (argc && !strcmp(argv[0], "edit")) - edit = 1; - else if (argc && !strcmp(argv[0], "show")) - show = 1; - else if (argc && !strcmp(argv[0], "remove")) - remove = 1; - else if (argc && !strcmp(argv[0], "prune")) - prune = 1; - else if (!argc) { - list = 1; /* Default to 'list' if no other subcommand given */ - i = 0; - } + object_ref = argc ? argv[0] : "HEAD"; - if (list + add + copy + append + edit + show + remove + prune != 1) - usage_with_options(git_notes_usage, options); + if (get_sha1(object_ref, object)) + die("Failed to resolve '%s' as a valid ref.", object_ref); - if (msg.given && !(add || append || edit)) { - error("cannot use -m/-F/-c/-C options with %s subcommand.", - argv[0]); - usage_with_options(git_notes_usage, options); - } + t = init_notes_check("add"); + note = get_note(t, object); - if (msg.given && edit) { - fprintf(stderr, "The -m/-F/-c/-C options have been deprecated " - "for the 'edit' subcommand.\n" - "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"); + if (note) { + if (!force) { + retval = error("Cannot add notes. Found existing notes " + "for object %s. Use '-f' to overwrite " + "existing notes", sha1_to_hex(object)); + goto out; + } + fprintf(stderr, "Overwriting existing notes for object %s\n", + sha1_to_hex(object)); } - if (force && !(add || copy)) { - error("cannot use -f option with %s subcommand.", argv[0]); - usage_with_options(git_notes_usage, options); - } + create_note(object, &msg, 0, note, new_note); - if (!copy && rewrite_cmd) { - error("cannot use --for-rewrite with %s subcommand.", argv[0]); - usage_with_options(git_notes_usage, options); - } - if (!copy && from_stdin) { - error("cannot use --stdin with %s subcommand.", argv[0]); - usage_with_options(git_notes_usage, options); - } + if (is_null_sha1(new_note)) + remove_note(t, object); + else + add_note(t, object, new_note, combine_notes_overwrite); - if (copy) { - const char *from_ref; - if (from_stdin || rewrite_cmd) { - if (argc > 1) { - error("too many parameters"); - usage_with_options(git_notes_usage, options); - } else { - return notes_copy_from_stdin(force, rewrite_cmd); - } - } - if (argc < 3) { - error("too few parameters"); - usage_with_options(git_notes_usage, options); + snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'", + is_null_sha1(new_note) ? "removed" : "added", "add"); + commit_notes(t, logmsg); +out: + free_notes(t); + strbuf_release(&(msg.buf)); + return retval; +} + +static int copy(int argc, const char **argv, const char *prefix) +{ + int retval = 0, force = 0, from_stdin = 0; + const unsigned char *from_note, *note; + const char *object_ref; + unsigned char object[20], from_obj[20]; + struct notes_tree *t; + const char *rewrite_cmd = NULL; + struct option options[] = { + OPT_BOOLEAN('f', "force", &force, "replace existing notes"), + OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"), + OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command", + "load rewriting config for <command> (implies " + "--stdin)"), + OPT_END() + }; + + argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage, + 0); + + if (from_stdin || rewrite_cmd) { + if (argc) { + error("too many parameters"); + usage_with_options(git_notes_copy_usage, options); + } else { + return notes_copy_from_stdin(force, rewrite_cmd); } - from_ref = argv[i++]; - if (get_sha1(from_ref, from_obj)) - die("Failed to resolve '%s' as a valid ref.", from_ref); } - given_object = argc > i; - object_ref = given_object ? argv[i++] : "HEAD"; - - if (argc > i || (prune && given_object)) { + if (2 < argc) { error("too many parameters"); - usage_with_options(git_notes_usage, options); + usage_with_options(git_notes_copy_usage, options); } - if (get_sha1(object_ref, object)) - die("Failed to resolve '%s' as a valid ref.", object_ref); + if (get_sha1(argv[0], from_obj)) + die("Failed to resolve '%s' as a valid ref.", argv[0]); - init_notes(NULL, NULL, NULL, 0); - t = &default_notes_tree; + object_ref = 1 < argc ? argv[1] : "HEAD"; - if (prefixcmp(t->ref, "refs/notes/")) - die("Refusing to %s notes in %s (outside of refs/notes/)", - argv[0], t->ref); + if (get_sha1(object_ref, object)) + die("Failed to resolve '%s' as a valid ref.", object_ref); + t = init_notes_check("copy"); note = get_note(t, object); - /* list command */ - - if (list) { - if (given_object) { - if (note) { - puts(sha1_to_hex(note)); - goto end; - } - } else { - retval = for_each_note(t, 0, list_each_note, NULL); - goto end; + if (note) { + if (!force) { + retval = error("Cannot copy notes. Found existing " + "notes for object %s. Use '-f' to " + "overwrite existing notes", + sha1_to_hex(object)); + goto out; } + fprintf(stderr, "Overwriting existing notes for object %s\n", + sha1_to_hex(object)); } - /* show command */ - - if ((list || show) && !note) { - error("No note found for object %s.", sha1_to_hex(object)); - retval = 1; - goto end; - } else if (show) { - const char *show_args[3] = {"show", sha1_to_hex(note), NULL}; - retval = execv_git_cmd(show_args); - goto end; + from_note = get_note(t, from_obj); + if (!from_note) { + retval = error("Missing notes on source object %s. Cannot " + "copy.", sha1_to_hex(from_obj)); + goto out; } - /* add/append/edit/remove/prune command */ + add_note(t, object, from_note, combine_notes_overwrite); + commit_notes(t, "Notes added by 'git notes copy'"); +out: + free_notes(t); + return retval; +} - if ((add || copy) && note) { - if (!force) { - error("Cannot %s notes. Found existing notes for object" - " %s. Use '-f' to overwrite existing notes", - argv[0], sha1_to_hex(object)); - retval = 1; - goto end; - } - fprintf(stderr, "Overwriting existing notes for object %s\n", - sha1_to_hex(object)); - } +static int append_edit(int argc, const char **argv, const char *prefix) +{ + const char *object_ref; + struct notes_tree *t; + unsigned char object[20], new_note[20]; + const unsigned char *note; + char logmsg[100]; + const char * const *usage; + struct msg_arg msg = { 0, 0, STRBUF_INIT }; + struct option options[] = { + { OPTION_CALLBACK, 'm', "message", &msg, "MSG", + "note contents as a string", PARSE_OPT_NONEG, + parse_msg_arg}, + { OPTION_CALLBACK, 'F', "file", &msg, "FILE", + "note contents in a file", PARSE_OPT_NONEG, + parse_file_arg}, + { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT", + "reuse and edit specified note object", PARSE_OPT_NONEG, + parse_reedit_arg}, + { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT", + "reuse specified note object", PARSE_OPT_NONEG, + parse_reuse_arg}, + OPT_END() + }; + int edit = !strcmp(argv[0], "edit"); + + usage = edit ? git_notes_edit_usage : git_notes_append_usage; + argc = parse_options(argc, argv, prefix, options, usage, + PARSE_OPT_KEEP_ARGV0); - if (remove) { - msg.given = 1; - msg.use_editor = 0; - strbuf_reset(&(msg.buf)); + if (2 < argc) { + error("too many parameters"); + usage_with_options(usage, options); } - if (prune) { - hashclr(new_note); - prune_notes(t); - goto commit; - } else if (copy) { - const unsigned char *from_note = get_note(t, from_obj); - if (!from_note) { - error("Missing notes on source object %s. Cannot copy.", - sha1_to_hex(from_obj)); - retval = 1; - goto end; - } - hashcpy(new_note, from_note); - } else - create_note(object, &msg, append, note, new_note); + if (msg.given && edit) + fprintf(stderr, "The -m/-F/-c/-C options have been deprecated " + "for the 'edit' subcommand.\n" + "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"); + + object_ref = 1 < argc ? argv[1] : "HEAD"; + + if (get_sha1(object_ref, object)) + die("Failed to resolve '%s' as a valid ref.", object_ref); + + t = init_notes_check(argv[0]); + note = get_note(t, object); + + create_note(object, &msg, !edit, note, new_note); if (is_null_sha1(new_note)) remove_note(t, object); else add_note(t, object, new_note, combine_notes_overwrite); -commit: snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'", is_null_sha1(new_note) ? "removed" : "added", argv[0]); commit_notes(t, logmsg); - -end: free_notes(t); strbuf_release(&(msg.buf)); + return 0; +} + +static int show(int argc, const char **argv, const char *prefix) +{ + const char *object_ref; + struct notes_tree *t; + unsigned char object[20]; + const unsigned char *note; + int retval; + struct option options[] = { + OPT_END() + }; + + argc = parse_options(argc, argv, prefix, options, git_notes_show_usage, + 0); + + if (1 < argc) { + error("too many parameters"); + usage_with_options(git_notes_show_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("show"); + note = get_note(t, object); + + if (!note) + retval = error("No note found for object %s.", + sha1_to_hex(object)); + else { + const char *show_args[3] = {"show", sha1_to_hex(note), NULL}; + retval = execv_git_cmd(show_args); + } + free_notes(t); return retval; } + +static int remove_cmd(int argc, const char **argv, const char *prefix) +{ + struct option options[] = { + OPT_END() + }; + const char *object_ref; + struct notes_tree *t; + unsigned char object[20]; + + 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"); + + fprintf(stderr, "Removing note for object %s\n", sha1_to_hex(object)); + remove_note(t, object); + + commit_notes(t, "Notes removed by 'git notes remove'"); + free_notes(t); + return 0; +} + +static int prune(int argc, const char **argv, const char *prefix) +{ + struct notes_tree *t; + struct option options[] = { + OPT_END() + }; + + argc = parse_options(argc, argv, prefix, options, git_notes_prune_usage, + 0); + + if (argc) { + error("too many parameters"); + usage_with_options(git_notes_prune_usage, options); + } + + t = init_notes_check("prune"); + + prune_notes(t); + commit_notes(t, "Notes removed by 'git notes prune'"); + free_notes(t); + return 0; +} + +int cmd_notes(int argc, const char **argv, const char *prefix) +{ + int result; + const char *override_notes_ref = NULL; + struct option options[] = { + OPT_STRING(0, "ref", &override_notes_ref, "notes_ref", + "use notes from <notes_ref>"), + OPT_END() + }; + + git_config(git_default_config, NULL); + argc = parse_options(argc, argv, prefix, options, git_notes_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + if (override_notes_ref) { + struct strbuf sb = STRBUF_INIT; + if (!prefixcmp(override_notes_ref, "refs/notes/")) + /* we're happy */; + else if (!prefixcmp(override_notes_ref, "notes/")) + strbuf_addstr(&sb, "refs/"); + else + strbuf_addstr(&sb, "refs/notes/"); + strbuf_addstr(&sb, override_notes_ref); + setenv("GIT_NOTES_REF", sb.buf, 1); + strbuf_release(&sb); + } + + if (argc < 1 || !strcmp(argv[0], "list")) + result = list(argc, argv, prefix); + else if (!strcmp(argv[0], "add")) + result = add(argc, argv, prefix); + else if (!strcmp(argv[0], "copy")) + result = copy(argc, argv, prefix); + else if (!strcmp(argv[0], "append") || !strcmp(argv[0], "edit")) + result = append_edit(argc, argv, prefix); + else if (!strcmp(argv[0], "show")) + result = show(argc, argv, prefix); + else if (!strcmp(argv[0], "remove")) + result = remove_cmd(argc, argv, prefix); + else if (!strcmp(argv[0], "prune")) + result = prune(argc, argv, prefix); + else { + result = error("Unknown subcommand: %s", argv[0]); + usage_with_options(git_notes_usage, options); + } + + return result ? 1 : 0; +} diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 97802585ea..214d7ef2b1 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -18,8 +18,8 @@ #include "refs.h" #ifndef NO_PTHREADS -#include "thread-utils.h" #include <pthread.h> +#include "thread-utils.h" #endif static const char pack_usage[] = @@ -1522,6 +1522,13 @@ static void find_deltas(struct object_entry **list, unsigned *list_size, #ifndef NO_PTHREADS +static void try_to_free_from_threads(size_t size) +{ + read_lock(); + release_pack_memory(size, -1); + read_unlock(); +} + /* * 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 @@ -1552,14 +1559,16 @@ static pthread_cond_t progress_cond; */ static void init_threaded_search(void) { - pthread_mutex_init(&read_mutex, NULL); + init_recursive_mutex(&read_mutex); 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); } static void cleanup_threaded_search(void) { + set_try_to_free_routine(NULL); pthread_cond_destroy(&progress_cond); pthread_mutex_destroy(&read_mutex); pthread_mutex_destroy(&cache_mutex); diff --git a/builtin/push.c b/builtin/push.c index 62957ededd..f4358b9d23 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -10,7 +10,7 @@ #include "parse-options.h" static const char * const push_usage[] = { - "git push [<options>] [<repository> <refspec>...]", + "git push [<options>] [<repository> [<refspec>...]]", NULL, }; diff --git a/builtin/reflog.c b/builtin/reflog.c index 64e45bd813..bd7880dc04 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -13,7 +13,7 @@ */ static const char reflog_expire_usage[] = -"git reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>..."; +"git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>..."; static const char reflog_delete_usage[] = "git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>..."; diff --git a/builtin/rerere.c b/builtin/rerere.c index 34f9acee91..0048f9ef7f 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -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/reset.c b/builtin/reset.c index 2c3a69adc6..1283068fd2 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -23,7 +23,8 @@ static const char * const git_reset_usage[] = { "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]", - "git reset [--mixed] <commit> [--] <paths>...", + "git reset [-q] <commit> [--] <paths>...", + "git reset --patch [<commit>] [--] [<paths>...]", NULL }; diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 5679170e82..51ceb19d88 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -133,9 +133,12 @@ static void show_commit(struct commit *commit, void *data) */ if (graph_show_remainder(revs->graph)) putchar('\n'); + if (revs->commit_format == CMIT_FMT_ONELINE) + putchar('\n'); } } else { - if (buf.len) + if (revs->commit_format != CMIT_FMT_USERFORMAT || + buf.len) printf("%s%c", buf.buf, info->hdr_termination); } strbuf_release(&buf); @@ -313,7 +316,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); init_revisions(&revs, prefix); - revs.abbrev = 0; + revs.abbrev = DEFAULT_ABBREV; revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); diff --git a/builtin/revert.c b/builtin/revert.c index eff52687a8..7d68ef714e 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -13,6 +13,7 @@ #include "revision.h" #include "rerere.h" #include "merge-recursive.h" +#include "refs.h" /* * This implements the builtins revert and cherry-pick. @@ -35,7 +36,7 @@ static const char * const cherry_pick_usage[] = { NULL }; -static int edit, no_replay, no_commit, mainline, signoff; +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; @@ -45,6 +46,8 @@ static const char *me; #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" +static char *get_encoding(const char *message); + static void parse_args(int argc, const char **argv) { const char * const * usage_str = @@ -60,8 +63,19 @@ static void parse_args(int argc, const char **argv) OPT_INTEGER('m', "mainline", &mainline, "parent number"), OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), OPT_END(), + OPT_END(), + OPT_END(), }; + if (action == CHERRY_PICK) { + struct option cp_extra[] = { + OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"), + OPT_END(), + }; + if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra)) + die("program error"); + } + if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1) usage_with_options(usage_str, options); @@ -73,33 +87,69 @@ static void parse_args(int argc, const char **argv) exit(1); } -static char *get_oneline(const char *message) +struct commit_message { + char *parent_label; + const char *label; + const char *subject; + char *reencoded_message; + const char *message; +}; + +static int get_message(const char *raw_message, struct commit_message *out) { - char *result; - const char *p = message, *abbrev, *eol; + const char *encoding; + const char *p, *abbrev, *eol; + char *q; int abbrev_len, oneline_len; - if (!p) - die ("Could not read commit message of %s", - sha1_to_hex(commit->object.sha1)); + if (!raw_message) + return -1; + encoding = get_encoding(raw_message); + if (!encoding) + encoding = "UTF-8"; + if (!git_commit_encoding) + git_commit_encoding = "UTF-8"; + + out->reencoded_message = NULL; + out->message = raw_message; + if (strcmp(encoding, git_commit_encoding)) + out->reencoded_message = reencode_string(raw_message, + git_commit_encoding, encoding); + if (out->reencoded_message) + out->message = out->reencoded_message; + + abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); + abbrev_len = strlen(abbrev); + + /* Find beginning and end of commit subject. */ + p = out->message; while (*p && (*p != '\n' || p[1] != '\n')) p++; - if (*p) { p += 2; for (eol = p + 1; *eol && *eol != '\n'; eol++) ; /* do nothing */ } else eol = p; - abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); - abbrev_len = strlen(abbrev); oneline_len = eol - p; - result = xmalloc(abbrev_len + 5 + oneline_len); - memcpy(result, abbrev, abbrev_len); - memcpy(result + abbrev_len, "... ", 4); - memcpy(result + abbrev_len + 4, p, oneline_len); - result[abbrev_len + 4 + oneline_len] = '\0'; - return result; + + out->parent_label = xmalloc(strlen("parent of ") + abbrev_len + + strlen("... ") + oneline_len + 1); + q = out->parent_label; + q = mempcpy(q, "parent of ", strlen("parent of ")); + out->label = q; + q = mempcpy(q, abbrev, abbrev_len); + q = mempcpy(q, "... ", strlen("... ")); + out->subject = q; + q = mempcpy(q, p, oneline_len); + *q = '\0'; + return 0; +} + +static void free_message(struct commit_message *msg) +{ + free(msg->parent_label); + free(msg->reencoded_message); } static char *get_encoding(const char *message) @@ -244,14 +294,25 @@ static NORETURN void die_dirty_index(const char *me) } } +static int fast_forward_to(const unsigned char *to, const unsigned char *from) +{ + struct ref_lock *ref_lock; + + read_cache(); + if (checkout_fast_forward(from, to)) + exit(1); /* the callee should have complained already */ + ref_lock = lock_any_ref_for_update("HEAD", from, 0); + return write_ref_sha1(ref_lock, to, "cherry-pick"); +} + static int revert_or_cherry_pick(int argc, const char **argv) { unsigned char head[20]; struct commit *base, *next, *parent; + const char *base_label, *next_label; int i, index_fd, clean; - char *oneline, *reencoded_message = NULL; - const char *message, *encoding; - char *defmsg = git_pathdup("MERGE_MSG"); + struct commit_message msg = { NULL, NULL, NULL, NULL, NULL }; + char *defmsg = NULL; struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; static struct lock_file index_lock; @@ -265,6 +326,17 @@ static int revert_or_cherry_pick(int argc, const char **argv) 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) { @@ -284,8 +356,6 @@ static int revert_or_cherry_pick(int argc, const char **argv) } discard_cache(); - index_fd = hold_locked_index(&index_lock, 1); - if (!commit->parents) { if (action == REVERT) die ("Cannot revert a root commit"); @@ -314,14 +384,17 @@ static int revert_or_cherry_pick(int argc, const char **argv) else parent = commit->parents->item; - if (!(message = commit->buffer)) - die ("Cannot get commit message for %s", - sha1_to_hex(commit->object.sha1)); + if (allow_ff && !hashcmp(parent->object.sha1, head)) + return fast_forward_to(commit->object.sha1, head); if (parent && parse_commit(parent) < 0) die("%s: cannot parse parent commit %s", me, sha1_to_hex(parent->object.sha1)); + if (get_message(commit->buffer, &msg) != 0) + die("Cannot get commit message for %s", + sha1_to_hex(commit->object.sha1)); + /* * "commit" is an existing commit. We would want to apply * the difference it introduces since its first parent "prev" @@ -329,27 +402,19 @@ static int revert_or_cherry_pick(int argc, const char **argv) * reverse of it if we are revert. */ + defmsg = git_pathdup("MERGE_MSG"); msg_fd = hold_lock_file_for_update(&msg_file, defmsg, LOCK_DIE_ON_ERROR); - encoding = get_encoding(message); - if (!encoding) - encoding = "UTF-8"; - if (!git_commit_encoding) - git_commit_encoding = "UTF-8"; - if ((reencoded_message = reencode_string(message, - git_commit_encoding, encoding))) - message = reencoded_message; - - oneline = get_oneline(message); + index_fd = hold_locked_index(&index_lock, 1); if (action == REVERT) { - char *oneline_body = strchr(oneline, ' '); - base = commit; + base_label = msg.label; next = parent; + next_label = msg.parent_label; add_to_msg("Revert \""); - add_to_msg(oneline_body + 1); + add_to_msg(msg.subject); add_to_msg("\"\n\nThis reverts commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); @@ -360,9 +425,11 @@ static int revert_or_cherry_pick(int argc, const char **argv) add_to_msg(".\n"); } else { base = parent; + base_label = msg.parent_label; next = commit; - set_author_ident_env(message); - add_message_to_msg(message); + next_label = msg.label; + set_author_ident_env(msg.message); + add_message_to_msg(msg.message); if (no_replay) { add_to_msg("(cherry picked from commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); @@ -372,8 +439,9 @@ static int revert_or_cherry_pick(int argc, const char **argv) read_cache(); init_merge_options(&o); + o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; - o.branch2 = oneline; + o.branch2 = next ? next_label : "(empty tree)"; head_tree = parse_tree_indirect(head); next_tree = next ? next->tree : empty_tree(); @@ -437,7 +505,7 @@ static int revert_or_cherry_pick(int argc, const char **argv) args[i] = NULL; return execv_git_cmd(args); } - free(reencoded_message); + free_message(&msg); free(defmsg); return 0; diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 06320f5285..5089502800 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -162,7 +162,7 @@ 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.abbrev = DEFAULT_ABBREV; + ctx.abbrev = log->abbrev; ctx.subject = ""; ctx.after_subject = ""; ctx.date_mode = DATE_NORMAL; @@ -290,6 +290,7 @@ parse_done: } log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT; + log.abbrev = rev.abbrev; /* assume HEAD if from a tty */ if (!nongit && !rev.pending.nr && isatty(0)) diff --git a/builtin/show-branch.c b/builtin/show-branch.c index e20fcf3e93..e8719aa9e9 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/tag.c b/builtin/tag.c index 4ef1c4f508..d311491e49 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -147,11 +147,11 @@ static int delete_tag(const char *name, const char *ref, static int verify_tag(const char *name, const char *ref, const unsigned char *sha1) { - const char *argv_verify_tag[] = {"git-verify-tag", + const char *argv_verify_tag[] = {"verify-tag", "-v", "SHA1_HEX", NULL}; argv_verify_tag[2] = sha1_to_hex(sha1); - if (run_command_v_opt(argv_verify_tag, 0)) + if (run_command_v_opt(argv_verify_tag, RUN_GIT_CMD)) return error("could not verify the tag '%s'", name); return 0; } |
