diff options
Diffstat (limited to 'builtin')
86 files changed, 1060 insertions, 2868 deletions
diff --git a/builtin/add.c b/builtin/add.c index d9a2491e48..e888fb8c5f 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -4,6 +4,7 @@ * Copyright (C) 2006 Linus Torvalds */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "lockfile.h" #include "dir.h" @@ -249,6 +250,7 @@ N_("The following paths are ignored by one of your .gitignore files:\n"); static int verbose, show_only, ignored_too, refresh_only; static int ignore_add_errors, intent_to_add, ignore_missing; +static int warn_on_embedded_repo = 1; #define ADDREMOVE_DEFAULT 1 static int addremove = ADDREMOVE_DEFAULT; @@ -282,6 +284,8 @@ static struct option builtin_add_options[] = { OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")), OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")), OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")), + OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo, + N_("warn when adding an embedded repository")), OPT_END(), }; @@ -295,6 +299,45 @@ static int add_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } +static const char embedded_advice[] = N_( +"You've added another git repository inside your current repository.\n" +"Clones of the outer repository will not contain the contents of\n" +"the embedded repository and will not know how to obtain it.\n" +"If you meant to add a submodule, use:\n" +"\n" +" git submodule add <url> %s\n" +"\n" +"If you added this path by mistake, you can remove it from the\n" +"index with:\n" +"\n" +" git rm --cached %s\n" +"\n" +"See \"git help submodule\" for more information." +); + +static void check_embedded_repo(const char *path) +{ + struct strbuf name = STRBUF_INIT; + + if (!warn_on_embedded_repo) + return; + if (!ends_with(path, "/")) + return; + + /* Drop trailing slash for aesthetics */ + strbuf_addstr(&name, path); + strbuf_strip_suffix(&name, "/"); + + warning(_("adding embedded git repository: %s"), name.buf); + if (advice_add_embedded_repo) { + advise(embedded_advice, name.buf, name.buf); + /* there may be multiple entries; advise only once */ + advice_add_embedded_repo = 0; + } + + strbuf_release(&name); +} + static int add_files(struct dir_struct *dir, int flags) { int i, exit_status = 0; @@ -307,12 +350,14 @@ static int add_files(struct dir_struct *dir, int flags) exit_status = 1; } - for (i = 0; i < dir->nr; i++) + for (i = 0; i < dir->nr; i++) { + check_embedded_repo(dir->entries[i]->name); if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) { if (!ignore_add_errors) die(_("adding files failed")); exit_status = 1; } + } return exit_status; } diff --git a/builtin/am.c b/builtin/am.c index 0f63dcab16..40cc6d6fe8 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -4,6 +4,7 @@ * Based on git-am.sh by Junio C Hamano. */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "exec_cmd.h" #include "parse-options.h" @@ -483,8 +484,7 @@ static int run_applypatch_msg_hook(struct am_state *state) ret = run_hook_le(NULL, "applypatch-msg", am_path(state, "final-commit"), NULL); if (!ret) { - free(state->msg); - state->msg = NULL; + FREE_AND_NULL(state->msg); if (read_commit_msg(state) < 0) die(_("'%s' was deleted by the applypatch-msg hook"), am_path(state, "final-commit")); @@ -563,7 +563,7 @@ static int copy_notes_for_rebase(const struct am_state *state) goto finish; } - if (copy_note_for_rewrite(c, from_obj.hash, to_obj.hash)) + if (copy_note_for_rewrite(c, &from_obj, &to_obj)) ret = error(_("Failed to copy notes from '%s' to '%s'"), oid_to_hex(&from_obj), oid_to_hex(&to_obj)); } @@ -1073,17 +1073,10 @@ static void am_next(struct am_state *state) { struct object_id head; - free(state->author_name); - state->author_name = NULL; - - free(state->author_email); - state->author_email = NULL; - - free(state->author_date); - state->author_date = NULL; - - free(state->msg); - state->msg = NULL; + FREE_AND_NULL(state->author_name); + FREE_AND_NULL(state->author_email); + FREE_AND_NULL(state->author_date); + FREE_AND_NULL(state->msg); state->msg_len = 0; unlink(am_path(state, "author-script")); @@ -1138,7 +1131,7 @@ static int index_has_changes(struct strbuf *sb) struct object_id head; int i; - if (!get_sha1_tree("HEAD", head.hash)) { + if (!get_oid_tree("HEAD", &head)) { struct diff_options opt; diff_setup(&opt); @@ -1275,12 +1268,8 @@ static int parse_mail(struct am_state *state, const char *mail) die("BUG: invalid value for state->scissors"); } - mi.input = fopen(mail, "r"); - if (!mi.input) - die("could not open input"); - mi.output = fopen(am_path(state, "info"), "w"); - if (!mi.output) - die("could not open output 'info'"); + mi.input = xfopen(mail, "r"); + mi.output = xfopen(am_path(state, "info"), "w"); if (mailinfo(&mi, am_path(state, "msg"), am_path(state, "patch"))) die("could not parse patch"); @@ -1443,7 +1432,7 @@ static void write_index_patch(const struct am_state *state) struct rev_info rev_info; FILE *fp; - if (!get_sha1_tree("HEAD", head.hash)) + if (!get_oid_tree("HEAD", &head)) tree = lookup_tree(&head); else tree = lookup_tree(&empty_tree_oid); @@ -1672,7 +1661,7 @@ static void do_commit(const struct am_state *state) if (write_cache_as_tree(tree.hash, 0, NULL)) die(_("git write-tree failed to write a tree")); - if (!get_sha1_commit("HEAD", parent.hash)) { + if (!get_oid_commit("HEAD", &parent)) { old_oid = &parent; commit_list_insert(lookup_commit(&parent), &parents); } else { @@ -2311,6 +2300,9 @@ int cmd_am(int argc, const char **argv, const char *prefix) OPT_END() }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(usage, options); + git_config(git_am_config, NULL); am_state_init(&state); diff --git a/builtin/blame.c b/builtin/blame.c index 1043e5376f..bda1a78726 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -6,21 +6,14 @@ */ #include "cache.h" -#include "refs.h" +#include "config.h" #include "builtin.h" -#include "blob.h" #include "commit.h" -#include "tag.h" -#include "tree-walk.h" #include "diff.h" -#include "diffcore.h" #include "revision.h" #include "quote.h" -#include "xdiff-interface.h" -#include "cache-tree.h" #include "string-list.h" #include "mailmap.h" -#include "mergesort.h" #include "parse-options.h" #include "prio-queue.h" #include "utf8.h" @@ -29,6 +22,7 @@ #include "line-log.h" #include "dir.h" #include "progress.h" +#include "blame.h" static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"); @@ -62,1497 +56,21 @@ static struct string_list mailmap = STRING_LIST_INIT_NODUP; #define DEBUG 0 #endif -/* stats */ -static int num_read_blob; -static int num_get_patch; -static int num_commits; - -#define PICKAXE_BLAME_MOVE 01 -#define PICKAXE_BLAME_COPY 02 -#define PICKAXE_BLAME_COPY_HARDER 04 -#define PICKAXE_BLAME_COPY_HARDEST 010 - -/* - * blame for a blame_entry with score lower than these thresholds - * is not passed to the parent using move/copy logic. - */ static unsigned blame_move_score; static unsigned blame_copy_score; -#define BLAME_DEFAULT_MOVE_SCORE 20 -#define BLAME_DEFAULT_COPY_SCORE 40 /* Remember to update object flag allocation in object.h */ #define METAINFO_SHOWN (1u<<12) #define MORE_THAN_ONE_PATH (1u<<13) -/* - * One blob in a commit that is being suspected - */ -struct origin { - int refcnt; - /* Record preceding blame record for this blob */ - struct origin *previous; - /* origins are put in a list linked via `next' hanging off the - * corresponding commit's util field in order to make finding - * them fast. The presence in this chain does not count - * towards the origin's reference count. It is tempting to - * let it count as long as the commit is pending examination, - * but even under circumstances where the commit will be - * present multiple times in the priority queue of unexamined - * commits, processing the first instance will not leave any - * work requiring the origin data for the second instance. An - * interspersed commit changing that would have to be - * preexisting with a different ancestry and with the same - * commit date in order to wedge itself between two instances - * of the same commit in the priority queue _and_ produce - * blame entries relevant for it. While we don't want to let - * us get tripped up by this case, it certainly does not seem - * worth optimizing for. - */ - struct origin *next; - struct commit *commit; - /* `suspects' contains blame entries that may be attributed to - * this origin's commit or to parent commits. When a commit - * is being processed, all suspects will be moved, either by - * assigning them to an origin in a different commit, or by - * shipping them to the scoreboard's ent list because they - * cannot be attributed to a different commit. - */ - struct blame_entry *suspects; - mmfile_t file; - struct object_id blob_oid; - unsigned mode; - /* guilty gets set when shipping any suspects to the final - * blame list instead of other commits - */ - char guilty; - char path[FLEX_ARRAY]; -}; - struct progress_info { struct progress *progress; int blamed_lines; }; -static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, - xdl_emit_hunk_consume_func_t hunk_func, void *cb_data) -{ - xpparam_t xpp = {0}; - xdemitconf_t xecfg = {0}; - xdemitcb_t ecb = {NULL}; - - xpp.flags = xdl_opts; - xecfg.hunk_func = hunk_func; - ecb.priv = cb_data; - return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb); -} - -/* - * 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, - unsigned mode, - const struct object_id *oid, - int oid_valid, - char **buf, - unsigned long *buf_size) -{ - struct diff_filespec *df; - struct userdiff_driver *textconv; - - df = alloc_filespec(path); - fill_filespec(df, oid->hash, oid_valid, mode); - 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 diff_options *opt, - struct origin *o, mmfile_t *file) -{ - if (!o->file.ptr) { - enum object_type type; - unsigned long file_size; - - num_read_blob++; - if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && - textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size)) - ; - else - file->ptr = read_sha1_file(o->blob_oid.hash, &type, - &file_size); - file->size = file_size; - - if (!file->ptr) - die("Cannot read blob %s for path %s", - oid_to_hex(&o->blob_oid), - o->path); - o->file = *file; - } - else - *file = o->file; -} - -/* - * Origin is refcounted and usually we keep the blob contents to be - * reused. - */ -static inline struct origin *origin_incref(struct origin *o) -{ - if (o) - o->refcnt++; - return o; -} - -static void origin_decref(struct origin *o) -{ - if (o && --o->refcnt <= 0) { - struct origin *p, *l = NULL; - if (o->previous) - origin_decref(o->previous); - free(o->file.ptr); - /* Should be present exactly once in commit chain */ - for (p = o->commit->util; p; l = p, p = p->next) { - if (p == o) { - if (l) - l->next = p->next; - else - o->commit->util = p->next; - free(o); - return; - } - } - die("internal error in blame::origin_decref"); - } -} - -static void drop_origin_blob(struct origin *o) -{ - if (o->file.ptr) { - free(o->file.ptr); - o->file.ptr = NULL; - } -} - -/* - * Each group of lines is described by a blame_entry; it can be split - * as we pass blame to the parents. They are arranged in linked lists - * kept as `suspects' of some unprocessed origin, or entered (when the - * blame origin has been finalized) into the scoreboard structure. - * While the scoreboard structure is only sorted at the end of - * processing (according to final image line number), the lists - * attached to an origin are sorted by the target line number. - */ -struct blame_entry { - struct blame_entry *next; - - /* the first line of this group in the final image; - * internally all line numbers are 0 based. - */ - int lno; - - /* how many lines this group has */ - int num_lines; - - /* the commit that introduced this group into the final image */ - struct origin *suspect; - - /* the line number of the first line of this group in the - * suspect's file; internally all line numbers are 0 based. - */ - int s_lno; - - /* how significant this entry is -- cached to avoid - * scanning the lines over and over. - */ - unsigned score; -}; - -/* - * Any merge of blames happens on lists of blames that arrived via - * different parents in a single suspect. In this case, we want to - * sort according to the suspect line numbers as opposed to the final - * image line numbers. The function body is somewhat longish because - * it avoids unnecessary writes. - */ - -static struct blame_entry *blame_merge(struct blame_entry *list1, - struct blame_entry *list2) -{ - struct blame_entry *p1 = list1, *p2 = list2, - **tail = &list1; - - if (!p1) - return p2; - if (!p2) - return p1; - - if (p1->s_lno <= p2->s_lno) { - do { - tail = &p1->next; - if ((p1 = *tail) == NULL) { - *tail = p2; - return list1; - } - } while (p1->s_lno <= p2->s_lno); - } - for (;;) { - *tail = p2; - do { - tail = &p2->next; - if ((p2 = *tail) == NULL) { - *tail = p1; - return list1; - } - } while (p1->s_lno > p2->s_lno); - *tail = p1; - do { - tail = &p1->next; - if ((p1 = *tail) == NULL) { - *tail = p2; - return list1; - } - } while (p1->s_lno <= p2->s_lno); - } -} - -static void *get_next_blame(const void *p) -{ - return ((struct blame_entry *)p)->next; -} - -static void set_next_blame(void *p1, void *p2) -{ - ((struct blame_entry *)p1)->next = p2; -} - -/* - * Final image line numbers are all different, so we don't need a - * three-way comparison here. - */ - -static int compare_blame_final(const void *p1, const void *p2) -{ - return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno - ? 1 : -1; -} - -static int compare_blame_suspect(const void *p1, const void *p2) -{ - const struct blame_entry *s1 = p1, *s2 = p2; - /* - * to allow for collating suspects, we sort according to the - * respective pointer value as the primary sorting criterion. - * The actual relation is pretty unimportant as long as it - * establishes a total order. Comparing as integers gives us - * that. - */ - if (s1->suspect != s2->suspect) - return (intptr_t)s1->suspect > (intptr_t)s2->suspect ? 1 : -1; - if (s1->s_lno == s2->s_lno) - return 0; - return s1->s_lno > s2->s_lno ? 1 : -1; -} - -static struct blame_entry *blame_sort(struct blame_entry *head, - int (*compare_fn)(const void *, const void *)) -{ - return llist_mergesort (head, get_next_blame, set_next_blame, compare_fn); -} - -static int compare_commits_by_reverse_commit_date(const void *a, - const void *b, - void *c) -{ - return -compare_commits_by_commit_date(a, b, c); -} - -/* - * The current state of the blame assignment. - */ -struct scoreboard { - /* the final commit (i.e. where we started digging from) */ - struct commit *final; - /* Priority queue for commits with unassigned blame records */ - struct prio_queue commits; - struct rev_info *revs; - const char *path; - - /* - * The contents in the final image. - * Used by many functions to obtain contents of the nth line, - * indexed with scoreboard.lineno[blame_entry.lno]. - */ - const char *final_buf; - unsigned long final_buf_size; - - /* linked list of blames */ - struct blame_entry *ent; - - /* look-up a line in the final buffer */ - int num_lines; - int *lineno; -}; - -static void sanity_check_refcnt(struct scoreboard *); - -/* - * If two blame entries that are next to each other came from - * contiguous lines in the same origin (i.e. <commit, path> pair), - * merge them together. - */ -static void coalesce(struct scoreboard *sb) -{ - struct blame_entry *ent, *next; - - for (ent = sb->ent; ent && (next = ent->next); ent = next) { - if (ent->suspect == next->suspect && - ent->s_lno + ent->num_lines == next->s_lno) { - ent->num_lines += next->num_lines; - ent->next = next->next; - origin_decref(next->suspect); - free(next); - ent->score = 0; - next = ent; /* again */ - } - } - - if (DEBUG) /* sanity */ - sanity_check_refcnt(sb); -} - -/* - * Merge the given sorted list of blames into a preexisting origin. - * If there were no previous blames to that commit, it is entered into - * the commit priority queue of the score board. - */ - -static void queue_blames(struct scoreboard *sb, struct origin *porigin, - struct blame_entry *sorted) -{ - if (porigin->suspects) - porigin->suspects = blame_merge(porigin->suspects, sorted); - else { - struct origin *o; - for (o = porigin->commit->util; o; o = o->next) { - if (o->suspects) { - porigin->suspects = sorted; - return; - } - } - porigin->suspects = sorted; - prio_queue_put(&sb->commits, porigin->commit); - } -} - -/* - * Given a commit and a path in it, create a new origin structure. - * The callers that add blame to the scoreboard should use - * get_origin() to obtain shared, refcounted copy instead of calling - * this function directly. - */ -static struct origin *make_origin(struct commit *commit, const char *path) -{ - struct origin *o; - FLEX_ALLOC_STR(o, path, path); - o->commit = commit; - o->refcnt = 1; - o->next = commit->util; - commit->util = o; - return o; -} - -/* - * Locate an existing origin or create a new one. - * This moves the origin to front position in the commit util list. - */ -static struct origin *get_origin(struct scoreboard *sb, - struct commit *commit, - const char *path) -{ - struct origin *o, *l; - - for (o = commit->util, l = NULL; o; l = o, o = o->next) { - if (!strcmp(o->path, path)) { - /* bump to front */ - if (l) { - l->next = o->next; - o->next = commit->util; - commit->util = o; - } - return origin_incref(o); - } - } - return make_origin(commit, path); -} - -/* - * Fill the blob_sha1 field of an origin if it hasn't, so that later - * call to fill_origin_blob() can use it to locate the data. blob_sha1 - * for an origin is also used to pass the blame for the entire file to - * the parent to detect the case where a child's blob is identical to - * that of its parent's. - * - * This also fills origin->mode for corresponding tree path. - */ -static int fill_blob_sha1_and_mode(struct origin *origin) -{ - if (!is_null_oid(&origin->blob_oid)) - return 0; - if (get_tree_entry(origin->commit->object.oid.hash, - origin->path, - origin->blob_oid.hash, &origin->mode)) - goto error_out; - if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB) - goto error_out; - return 0; - error_out: - oidclr(&origin->blob_oid); - origin->mode = S_IFINVALID; - return -1; -} - -/* - * We have an origin -- check if the same path exists in the - * parent and return an origin structure to represent it. - */ -static struct origin *find_origin(struct scoreboard *sb, - struct commit *parent, - struct origin *origin) -{ - struct origin *porigin; - struct diff_options diff_opts; - const char *paths[2]; - - /* First check any existing origins */ - for (porigin = parent->util; porigin; porigin = porigin->next) - if (!strcmp(porigin->path, origin->path)) { - /* - * The same path between origin and its parent - * without renaming -- the most common case. - */ - return origin_incref (porigin); - } - - /* See if the origin->path is different between parent - * and origin first. Most of the time they are the - * same and diff-tree is fairly efficient about this. - */ - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.detect_rename = 0; - diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - paths[0] = origin->path; - paths[1] = NULL; - - parse_pathspec(&diff_opts.pathspec, - PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, - PATHSPEC_LITERAL_PATH, "", paths); - diff_setup_done(&diff_opts); - - if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(&parent->tree->object.oid, &diff_opts); - else - diff_tree_sha1(parent->tree->object.oid.hash, - origin->commit->tree->object.oid.hash, - "", &diff_opts); - diffcore_std(&diff_opts); - - if (!diff_queued_diff.nr) { - /* The path is the same as parent */ - porigin = get_origin(sb, parent, origin->path); - oidcpy(&porigin->blob_oid, &origin->blob_oid); - porigin->mode = origin->mode; - } else { - /* - * Since origin->path is a pathspec, if the parent - * commit had it as a directory, we will see a whole - * bunch of deletion of files in the directory that we - * do not care about. - */ - int i; - struct diff_filepair *p = NULL; - for (i = 0; i < diff_queued_diff.nr; i++) { - const char *name; - p = diff_queued_diff.queue[i]; - name = p->one->path ? p->one->path : p->two->path; - if (!strcmp(name, origin->path)) - break; - } - if (!p) - die("internal error in blame::find_origin"); - switch (p->status) { - default: - die("internal error in blame::find_origin (%c)", - p->status); - case 'M': - porigin = get_origin(sb, parent, origin->path); - oidcpy(&porigin->blob_oid, &p->one->oid); - porigin->mode = p->one->mode; - break; - case 'A': - case 'T': - /* Did not exist in parent, or type changed */ - break; - } - } - diff_flush(&diff_opts); - clear_pathspec(&diff_opts.pathspec); - return porigin; -} - -/* - * We have an origin -- find the path that corresponds to it in its - * parent and return an origin structure to represent it. - */ -static struct origin *find_rename(struct scoreboard *sb, - struct commit *parent, - struct origin *origin) -{ - struct origin *porigin = NULL; - struct diff_options diff_opts; - int i; - - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.detect_rename = DIFF_DETECT_RENAME; - diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - diff_opts.single_follow = origin->path; - diff_setup_done(&diff_opts); - - if (is_null_oid(&origin->commit->object.oid)) - do_diff_cache(&parent->tree->object.oid, &diff_opts); - else - diff_tree_sha1(parent->tree->object.oid.hash, - origin->commit->tree->object.oid.hash, - "", &diff_opts); - diffcore_std(&diff_opts); - - for (i = 0; i < diff_queued_diff.nr; i++) { - struct diff_filepair *p = diff_queued_diff.queue[i]; - if ((p->status == 'R' || p->status == 'C') && - !strcmp(p->two->path, origin->path)) { - porigin = get_origin(sb, parent, p->one->path); - oidcpy(&porigin->blob_oid, &p->one->oid); - porigin->mode = p->one->mode; - break; - } - } - diff_flush(&diff_opts); - clear_pathspec(&diff_opts.pathspec); - return porigin; -} - -/* - * Append a new blame entry to a given output queue. - */ -static void add_blame_entry(struct blame_entry ***queue, - const struct blame_entry *src) -{ - struct blame_entry *e = xmalloc(sizeof(*e)); - memcpy(e, src, sizeof(*e)); - origin_incref(e->suspect); - - e->next = **queue; - **queue = e; - *queue = &e->next; -} - -/* - * src typically is on-stack; we want to copy the information in it to - * a malloced blame_entry that gets added to the given queue. The - * origin of dst loses a refcnt. - */ -static void dup_entry(struct blame_entry ***queue, - struct blame_entry *dst, struct blame_entry *src) -{ - origin_incref(src->suspect); - origin_decref(dst->suspect); - memcpy(dst, src, sizeof(*src)); - dst->next = **queue; - **queue = dst; - *queue = &dst->next; -} - -static const char *nth_line(struct scoreboard *sb, long lno) -{ - return sb->final_buf + sb->lineno[lno]; -} - static const char *nth_line_cb(void *data, long lno) { - return nth_line((struct scoreboard *)data, lno); -} - -/* - * It is known that lines between tlno to same came from parent, and e - * has an overlap with that range. it also is known that parent's - * line plno corresponds to e's line tlno. - * - * <---- e -----> - * <------> - * <------------> - * <------------> - * <------------------> - * - * Split e into potentially three parts; before this chunk, the chunk - * to be blamed for the parent, and after that portion. - */ -static void split_overlap(struct blame_entry *split, - struct blame_entry *e, - int tlno, int plno, int same, - struct origin *parent) -{ - int chunk_end_lno; - memset(split, 0, sizeof(struct blame_entry [3])); - - if (e->s_lno < tlno) { - /* there is a pre-chunk part not blamed on parent */ - split[0].suspect = origin_incref(e->suspect); - split[0].lno = e->lno; - split[0].s_lno = e->s_lno; - split[0].num_lines = tlno - e->s_lno; - split[1].lno = e->lno + tlno - e->s_lno; - split[1].s_lno = plno; - } - else { - split[1].lno = e->lno; - split[1].s_lno = plno + (e->s_lno - tlno); - } - - if (same < e->s_lno + e->num_lines) { - /* there is a post-chunk part not blamed on parent */ - split[2].suspect = origin_incref(e->suspect); - split[2].lno = e->lno + (same - e->s_lno); - split[2].s_lno = e->s_lno + (same - e->s_lno); - split[2].num_lines = e->s_lno + e->num_lines - same; - chunk_end_lno = split[2].lno; - } - else - chunk_end_lno = e->lno + e->num_lines; - split[1].num_lines = chunk_end_lno - split[1].lno; - - /* - * if it turns out there is nothing to blame the parent for, - * forget about the splitting. !split[1].suspect signals this. - */ - if (split[1].num_lines < 1) - return; - split[1].suspect = origin_incref(parent); -} - -/* - * split_overlap() divided an existing blame e into up to three parts - * in split. Any assigned blame is moved to queue to - * reflect the split. - */ -static void split_blame(struct blame_entry ***blamed, - struct blame_entry ***unblamed, - struct blame_entry *split, - struct blame_entry *e) -{ - if (split[0].suspect && split[2].suspect) { - /* The first part (reuse storage for the existing entry e) */ - dup_entry(unblamed, e, &split[0]); - - /* The last part -- me */ - add_blame_entry(unblamed, &split[2]); - - /* ... and the middle part -- parent */ - add_blame_entry(blamed, &split[1]); - } - else if (!split[0].suspect && !split[2].suspect) - /* - * The parent covers the entire area; reuse storage for - * e and replace it with the parent. - */ - dup_entry(blamed, e, &split[1]); - else if (split[0].suspect) { - /* me and then parent */ - dup_entry(unblamed, e, &split[0]); - add_blame_entry(blamed, &split[1]); - } - else { - /* parent and then me */ - dup_entry(blamed, e, &split[1]); - add_blame_entry(unblamed, &split[2]); - } -} - -/* - * After splitting the blame, the origins used by the - * on-stack blame_entry should lose one refcnt each. - */ -static void decref_split(struct blame_entry *split) -{ - int i; - - for (i = 0; i < 3; i++) - origin_decref(split[i].suspect); -} - -/* - * reverse_blame reverses the list given in head, appending tail. - * That allows us to build lists in reverse order, then reverse them - * afterwards. This can be faster than building the list in proper - * order right away. The reason is that building in proper order - * requires writing a link in the _previous_ element, while building - * in reverse order just requires placing the list head into the - * _current_ element. - */ - -static struct blame_entry *reverse_blame(struct blame_entry *head, - struct blame_entry *tail) -{ - while (head) { - struct blame_entry *next = head->next; - head->next = tail; - tail = head; - head = next; - } - return tail; -} - -/* - * Process one hunk from the patch between the current suspect for - * blame_entry e and its parent. This first blames any unfinished - * entries before the chunk (which is where target and parent start - * differing) on the parent, and then splits blame entries at the - * start and at the end of the difference region. Since use of -M and - * -C options may lead to overlapping/duplicate source line number - * ranges, all we can rely on from sorting/merging is the order of the - * first suspect line number. - */ -static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq, - int tlno, int offset, int same, - struct origin *parent) -{ - struct blame_entry *e = **srcq; - struct blame_entry *samep = NULL, *diffp = NULL; - - while (e && e->s_lno < tlno) { - struct blame_entry *next = e->next; - /* - * current record starts before differing portion. If - * it reaches into it, we need to split it up and - * examine the second part separately. - */ - if (e->s_lno + e->num_lines > tlno) { - /* Move second half to a new record */ - int len = tlno - e->s_lno; - struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry)); - n->suspect = e->suspect; - n->lno = e->lno + len; - n->s_lno = e->s_lno + len; - n->num_lines = e->num_lines - len; - e->num_lines = len; - e->score = 0; - /* Push new record to diffp */ - n->next = diffp; - diffp = n; - } else - origin_decref(e->suspect); - /* Pass blame for everything before the differing - * chunk to the parent */ - e->suspect = origin_incref(parent); - e->s_lno += offset; - e->next = samep; - samep = e; - e = next; - } - /* - * As we don't know how much of a common stretch after this - * diff will occur, the currently blamed parts are all that we - * can assign to the parent for now. - */ - - if (samep) { - **dstq = reverse_blame(samep, **dstq); - *dstq = &samep->next; - } - /* - * Prepend the split off portions: everything after e starts - * after the blameable portion. - */ - e = reverse_blame(diffp, e); - - /* - * Now retain records on the target while parts are different - * from the parent. - */ - samep = NULL; - diffp = NULL; - while (e && e->s_lno < same) { - struct blame_entry *next = e->next; - - /* - * If current record extends into sameness, need to split. - */ - if (e->s_lno + e->num_lines > same) { - /* - * Move second half to a new record to be - * processed by later chunks - */ - int len = same - e->s_lno; - struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry)); - n->suspect = origin_incref(e->suspect); - n->lno = e->lno + len; - n->s_lno = e->s_lno + len; - n->num_lines = e->num_lines - len; - e->num_lines = len; - e->score = 0; - /* Push new record to samep */ - n->next = samep; - samep = n; - } - e->next = diffp; - diffp = e; - e = next; - } - **srcq = reverse_blame(diffp, reverse_blame(samep, e)); - /* Move across elements that are in the unblamable portion */ - if (diffp) - *srcq = &diffp->next; -} - -struct blame_chunk_cb_data { - struct origin *parent; - long offset; - struct blame_entry **dstq; - struct blame_entry **srcq; -}; - -/* diff chunks are from parent to target */ -static int blame_chunk_cb(long start_a, long count_a, - long start_b, long count_b, void *data) -{ - struct blame_chunk_cb_data *d = data; - if (start_a - start_b != d->offset) - die("internal error in blame::blame_chunk_cb"); - blame_chunk(&d->dstq, &d->srcq, start_b, start_a - start_b, - start_b + count_b, d->parent); - d->offset = start_a + count_a - (start_b + count_b); - return 0; -} - -/* - * We are looking at the origin 'target' and aiming to pass blame - * for the lines it is suspected to its parent. Run diff to find - * which lines came from parent and pass blame for them. - */ -static void pass_blame_to_parent(struct scoreboard *sb, - struct origin *target, - struct origin *parent) -{ - mmfile_t file_p, file_o; - struct blame_chunk_cb_data d; - struct blame_entry *newdest = NULL; - - if (!target->suspects) - return; /* nothing remains for this target */ - - d.parent = parent; - d.offset = 0; - d.dstq = &newdest; d.srcq = &target->suspects; - - fill_origin_blob(&sb->revs->diffopt, parent, &file_p); - fill_origin_blob(&sb->revs->diffopt, target, &file_o); - num_get_patch++; - - if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d)) - die("unable to generate diff (%s -> %s)", - oid_to_hex(&parent->commit->object.oid), - oid_to_hex(&target->commit->object.oid)); - /* The rest are the same as the parent */ - blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent); - *d.dstq = NULL; - queue_blames(sb, parent, newdest); - - return; -} - -/* - * The lines in blame_entry after splitting blames many times can become - * very small and trivial, and at some point it becomes pointless to - * blame the parents. E.g. "\t\t}\n\t}\n\n" appears everywhere in any - * ordinary C program, and it is not worth to say it was copied from - * totally unrelated file in the parent. - * - * Compute how trivial the lines in the blame_entry are. - */ -static unsigned ent_score(struct scoreboard *sb, struct blame_entry *e) -{ - unsigned score; - const char *cp, *ep; - - if (e->score) - return e->score; - - score = 1; - cp = nth_line(sb, e->lno); - ep = nth_line(sb, e->lno + e->num_lines); - while (cp < ep) { - unsigned ch = *((unsigned char *)cp); - if (isalnum(ch)) - score++; - cp++; - } - e->score = score; - return score; -} - -/* - * best_so_far[] and this[] are both a split of an existing blame_entry - * that passes blame to the parent. Maintain best_so_far the best split - * so far, by comparing this and best_so_far and copying this into - * bst_so_far as needed. - */ -static void copy_split_if_better(struct scoreboard *sb, - struct blame_entry *best_so_far, - struct blame_entry *this) -{ - int i; - - if (!this[1].suspect) - return; - if (best_so_far[1].suspect) { - if (ent_score(sb, &this[1]) < ent_score(sb, &best_so_far[1])) - return; - } - - for (i = 0; i < 3; i++) - origin_incref(this[i].suspect); - decref_split(best_so_far); - memcpy(best_so_far, this, sizeof(struct blame_entry [3])); -} - -/* - * We are looking at a part of the final image represented by - * ent (tlno and same are offset by ent->s_lno). - * tlno is where we are looking at in the final image. - * up to (but not including) same match preimage. - * plno is where we are looking at in the preimage. - * - * <-------------- final image ----------------------> - * <------ent------> - * ^tlno ^same - * <---------preimage-----> - * ^plno - * - * All line numbers are 0-based. - */ -static void handle_split(struct scoreboard *sb, - struct blame_entry *ent, - int tlno, int plno, int same, - struct origin *parent, - struct blame_entry *split) -{ - if (ent->num_lines <= tlno) - return; - if (tlno < same) { - struct blame_entry this[3]; - tlno += ent->s_lno; - same += ent->s_lno; - split_overlap(this, ent, tlno, plno, same, parent); - copy_split_if_better(sb, split, this); - decref_split(this); - } -} - -struct handle_split_cb_data { - struct scoreboard *sb; - struct blame_entry *ent; - struct origin *parent; - struct blame_entry *split; - long plno; - long tlno; -}; - -static int handle_split_cb(long start_a, long count_a, - long start_b, long count_b, void *data) -{ - struct handle_split_cb_data *d = data; - handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent, - d->split); - d->plno = start_a + count_a; - d->tlno = start_b + count_b; - return 0; -} - -/* - * Find the lines from parent that are the same as ent so that - * we can pass blames to it. file_p has the blob contents for - * the parent. - */ -static void find_copy_in_blob(struct scoreboard *sb, - struct blame_entry *ent, - struct origin *parent, - struct blame_entry *split, - mmfile_t *file_p) -{ - const char *cp; - mmfile_t file_o; - struct handle_split_cb_data d; - - 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. - */ - cp = nth_line(sb, ent->lno); - file_o.ptr = (char *) cp; - file_o.size = nth_line(sb, ent->lno + ent->num_lines) - cp; - - /* - * file_o is a part of final image we are annotating. - * file_p partially may match that image. - */ - memset(split, 0, sizeof(struct blame_entry [3])); - if (diff_hunks(file_p, &file_o, handle_split_cb, &d)) - die("unable to generate diff (%s)", - oid_to_hex(&parent->commit->object.oid)); - /* remainder, if any, all match the preimage */ - handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split); -} - -/* Move all blame entries from list *source that have a score smaller - * than score_min to the front of list *small. - * Returns a pointer to the link pointing to the old head of the small list. - */ - -static struct blame_entry **filter_small(struct scoreboard *sb, - struct blame_entry **small, - struct blame_entry **source, - unsigned score_min) -{ - struct blame_entry *p = *source; - struct blame_entry *oldsmall = *small; - while (p) { - if (ent_score(sb, p) <= score_min) { - *small = p; - small = &p->next; - p = *small; - } else { - *source = p; - source = &p->next; - p = *source; - } - } - *small = oldsmall; - *source = NULL; - return small; -} - -/* - * See if lines currently target is suspected for can be attributed to - * parent. - */ -static void find_move_in_parent(struct scoreboard *sb, - struct blame_entry ***blamed, - struct blame_entry **toosmall, - struct origin *target, - struct origin *parent) -{ - struct blame_entry *e, split[3]; - struct blame_entry *unblamed = target->suspects; - struct blame_entry *leftover = NULL; - mmfile_t file_p; - - if (!unblamed) - return; /* nothing remains for this target */ - - fill_origin_blob(&sb->revs->diffopt, parent, &file_p); - if (!file_p.ptr) - return; - - /* At each iteration, unblamed has a NULL-terminated list of - * entries that have not yet been tested for blame. leftover - * contains the reversed list of entries that have been tested - * without being assignable to the parent. - */ - do { - struct blame_entry **unblamedtail = &unblamed; - struct blame_entry *next; - for (e = unblamed; e; e = next) { - next = e->next; - find_copy_in_blob(sb, e, parent, split, &file_p); - if (split[1].suspect && - blame_move_score < ent_score(sb, &split[1])) { - split_blame(blamed, &unblamedtail, split, e); - } else { - e->next = leftover; - leftover = e; - } - decref_split(split); - } - *unblamedtail = NULL; - toosmall = filter_small(sb, toosmall, &unblamed, blame_move_score); - } while (unblamed); - target->suspects = reverse_blame(leftover, NULL); -} - -struct blame_list { - struct blame_entry *ent; - struct blame_entry split[3]; -}; - -/* - * Count the number of entries the target is suspected for, - * and prepare a list of entry and the best split. - */ -static struct blame_list *setup_blame_list(struct blame_entry *unblamed, - int *num_ents_p) -{ - struct blame_entry *e; - int num_ents, i; - struct blame_list *blame_list = NULL; - - for (e = unblamed, num_ents = 0; e; e = e->next) - num_ents++; - if (num_ents) { - blame_list = xcalloc(num_ents, sizeof(struct blame_list)); - for (e = unblamed, i = 0; e; e = e->next) - blame_list[i++].ent = e; - } - *num_ents_p = num_ents; - return blame_list; -} - -/* - * For lines target is suspected for, see if we can find code movement - * across file boundary from the parent commit. porigin is the path - * in the parent we already tried. - */ -static void find_copy_in_parent(struct scoreboard *sb, - struct blame_entry ***blamed, - struct blame_entry **toosmall, - struct origin *target, - struct commit *parent, - struct origin *porigin, - int opt) -{ - struct diff_options diff_opts; - int i, j; - struct blame_list *blame_list; - int num_ents; - struct blame_entry *unblamed = target->suspects; - struct blame_entry *leftover = NULL; - - if (!unblamed) - return; /* nothing remains for this target */ - - diff_setup(&diff_opts); - DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - - diff_setup_done(&diff_opts); - - /* Try "find copies harder" on new path if requested; - * we do not want to use diffcore_rename() actually to - * match things up; find_copies_harder is set only to - * force diff_tree_sha1() to feed all filepairs to diff_queue, - * and this code needs to be after diff_setup_done(), which - * usually makes find-copies-harder imply copy detection. - */ - if ((opt & PICKAXE_BLAME_COPY_HARDEST) - || ((opt & PICKAXE_BLAME_COPY_HARDER) - && (!porigin || strcmp(target->path, porigin->path)))) - DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); - - if (is_null_oid(&target->commit->object.oid)) - do_diff_cache(&parent->tree->object.oid, &diff_opts); - else - diff_tree_sha1(parent->tree->object.oid.hash, - target->commit->tree->object.oid.hash, - "", &diff_opts); - - if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER)) - diffcore_std(&diff_opts); - - do { - struct blame_entry **unblamedtail = &unblamed; - blame_list = setup_blame_list(unblamed, &num_ents); - - for (i = 0; i < diff_queued_diff.nr; i++) { - struct diff_filepair *p = diff_queued_diff.queue[i]; - struct origin *norigin; - mmfile_t file_p; - struct blame_entry this[3]; - - if (!DIFF_FILE_VALID(p->one)) - continue; /* does not exist in parent */ - if (S_ISGITLINK(p->one->mode)) - continue; /* ignore git links */ - if (porigin && !strcmp(p->one->path, porigin->path)) - /* find_move already dealt with this path */ - continue; - - norigin = get_origin(sb, parent, p->one->path); - oidcpy(&norigin->blob_oid, &p->one->oid); - norigin->mode = p->one->mode; - fill_origin_blob(&sb->revs->diffopt, norigin, &file_p); - if (!file_p.ptr) - continue; - - for (j = 0; j < num_ents; j++) { - find_copy_in_blob(sb, blame_list[j].ent, - norigin, this, &file_p); - copy_split_if_better(sb, blame_list[j].split, - this); - decref_split(this); - } - origin_decref(norigin); - } - - for (j = 0; j < num_ents; j++) { - struct blame_entry *split = blame_list[j].split; - if (split[1].suspect && - blame_copy_score < ent_score(sb, &split[1])) { - split_blame(blamed, &unblamedtail, split, - blame_list[j].ent); - } else { - blame_list[j].ent->next = leftover; - leftover = blame_list[j].ent; - } - decref_split(split); - } - free(blame_list); - *unblamedtail = NULL; - toosmall = filter_small(sb, toosmall, &unblamed, blame_copy_score); - } while (unblamed); - target->suspects = reverse_blame(leftover, NULL); - diff_flush(&diff_opts); - clear_pathspec(&diff_opts.pathspec); -} - -/* - * The blobs of origin and porigin exactly match, so everything - * origin is suspected for can be blamed on the parent. - */ -static void pass_whole_blame(struct scoreboard *sb, - struct origin *origin, struct origin *porigin) -{ - struct blame_entry *e, *suspects; - - if (!porigin->file.ptr && origin->file.ptr) { - /* Steal its file */ - porigin->file = origin->file; - origin->file.ptr = NULL; - } - suspects = origin->suspects; - origin->suspects = NULL; - for (e = suspects; e; e = e->next) { - origin_incref(porigin); - origin_decref(e->suspect); - e->suspect = porigin; - } - queue_blames(sb, porigin, suspects); -} - -/* - * We pass blame from the current commit to its parents. We keep saying - * "parent" (and "porigin"), but what we mean is to find scapegoat to - * exonerate ourselves. - */ -static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit) -{ - if (!reverse) { - if (revs->first_parent_only && - commit->parents && - commit->parents->next) { - free_commit_list(commit->parents->next); - commit->parents->next = NULL; - } - return commit->parents; - } - return lookup_decoration(&revs->children, &commit->object); -} - -static int num_scapegoats(struct rev_info *revs, struct commit *commit) -{ - struct commit_list *l = first_scapegoat(revs, commit); - return commit_list_count(l); -} - -/* Distribute collected unsorted blames to the respected sorted lists - * in the various origins. - */ -static void distribute_blame(struct scoreboard *sb, struct blame_entry *blamed) -{ - blamed = blame_sort(blamed, compare_blame_suspect); - while (blamed) - { - struct origin *porigin = blamed->suspect; - struct blame_entry *suspects = NULL; - do { - struct blame_entry *next = blamed->next; - blamed->next = suspects; - suspects = blamed; - blamed = next; - } while (blamed && blamed->suspect == porigin); - suspects = reverse_blame(suspects, NULL); - queue_blames(sb, porigin, suspects); - } -} - -#define MAXSG 16 - -static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt) -{ - struct rev_info *revs = sb->revs; - int i, pass, num_sg; - struct commit *commit = origin->commit; - struct commit_list *sg; - struct origin *sg_buf[MAXSG]; - struct origin *porigin, **sg_origin = sg_buf; - struct blame_entry *toosmall = NULL; - struct blame_entry *blames, **blametail = &blames; - - num_sg = num_scapegoats(revs, commit); - if (!num_sg) - goto finish; - else if (num_sg < ARRAY_SIZE(sg_buf)) - memset(sg_buf, 0, sizeof(sg_buf)); - else - sg_origin = xcalloc(num_sg, sizeof(*sg_origin)); - - /* - * The first pass looks for unrenamed path to optimize for - * common cases, then we look for renames in the second pass. - */ - for (pass = 0; pass < 2 - no_whole_file_rename; pass++) { - struct origin *(*find)(struct scoreboard *, - struct commit *, struct origin *); - find = pass ? find_rename : find_origin; - - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct commit *p = sg->item; - int j, same; - - if (sg_origin[i]) - continue; - if (parse_commit(p)) - continue; - porigin = find(sb, p, origin); - if (!porigin) - continue; - if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) { - pass_whole_blame(sb, origin, porigin); - origin_decref(porigin); - goto finish; - } - for (j = same = 0; j < i; j++) - if (sg_origin[j] && - !oidcmp(&sg_origin[j]->blob_oid, &porigin->blob_oid)) { - same = 1; - break; - } - if (!same) - sg_origin[i] = porigin; - else - origin_decref(porigin); - } - } - - num_commits++; - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct origin *porigin = sg_origin[i]; - if (!porigin) - continue; - if (!origin->previous) { - origin_incref(porigin); - origin->previous = porigin; - } - pass_blame_to_parent(sb, origin, porigin); - if (!origin->suspects) - goto finish; - } - - /* - * Optionally find moves in parents' files. - */ - if (opt & PICKAXE_BLAME_MOVE) { - filter_small(sb, &toosmall, &origin->suspects, blame_move_score); - if (origin->suspects) { - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct origin *porigin = sg_origin[i]; - if (!porigin) - continue; - find_move_in_parent(sb, &blametail, &toosmall, origin, porigin); - if (!origin->suspects) - break; - } - } - } - - /* - * Optionally find copies from parents' files. - */ - if (opt & PICKAXE_BLAME_COPY) { - if (blame_copy_score > blame_move_score) - filter_small(sb, &toosmall, &origin->suspects, blame_copy_score); - else if (blame_copy_score < blame_move_score) { - origin->suspects = blame_merge(origin->suspects, toosmall); - toosmall = NULL; - filter_small(sb, &toosmall, &origin->suspects, blame_copy_score); - } - if (!origin->suspects) - goto finish; - - for (i = 0, sg = first_scapegoat(revs, commit); - i < num_sg && sg; - sg = sg->next, i++) { - struct origin *porigin = sg_origin[i]; - find_copy_in_parent(sb, &blametail, &toosmall, - origin, sg->item, porigin, opt); - if (!origin->suspects) - goto finish; - } - } - -finish: - *blametail = NULL; - distribute_blame(sb, blames); - /* - * prepend toosmall to origin->suspects - * - * There is no point in sorting: this ends up on a big - * unsorted list in the caller anyway. - */ - if (toosmall) { - struct blame_entry **tail = &toosmall; - while (*tail) - tail = &(*tail)->next; - *tail = origin->suspects; - origin->suspects = toosmall; - } - for (i = 0; i < num_sg; i++) { - if (sg_origin[i]) { - drop_origin_blob(sg_origin[i]); - origin_decref(sg_origin[i]); - } - } - drop_origin_blob(origin); - if (sg_buf != sg_origin) - free(sg_origin); + return blame_nth_line((struct blame_scoreboard *)data, lno); } /* @@ -1699,10 +217,10 @@ static void get_commit_info(struct commit *commit, * To allow LF and other nonportable characters in pathnames, * they are c-style quoted as needed. */ -static void write_filename_info(struct origin *suspect) +static void write_filename_info(struct blame_origin *suspect) { if (suspect->previous) { - struct origin *prev = suspect->previous; + struct blame_origin *prev = suspect->previous; printf("previous %s ", oid_to_hex(&prev->commit->object.oid)); write_name_quoted(prev->path, stdout, '\n'); } @@ -1716,7 +234,7 @@ static void write_filename_info(struct origin *suspect) * the first time each commit appears in the output (unless the * user has specifically asked for us to repeat). */ -static int emit_one_suspect_detail(struct origin *suspect, int repeat) +static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat) { struct commit_info ci; @@ -1746,11 +264,12 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat) * The blame_entry is found to be guilty for the range. * Show it in incremental output. */ -static void found_guilty_entry(struct blame_entry *ent, - struct progress_info *pi) +static void found_guilty_entry(struct blame_entry *ent, void *data) { + struct progress_info *pi = (struct progress_info *)data; + if (incremental) { - struct origin *suspect = ent->suspect; + struct blame_origin *suspect = ent->suspect; printf("%s %d %d %d\n", oid_to_hex(&suspect->commit->object.oid), @@ -1763,80 +282,6 @@ static void found_guilty_entry(struct blame_entry *ent, display_progress(pi->progress, pi->blamed_lines); } -/* - * The main loop -- while we have blobs with lines whose true origin - * is still unknown, pick one blob, and allow its lines to pass blames - * to its parents. */ -static void assign_blame(struct scoreboard *sb, int opt) -{ - struct rev_info *revs = sb->revs; - struct commit *commit = prio_queue_get(&sb->commits); - struct progress_info pi = { NULL, 0 }; - - if (show_progress) - pi.progress = start_progress_delay(_("Blaming lines"), - sb->num_lines, 50, 1); - - while (commit) { - struct blame_entry *ent; - struct origin *suspect = commit->util; - - /* find one suspect to break down */ - while (suspect && !suspect->suspects) - suspect = suspect->next; - - if (!suspect) { - commit = prio_queue_get(&sb->commits); - continue; - } - - assert(commit == suspect->commit); - - /* - * We will use this suspect later in the loop, - * so hold onto it in the meantime. - */ - origin_incref(suspect); - parse_commit(commit); - if (reverse || - (!(commit->object.flags & UNINTERESTING) && - !(revs->max_age != -1 && commit->date < revs->max_age))) - pass_blame(sb, suspect, opt); - else { - commit->object.flags |= UNINTERESTING; - if (commit->object.parsed) - mark_parents_uninteresting(commit); - } - /* treat root commit as boundary */ - if (!commit->parents && !show_root) - commit->object.flags |= UNINTERESTING; - - /* Take responsibility for the remaining entries */ - ent = suspect->suspects; - if (ent) { - suspect->guilty = 1; - for (;;) { - struct blame_entry *next = ent->next; - found_guilty_entry(ent, &pi); - if (next) { - ent = next; - continue; - } - ent->next = sb->ent; - sb->ent = suspect->suspects; - suspect->suspects = NULL; - break; - } - } - origin_decref(suspect); - - if (DEBUG) /* sanity */ - sanity_check_refcnt(sb); - } - - stop_progress(&pi.progress); -} - static const char *format_time(timestamp_t time, const char *tz_str, int show_raw_time) { @@ -1876,20 +321,20 @@ static const char *format_time(timestamp_t time, const char *tz_str, #define OUTPUT_SHOW_EMAIL 0400 #define OUTPUT_LINE_PORCELAIN 01000 -static void emit_porcelain_details(struct origin *suspect, int repeat) +static void emit_porcelain_details(struct blame_origin *suspect, int repeat) { if (emit_one_suspect_detail(suspect, repeat) || (suspect->commit->object.flags & MORE_THAN_ONE_PATH)) write_filename_info(suspect); } -static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, +static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent, int opt) { int repeat = opt & OUTPUT_LINE_PORCELAIN; int cnt; const char *cp; - struct origin *suspect = ent->suspect; + struct blame_origin *suspect = ent->suspect; char hex[GIT_MAX_HEXSZ + 1]; oid_to_hex_r(hex, &suspect->commit->object.oid); @@ -1900,7 +345,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, ent->num_lines); emit_porcelain_details(suspect, repeat); - cp = nth_line(sb, ent->lno); + cp = blame_nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; if (cnt) { @@ -1922,11 +367,11 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, putchar('\n'); } -static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) +static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt) { int cnt; const char *cp; - struct origin *suspect = ent->suspect; + struct blame_origin *suspect = ent->suspect; struct commit_info ci; char hex[GIT_MAX_HEXSZ + 1]; int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP); @@ -1934,7 +379,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) get_commit_info(suspect->commit, &ci, 1); oid_to_hex_r(hex, &suspect->commit->object.oid); - cp = nth_line(sb, ent->lno); + cp = blame_nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev; @@ -2001,14 +446,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) commit_info_destroy(&ci); } -static void output(struct scoreboard *sb, int option) +static void output(struct blame_scoreboard *sb, int option) { struct blame_entry *ent; if (option & OUTPUT_PORCELAIN) { for (ent = sb->ent; ent; ent = ent->next) { int count = 0; - struct origin *suspect; + struct blame_origin *suspect; struct commit *commit = ent->suspect->commit; if (commit->object.flags & MORE_THAN_ONE_PATH) continue; @@ -2030,40 +475,6 @@ static void output(struct scoreboard *sb, int option) } } -static const char *get_next_line(const char *start, const char *end) -{ - const char *nl = memchr(start, '\n', end - start); - return nl ? nl + 1 : end; -} - -/* - * To allow quick access to the contents of nth line in the - * final image, prepare an index in the scoreboard. - */ -static int prepare_lines(struct scoreboard *sb) -{ - const char *buf = sb->final_buf; - unsigned long len = sb->final_buf_size; - const char *end = buf + len; - const char *p; - int *lineno; - int num = 0; - - for (p = buf; p < end; p = get_next_line(p, end)) - num++; - - ALLOC_ARRAY(sb->lineno, num + 1); - lineno = sb->lineno; - - for (p = buf; p < end; p = get_next_line(p, end)) - *lineno++ = p - buf; - - *lineno = len; - - sb->num_lines = num; - return sb->num_lines; -} - /* * Add phony grafts for use with -S; this is primarily to * support git's cvsserver that wants to give a linear history @@ -2071,7 +482,7 @@ static int prepare_lines(struct scoreboard *sb) */ static int read_ancestry(const char *graft_file) { - FILE *fp = fopen(graft_file, "r"); + FILE *fp = fopen_or_warn(graft_file, "r"); struct strbuf buf = STRBUF_INIT; if (!fp) return -1; @@ -2086,7 +497,7 @@ static int read_ancestry(const char *graft_file) return 0; } -static int update_auto_abbrev(int auto_abbrev, struct origin *suspect) +static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect) { const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash, auto_abbrev); @@ -2100,7 +511,7 @@ static int update_auto_abbrev(int auto_abbrev, struct origin *suspect) * How many columns do we need to show line numbers, authors, * and filenames? */ -static void find_alignment(struct scoreboard *sb, int *option) +static void find_alignment(struct blame_scoreboard *sb, int *option) { int longest_src_lines = 0; int longest_dst_lines = 0; @@ -2110,7 +521,7 @@ static void find_alignment(struct scoreboard *sb, int *option) int auto_abbrev = DEFAULT_ABBREV; for (e = sb->ent; e; e = e->next) { - struct origin *suspect = e->suspect; + struct blame_origin *suspect = e->suspect; int num; if (compute_auto_abbrev) @@ -2138,8 +549,8 @@ static void find_alignment(struct scoreboard *sb, int *option) num = e->lno + e->num_lines; if (longest_dst_lines < num) longest_dst_lines = num; - if (largest_score < ent_score(sb, e)) - largest_score = ent_score(sb, e); + if (largest_score < blame_entry_score(sb, e)) + largest_score = blame_entry_score(sb, e); } max_orig_digits = decimal_width(longest_src_lines); max_digits = decimal_width(longest_dst_lines); @@ -2150,31 +561,12 @@ static void find_alignment(struct scoreboard *sb, int *option) abbrev = auto_abbrev + 1; } -/* - * For debugging -- origin is refcounted, and this asserts that - * we do not underflow. - */ -static void sanity_check_refcnt(struct scoreboard *sb) +static void sanity_check_on_fail(struct blame_scoreboard *sb, int baa) { - int baa = 0; - struct blame_entry *ent; - - for (ent = sb->ent; ent; ent = ent->next) { - /* Nobody should have zero or negative refcnt */ - if (ent->suspect->refcnt <= 0) { - fprintf(stderr, "%s in %s has negative refcnt %d\n", - ent->suspect->path, - oid_to_hex(&ent->suspect->commit->object.oid), - ent->suspect->refcnt); - baa = 1; - } - } - if (baa) { - int opt = 0160; - find_alignment(sb, &opt); - output(sb, opt); - die("Baa %d!", baa); - } + int opt = OUTPUT_SHOW_SCORE | OUTPUT_SHOW_NUMBER | OUTPUT_SHOW_NAME; + find_alignment(sb, &opt); + output(sb, opt); + die("Baa %d!", baa); } static unsigned parse_score(const char *arg) @@ -2224,301 +616,6 @@ static int git_blame_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } -static void verify_working_tree_path(struct commit *work_tree, const char *path) -{ - struct commit_list *parents; - int pos; - - for (parents = work_tree->parents; parents; parents = parents->next) { - const struct object_id *commit_oid = &parents->item->object.oid; - struct object_id blob_oid; - unsigned mode; - - if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) && - sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB) - return; - } - - pos = cache_name_pos(path, strlen(path)); - if (pos >= 0) - ; /* path is in the index */ - else if (-1 - pos < active_nr && - !strcmp(active_cache[-1 - pos]->name, path)) - ; /* path is in the index, unmerged */ - else - die("no such path '%s' in HEAD", path); -} - -static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid) -{ - struct commit *parent; - - parent = lookup_commit_reference(oid); - if (!parent) - die("no such commit %s", oid_to_hex(oid)); - return &commit_list_insert(parent, tail)->next; -} - -static void append_merge_parents(struct commit_list **tail) -{ - int merge_head; - struct strbuf line = STRBUF_INIT; - - merge_head = open(git_path_merge_head(), O_RDONLY); - if (merge_head < 0) { - if (errno == ENOENT) - return; - die("cannot open '%s' for reading", git_path_merge_head()); - } - - while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { - struct object_id oid; - if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid)) - die("unknown line in '%s': %s", git_path_merge_head(), line.buf); - tail = append_parent(tail, &oid); - } - close(merge_head); - strbuf_release(&line); -} - -/* - * This isn't as simple as passing sb->buf and sb->len, because we - * want to transfer ownership of the buffer to the commit (so we - * must use detach). - */ -static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb) -{ - size_t len; - void *buf = strbuf_detach(sb, &len); - set_commit_buffer(c, buf, len); -} - -/* - * 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(struct diff_options *opt, - const char *path, - const char *contents_from) -{ - struct commit *commit; - struct origin *origin; - struct commit_list **parent_tail, *parent; - struct object_id head_oid; - struct strbuf buf = STRBUF_INIT; - const char *ident; - time_t now; - int size, len; - struct cache_entry *ce; - unsigned mode; - struct strbuf msg = STRBUF_INIT; - - read_cache(); - time(&now); - commit = alloc_commit_node(); - commit->object.parsed = 1; - commit->date = now; - parent_tail = &commit->parents; - - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) - die("no such ref: HEAD"); - - parent_tail = append_parent(parent_tail, &head_oid); - append_merge_parents(parent_tail); - verify_working_tree_path(commit, path); - - origin = make_origin(commit, path); - - ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0); - strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n"); - for (parent = commit->parents; parent; parent = parent->next) - strbuf_addf(&msg, "parent %s\n", - oid_to_hex(&parent->item->object.oid)); - strbuf_addf(&msg, - "author %s\n" - "committer %s\n\n" - "Version of %s from %s\n", - ident, ident, path, - (!contents_from ? path : - (!strcmp(contents_from, "-") ? "standard input" : contents_from))); - set_commit_buffer_from_strbuf(commit, &msg); - - if (!contents_from || strcmp("-", contents_from)) { - struct stat st; - const char *read_from; - char *buf_ptr; - unsigned long buf_len; - - if (contents_from) { - if (stat(contents_from, &st) < 0) - die_errno("Cannot stat '%s'", contents_from); - read_from = contents_from; - } - else { - if (lstat(path, &st) < 0) - die_errno("Cannot lstat '%s'", path); - read_from = path; - } - mode = canon_mode(st.st_mode); - - switch (st.st_mode & S_IFMT) { - case S_IFREG: - if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && - textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len)) - strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1); - 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: - if (strbuf_readlink(&buf, read_from, st.st_size) < 0) - die_errno("cannot readlink '%s'", read_from); - break; - default: - die("unsupported file type %s", read_from); - } - } - else { - /* Reading from stdin */ - mode = 0; - if (strbuf_read(&buf, 0, 0) < 0) - die_errno("failed to read from stdin"); - } - convert_to_git(path, buf.buf, buf.len, &buf, 0); - origin->file.ptr = buf.buf; - origin->file.size = buf.len; - pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash); - - /* - * Read the current index, replace the path entry with - * origin->blob_sha1 without mucking with its mode or type - * bits; we are not going to write this index out -- we just - * want to run "diff-index --cached". - */ - discard_cache(); - read_cache(); - - len = strlen(path); - if (!mode) { - int pos = cache_name_pos(path, len); - if (0 <= pos) - mode = active_cache[pos]->ce_mode; - else - /* Let's not bother reading from HEAD tree */ - mode = S_IFREG | 0644; - } - size = cache_entry_size(len); - ce = xcalloc(1, size); - oidcpy(&ce->oid, &origin->blob_oid); - memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(0); - ce->ce_namelen = len; - ce->ce_mode = create_ce_mode(mode); - add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); - - cache_tree_invalidate_path(&the_index, path); - - return commit; -} - -static struct commit *find_single_final(struct rev_info *revs, - const char **name_p) -{ - int i; - struct commit *found = NULL; - const char *name = NULL; - - for (i = 0; i < revs->pending.nr; i++) { - struct object *obj = revs->pending.objects[i].item; - if (obj->flags & UNINTERESTING) - continue; - obj = deref_tag(obj, NULL, 0); - if (obj->type != OBJ_COMMIT) - die("Non commit %s?", revs->pending.objects[i].name); - if (found) - die("More than one commit to dig from %s and %s?", - revs->pending.objects[i].name, name); - found = (struct commit *)obj; - name = revs->pending.objects[i].name; - } - if (name_p) - *name_p = name; - return found; -} - -static char *prepare_final(struct scoreboard *sb) -{ - const char *name; - sb->final = find_single_final(sb->revs, &name); - return xstrdup_or_null(name); -} - -static const char *dwim_reverse_initial(struct scoreboard *sb) -{ - /* - * DWIM "git blame --reverse ONE -- PATH" as - * "git blame --reverse ONE..HEAD -- PATH" but only do so - * when it makes sense. - */ - struct object *obj; - struct commit *head_commit; - struct object_id head_oid; - - if (sb->revs->pending.nr != 1) - return NULL; - - /* Is that sole rev a committish? */ - obj = sb->revs->pending.objects[0].item; - obj = deref_tag(obj, NULL, 0); - if (obj->type != OBJ_COMMIT) - return NULL; - - /* Do we have HEAD? */ - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL)) - return NULL; - head_commit = lookup_commit_reference_gently(&head_oid, 1); - if (!head_commit) - return NULL; - - /* Turn "ONE" into "ONE..HEAD" then */ - obj->flags |= UNINTERESTING; - add_pending_object(sb->revs, &head_commit->object, "HEAD"); - - sb->final = (struct commit *)obj; - return sb->revs->pending.objects[0].name; -} - -static char *prepare_initial(struct scoreboard *sb) -{ - int i; - const char *final_commit_name = NULL; - struct rev_info *revs = sb->revs; - - /* - * There must be one and only one negative commit, and it must be - * the boundary. - */ - for (i = 0; i < revs->pending.nr; i++) { - struct object *obj = revs->pending.objects[i].item; - if (!(obj->flags & UNINTERESTING)) - continue; - obj = deref_tag(obj, NULL, 0); - if (obj->type != OBJ_COMMIT) - die("Non commit %s?", revs->pending.objects[i].name); - if (sb->final) - die("More than one commit to dig up from, %s and %s?", - revs->pending.objects[i].name, - final_commit_name); - sb->final = (struct commit *) obj; - final_commit_name = revs->pending.objects[i].name; - } - - if (!final_commit_name) - final_commit_name = dwim_reverse_initial(sb); - if (!final_commit_name) - die("No commit to dig up from?"); - return xstrdup(final_commit_name); -} - static int blame_copy_callback(const struct option *option, const char *arg, int unset) { int *opt = option->value; @@ -2556,13 +653,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix) { struct rev_info revs; const char *path; - struct scoreboard sb; - struct origin *o; + struct blame_scoreboard sb; + struct blame_origin *o; struct blame_entry *ent = NULL; long dashdash_pos, lno; - char *final_commit_name = NULL; - enum object_type type; - struct commit *final_commit = NULL; + struct progress_info pi = { NULL, 0 }; struct string_list range_list = STRING_LIST_INIT_NODUP; int output_option = 0, opt = 0; @@ -2688,12 +783,15 @@ parse_done: blame_date_width = sizeof("2006-10-19"); break; case DATE_RELATIVE: - /* TRANSLATORS: This string is used to tell us the maximum - display width for a relative timestamp in "git blame" - output. For C locale, "4 years, 11 months ago", which - takes 22 places, is the longest among various forms of - relative timestamps, but your language may need more or - fewer display columns. */ + /* + * TRANSLATORS: This string is used to tell us the + * maximum display width for a relative timestamp in + * "git blame" output. For C locale, "4 years, 11 + * months ago", which takes 22 places, is the longest + * among various forms of relative timestamps, but + * your language may need more or fewer display + * columns. + */ blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */ break; case DATE_NORMAL: @@ -2709,11 +807,6 @@ parse_done: opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE | PICKAXE_BLAME_COPY_HARDER); - if (!blame_move_score) - blame_move_score = BLAME_DEFAULT_MOVE_SCORE; - if (!blame_copy_score) - blame_copy_score = BLAME_DEFAULT_COPY_SCORE; - /* * We have collected options unknown to us in argv[1..unk] * which are to be passed to revision machinery if we are @@ -2766,94 +859,13 @@ parse_done: revs.disable_stdin = 1; setup_revisions(argc, argv, &revs, NULL); - memset(&sb, 0, sizeof(sb)); + init_scoreboard(&sb); sb.revs = &revs; - if (!reverse) { - final_commit_name = prepare_final(&sb); - sb.commits.compare = compare_commits_by_commit_date; - } - else if (contents_from) - die(_("--contents and --reverse do not blend well.")); - else { - final_commit_name = prepare_initial(&sb); - sb.commits.compare = compare_commits_by_reverse_commit_date; - if (revs.first_parent_only) - revs.children.name = NULL; - } - - if (!sb.final) { - /* - * "--not A B -- path" without anything positive; - * do not default to HEAD, but use the working tree - * or "--contents". - */ - setup_work_tree(); - sb.final = fake_working_tree_commit(&sb.revs->diffopt, - path, contents_from); - add_pending_object(&revs, &(sb.final->object), ":"); - } - else if (contents_from) - die(_("cannot use --contents with final commit object name")); - - if (reverse && revs.first_parent_only) { - final_commit = find_single_final(sb.revs, NULL); - if (!final_commit) - die(_("--reverse and --first-parent together require specified latest commit")); - } - - /* - * If we have bottom, this will mark the ancestors of the - * bottom commits we would reach while traversing as - * uninteresting. - */ - if (prepare_revision_walk(&revs)) - die(_("revision walk setup failed")); - - if (reverse && revs.first_parent_only) { - struct commit *c = final_commit; - - sb.revs->children.name = "children"; - while (c->parents && - oidcmp(&c->object.oid, &sb.final->object.oid)) { - struct commit_list *l = xcalloc(1, sizeof(*l)); - - l->item = c; - if (add_decoration(&sb.revs->children, - &c->parents->item->object, l)) - die("BUG: not unique item in first-parent chain"); - c = c->parents->item; - } - - if (oidcmp(&c->object.oid, &sb.final->object.oid)) - die(_("--reverse --first-parent together require range along first-parent chain")); - } - - if (is_null_oid(&sb.final->object.oid)) { - o = sb.final->util; - sb.final_buf = xmemdupz(o->file.ptr, o->file.size); - sb.final_buf_size = o->file.size; - } - else { - o = get_origin(&sb, sb.final, path); - if (fill_blob_sha1_and_mode(o)) - die(_("no such path %s in %s"), path, final_commit_name); - - if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) && - textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb.final_buf, - &sb.final_buf_size)) - ; - else - sb.final_buf = read_sha1_file(o->blob_oid.hash, &type, - &sb.final_buf_size); - - if (!sb.final_buf) - die(_("cannot read blob %s for path %s"), - oid_to_hex(&o->blob_oid), - path); - } - num_read_blob++; - lno = prepare_lines(&sb); + sb.contents_from = contents_from; + sb.reverse = reverse; + setup_scoreboard(&sb, path, &o); + lno = sb.num_lines; if (lno && !range_list.nr) string_list_append(&range_list, "1"); @@ -2882,22 +894,13 @@ parse_done: for (range_i = ranges.nr; range_i > 0; --range_i) { const struct range *r = &ranges.ranges[range_i - 1]; - long bottom = r->start; - long top = r->end; - struct blame_entry *next = ent; - ent = xcalloc(1, sizeof(*ent)); - ent->lno = bottom; - ent->num_lines = top - bottom; - ent->suspect = o; - ent->s_lno = bottom; - ent->next = next; - origin_incref(o); + ent = blame_entry_prepend(ent, r->start, r->end, o); } o->suspects = ent; prio_queue_put(&sb.commits, o->commit); - origin_decref(o); + blame_origin_decref(o); range_set_release(&ranges); string_list_clear(&range_list, 0); @@ -2905,21 +908,38 @@ parse_done: sb.ent = NULL; sb.path = path; + if (blame_move_score) + sb.move_score = blame_move_score; + if (blame_copy_score) + sb.copy_score = blame_copy_score; + + sb.debug = DEBUG; + sb.on_sanity_fail = &sanity_check_on_fail; + + sb.show_root = show_root; + sb.xdl_opts = xdl_opts; + sb.no_whole_file_rename = no_whole_file_rename; + read_mailmap(&mailmap, NULL); + sb.found_guilty_entry = &found_guilty_entry; + sb.found_guilty_entry_data = π + if (show_progress) + pi.progress = start_progress_delay(_("Blaming lines"), + sb.num_lines, 50, 1); + assign_blame(&sb, opt); + stop_progress(&pi.progress); + if (!incremental) setup_pager(); - - free(final_commit_name); - - if (incremental) + else return 0; - sb.ent = blame_sort(sb.ent, compare_blame_final); + blame_sort_final(&sb); - coalesce(&sb); + blame_coalesce(&sb); if (!(output_option & OUTPUT_PORCELAIN)) find_alignment(&sb, &output_option); @@ -2933,9 +953,9 @@ parse_done: } if (show_stats) { - printf("num read blob: %d\n", num_read_blob); - printf("num get patch: %d\n", num_get_patch); - printf("num commits: %d\n", num_commits); + printf("num read blob: %d\n", sb.num_read_blob); + printf("num get patch: %d\n", sb.num_get_patch); + printf("num commits: %d\n", sb.num_commits); } return 0; } diff --git a/builtin/branch.c b/builtin/branch.c index 83fcda43dc..16d391b407 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -6,6 +6,7 @@ */ #include "cache.h" +#include "config.h" #include "color.h" #include "refs.h" #include "commit.h" @@ -91,7 +92,7 @@ static int git_branch_config(const char *var, const char *value, void *cb) return config_error_nonbool(var); return color_parse(value, branch_colors[slot]); } - return git_color_default_config(var, value, cb); + return git_default_config(var, value, cb); } static const char *branch_get_color(enum color_branch ix) @@ -334,8 +335,11 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r struct strbuf local = STRBUF_INIT; struct strbuf remote = STRBUF_INIT; - strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)", - branch_get_color(BRANCH_COLOR_CURRENT)); + strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else) %s%%(end)", + branch_get_color(BRANCH_COLOR_CURRENT), + branch_get_color(BRANCH_COLOR_LOCAL)); + strbuf_addf(&remote, " %s", + branch_get_color(BRANCH_COLOR_REMOTE)); if (filter->verbose) { struct strbuf obname = STRBUF_INIT; @@ -358,17 +362,17 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r else strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)"); - strbuf_addf(&remote, "%s%%(align:%d,left)%s%%(refname:lstrip=2)%%(end)%s" + strbuf_addf(&remote, "%%(align:%d,left)%s%%(refname:lstrip=2)%%(end)%s" "%%(if)%%(symref)%%(then) -> %%(symref:short)" "%%(else) %s %%(contents:subject)%%(end)", - branch_get_color(BRANCH_COLOR_REMOTE), maxwidth, quote_literal_for_format(remote_prefix), + maxwidth, quote_literal_for_format(remote_prefix), branch_get_color(BRANCH_COLOR_RESET), obname.buf); strbuf_release(&obname); } else { strbuf_addf(&local, "%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)", branch_get_color(BRANCH_COLOR_RESET)); - strbuf_addf(&remote, "%s%s%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)", - branch_get_color(BRANCH_COLOR_REMOTE), quote_literal_for_format(remote_prefix), + strbuf_addf(&remote, "%s%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)", + quote_literal_for_format(remote_prefix), branch_get_color(BRANCH_COLOR_RESET)); } @@ -379,7 +383,7 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r return strbuf_detach(&fmt, NULL); } -static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format) +static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, struct ref_format *format) { int i; struct ref_array array; @@ -403,14 +407,17 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin if (filter->verbose) maxwidth = calc_maxwidth(&array, strlen(remote_prefix)); - if (!format) - format = to_free = build_format(filter, maxwidth, remote_prefix); - verify_ref_format(format); + if (!format->format) + format->format = to_free = build_format(filter, maxwidth, remote_prefix); + format->use_color = branch_use_color; + + if (verify_ref_format(format)) + die(_("unable to parse format string")); ref_array_sort(sorting, &array); for (i = 0; i < array.nr; i++) { - format_ref_array_item(array.items[i], format, 0, &out); + format_ref_array_item(array.items[i], format, &out); if (column_active(colopts)) { assert(!filter->verbose && "--column and --verbose are incompatible"); /* format to a string_list to let print_columns() do its job */ @@ -545,7 +552,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) struct ref_filter filter; int icase = 0; static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; - const char *format = NULL; + struct ref_format format = REF_FORMAT_INIT; struct option options[] = { OPT_GROUP(N_("Generic options")), @@ -589,7 +596,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) N_("print only branches of the object"), 0, parse_opt_object_name }, OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), - OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), + OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")), OPT_END(), }; @@ -663,7 +670,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (!sorting) sorting = ref_default_sorting(); sorting->ignore_case = icase; - print_ref_list(&filter, sorting, format); + print_ref_list(&filter, sorting, &format); print_columns(&output, colopts, NULL); string_list_clear(&output, 0); return 0; diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 9af863e791..62c8cf0ebf 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -4,7 +4,9 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "builtin.h" +#include "diff.h" #include "parse-options.h" #include "userdiff.h" #include "streaming.h" @@ -55,13 +57,14 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, struct object_context obj_context; struct object_info oi = OBJECT_INFO_INIT; struct strbuf sb = STRBUF_INIT; - unsigned flags = LOOKUP_REPLACE_OBJECT; + unsigned flags = OBJECT_INFO_LOOKUP_REPLACE; const char *path = force_path; if (unknown_type) - flags |= LOOKUP_UNKNOWN_OBJECT; + flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE; - if (get_sha1_with_context(obj_name, 0, oid.hash, &obj_context)) + if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH, + &oid, &obj_context)) die("Not a valid object name %s", obj_name); if (!path) @@ -166,6 +169,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, write_or_die(1, buf, size); free(buf); + free(obj_context.path); return 0; } @@ -334,7 +338,8 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt, struct strbuf buf = STRBUF_INIT; if (!data->skip_object_info && - sha1_object_info_extended(data->oid.hash, &data->info, LOOKUP_REPLACE_OBJECT) < 0) { + sha1_object_info_extended(data->oid.hash, &data->info, + OBJECT_INFO_LOOKUP_REPLACE) < 0) { printf("%s missing\n", obj_name ? obj_name : oid_to_hex(&data->oid)); fflush(stdout); @@ -356,10 +361,10 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt, struct expand_data *data) { struct object_context ctx; - int flags = opt->follow_symlinks ? GET_SHA1_FOLLOW_SYMLINKS : 0; + int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0; enum follow_symlinks_result result; - result = get_sha1_with_context(obj_name, flags, data->oid.hash, &ctx); + result = get_oid_with_context(obj_name, flags, &data->oid, &ctx); if (result != FOUND) { switch (result) { case MISSING_OBJECT: diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 4d01ca0c8b..91444dc044 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "attr.h" #include "quote.h" #include "parse-options.h" diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c index c7b8c08897..3e280b9c7a 100644 --- a/builtin/check-ignore.c +++ b/builtin/check-ignore.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "dir.h" #include "quote.h" #include "pathspec.h" diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c index cf0f54f6b9..cdce144f3b 100644 --- a/builtin/check-mailmap.c +++ b/builtin/check-mailmap.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "mailmap.h" #include "parse-options.h" #include "string-list.h" diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 07631d0c9c..39c8be05dc 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -5,6 +5,7 @@ * */ #include "builtin.h" +#include "config.h" #include "lockfile.h" #include "quote.h" #include "cache-tree.h" diff --git a/builtin/checkout.c b/builtin/checkout.c index c1a256df8d..2d75ac66c7 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "lockfile.h" #include "parse-options.h" #include "refs.h" @@ -21,31 +22,12 @@ #include "submodule-config.h" #include "submodule.h" -static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; - static const char * const checkout_usage[] = { N_("git checkout [<options>] <branch>"), N_("git checkout [<options>] [<branch>] -- <file>..."), NULL, }; -static int option_parse_recurse_submodules(const struct option *opt, - const char *arg, int unset) -{ - if (unset) { - recurse_submodules = RECURSE_SUBMODULES_OFF; - return 0; - } - if (arg) - recurse_submodules = - parse_update_recurse_submodules_arg(opt->long_name, - arg); - else - recurse_submodules = RECURSE_SUBMODULES_ON; - - return 0; -} - struct checkout_opts { int patch_mode; int quiet; @@ -879,7 +861,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb) } if (starts_with(var, "submodule.")) - return parse_submodule_config_option(var, value); + return submodule_config(var, value, NULL); return git_xmerge_config(var, value, NULL); } @@ -1187,9 +1169,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) N_("second guess 'git checkout <no-such-branch>'")), OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees, N_("do not check if another worktree is holding the given ref")), - { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, + { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "checkout", "control recursive updating of submodules", - PARSE_OPT_OPTARG, option_parse_recurse_submodules }, + PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater }, OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")), OPT_END(), }; @@ -1220,12 +1202,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) git_xmerge_config("merge.conflictstyle", conflict_style, NULL); } - if (recurse_submodules != RECURSE_SUBMODULES_OFF) { - git_config(submodule_config, NULL); - if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) - set_config_update_recurse_submodules(recurse_submodules); - } - if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1) die(_("-b, -B and --orphan are mutually exclusive")); diff --git a/builtin/clean.c b/builtin/clean.c index 329b68c40b..21a7a32994 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -8,6 +8,7 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "dir.h" #include "parse-options.h" #include "string-list.h" @@ -32,15 +33,6 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n"); static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n"); static const char *msg_warn_remove_failed = N_("failed to remove %s"); -static int clean_use_color = -1; -static char clean_colors[][COLOR_MAXLEN] = { - GIT_COLOR_RESET, - GIT_COLOR_NORMAL, /* PLAIN */ - GIT_COLOR_BOLD_BLUE, /* PROMPT */ - GIT_COLOR_BOLD, /* HEADER */ - GIT_COLOR_BOLD_RED, /* HELP */ - GIT_COLOR_BOLD_RED, /* ERROR */ -}; enum color_clean { CLEAN_COLOR_RESET = 0, CLEAN_COLOR_PLAIN = 1, @@ -50,6 +42,16 @@ enum color_clean { CLEAN_COLOR_ERROR = 5 }; +static int clean_use_color = -1; +static char clean_colors[][COLOR_MAXLEN] = { + [CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED, + [CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD, + [CLEAN_COLOR_HELP] = GIT_COLOR_BOLD_RED, + [CLEAN_COLOR_PLAIN] = GIT_COLOR_NORMAL, + [CLEAN_COLOR_PROMPT] = GIT_COLOR_BOLD_BLUE, + [CLEAN_COLOR_RESET] = GIT_COLOR_RESET, +}; + #define MENU_OPTS_SINGLETON 01 #define MENU_OPTS_IMMEDIATE 02 #define MENU_OPTS_LIST_ONLY 04 @@ -124,8 +126,7 @@ static int git_clean_config(const char *var, const char *value, void *cb) return 0; } - /* inspect the color.ui config variable and others */ - return git_color_default_config(var, value, cb); + return git_default_config(var, value, cb); } static const char *clean_get_color(enum color_clean ix) @@ -837,8 +838,7 @@ static void interactive_main_loop(void) int ret; ret = menus[*chosen].fn(); if (ret != MENU_RETURN_NO_LOOP) { - free(chosen); - chosen = NULL; + FREE_AND_NULL(chosen); if (!del_list.nr) { clean_print_color(CLEAN_COLOR_ERROR); printf_ln(_("No more files to clean, exiting.")); @@ -851,12 +851,43 @@ static void interactive_main_loop(void) quit_cmd(); } - free(chosen); - chosen = NULL; + FREE_AND_NULL(chosen); break; } } +static void correct_untracked_entries(struct dir_struct *dir) +{ + int src, dst, ign; + + for (src = dst = ign = 0; src < dir->nr; src++) { + /* skip paths in ignored[] that cannot be inside entries[src] */ + while (ign < dir->ignored_nr && + 0 <= cmp_dir_entry(&dir->entries[src], &dir->ignored[ign])) + ign++; + + if (ign < dir->ignored_nr && + check_dir_entry_contains(dir->entries[src], dir->ignored[ign])) { + /* entries[src] contains an ignored path, so we drop it */ + free(dir->entries[src]); + } else { + struct dir_entry *ent = dir->entries[src++]; + + /* entries[src] does not contain an ignored path, so we keep it */ + dir->entries[dst++] = ent; + + /* then discard paths in entries[] contained inside entries[src] */ + while (src < dir->nr && + check_dir_entry_contains(ent, dir->entries[src])) + free(dir->entries[src++]); + + /* compensate for the outer loop's loop control */ + src--; + } + } + dir->nr = dst; +} + int cmd_clean(int argc, const char **argv, const char *prefix) { int i, res; @@ -916,6 +947,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix) dir.flags |= DIR_SHOW_OTHER_DIRECTORIES; + if (remove_directories) + dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS; + if (read_cache() < 0) die(_("index file corrupt")); @@ -931,6 +965,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) prefix, argv); fill_directory(&dir, &the_index, &pathspec); + correct_untracked_entries(&dir); for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; @@ -958,6 +993,12 @@ int cmd_clean(int argc, const char **argv, const char *prefix) string_list_append(&del_list, rel); } + for (i = 0; i < dir.nr; i++) + free(dir.entries[i]); + + for (i = 0; i < dir.ignored_nr; i++) + free(dir.ignored[i]); + if (interactive && del_list.nr > 0) interactive_main_loop(); diff --git a/builtin/clone.c b/builtin/clone.c index 743f16ae2a..08b5cc433c 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -9,6 +9,7 @@ */ #include "builtin.h" +#include "config.h" #include "lockfile.h" #include "parse-options.h" #include "fetch-pack.h" @@ -360,7 +361,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst, * to turn entries with paths relative to the original * absolute, so that they can be used in the new repository. */ - FILE *in = fopen(src->buf, "r"); + FILE *in = xfopen(src->buf, "r"); struct strbuf line = STRBUF_INIT; while (strbuf_getline(&line, in) != EOF) { diff --git a/builtin/column.c b/builtin/column.c index 33314b4d71..0c3223d64b 100644 --- a/builtin/column.c +++ b/builtin/column.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "strbuf.h" #include "parse-options.h" #include "string-list.h" diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index f39c2b2737..19e898fa4e 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "commit.h" #include "tree.h" #include "builtin.h" @@ -55,7 +56,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) struct object_id oid; if (argc <= ++i) usage(commit_tree_usage); - if (get_sha1_commit(argv[i], oid.hash)) + if (get_oid_commit(argv[i], &oid)) die("Not a valid object name %s", argv[i]); assert_sha1_type(oid.hash, OBJ_COMMIT); new_parent(lookup_commit(&oid), &parents); @@ -105,7 +106,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) continue; } - if (get_sha1_tree(arg, tree_oid.hash)) + if (get_oid_tree(arg, &tree_oid)) die("Not a valid object name %s", arg); if (got_tree) die("Cannot give more than one trees"); diff --git a/builtin/commit.c b/builtin/commit.c index da1ba4c862..4bbac014ab 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -6,6 +6,7 @@ */ #include "cache.h" +#include "config.h" #include "lockfile.h" #include "cache-tree.h" #include "color.h" @@ -139,7 +140,6 @@ static enum commit_whence whence; static int sequencer_in_use; static int use_editor = 1, include_status = 1; static int show_ignored_in_status, have_option_m; -static const char *only_include_assumed; static struct strbuf message = STRBUF_INIT; static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED; @@ -253,7 +253,8 @@ static int list_paths(struct string_list *list, const char *with_tree, if (with_tree) { char *max_prefix = common_prefix(pattern); - overlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix); + overlay_tree_on_index(&the_index, with_tree, + max_prefix ? max_prefix : prefix); free(max_prefix); } @@ -509,7 +510,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int s->index_file = index_file; s->fp = fp; s->nowarn = nowarn; - s->is_initial = get_sha1(s->reference, oid.hash) ? 1 : 0; + s->is_initial = get_oid(s->reference, &oid) ? 1 : 0; if (!s->is_initial) hashcpy(s->sha1_commit, oid.hash); s->status_format = status_format; @@ -841,9 +842,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix, "with '%c' will be kept; you may remove them" " yourself if you want to.\n" "An empty message aborts the commit.\n"), comment_line_char); - if (only_include_assumed) - status_printf_ln(s, GIT_COLOR_NORMAL, - "%s", only_include_assumed); /* * These should never fail because they come from our own @@ -877,8 +875,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, (int)(ci.name_end - ci.name_begin), ci.name_begin, (int)(ci.mail_end - ci.mail_begin), ci.mail_begin); - if (ident_shown) - status_printf_ln(s, GIT_COLOR_NORMAL, "%s", ""); + status_printf_ln(s, GIT_COLOR_NORMAL, "%s", ""); /* Add new line for clarity */ saved_color_setting = s->use_color; s->use_color = 0; @@ -894,7 +891,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (amend) parent = "HEAD^1"; - if (get_sha1(parent, oid.hash)) { + if (get_oid(parent, &oid)) { int i, ita_nr = 0; for (i = 0; i < active_nr; i++) @@ -984,7 +981,7 @@ static int rest_is_empty(struct strbuf *sb, int start) int i, eol; const char *nl; - /* Check if the rest is just whitespace and Signed-of-by's. */ + /* Check if the rest is just whitespace and Signed-off-by's. */ for (i = start; i < sb->len; i++) { nl = memchr(sb->buf + i, '\n', sb->len - i); if (nl) @@ -1208,8 +1205,6 @@ static int parse_and_validate_options(int argc, const char *argv[], die(_("Only one of --include/--only/--all/--interactive/--patch can be used.")); if (argc == 0 && (also || (only && !amend && !allow_empty))) die(_("No paths with --include/--only does not make sense.")); - if (argc > 0 && !also && !only) - only_include_assumed = _("Explicit paths specified without -i or -o; assuming --only paths..."); if (!cleanup_arg || !strcmp(cleanup_arg, "default")) cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE; else if (!strcmp(cleanup_arg, "verbatim")) @@ -1295,6 +1290,10 @@ static int git_status_config(const char *k, const char *v, void *cb) status_deferred_config.show_branch = git_config_bool(k, v); return 0; } + if (!strcmp(k, "status.showstash")) { + s->show_stash = git_config_bool(k, v); + return 0; + } if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { s->use_color = git_config_colorbool(k, v); return 0; @@ -1343,6 +1342,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) N_("show status concisely"), STATUS_FORMAT_SHORT), OPT_BOOL('b', "branch", &s.show_branch, N_("show branch information")), + OPT_BOOL(0, "show-stash", &s.show_stash, + N_("show stash information")), { OPTION_CALLBACK, 0, "porcelain", &status_format, N_("version"), N_("machine-readable output"), PARSE_OPT_OPTARG, opt_parse_porcelain }, @@ -1386,7 +1387,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) fd = hold_locked_index(&index_lock, 0); - s.is_initial = get_sha1(s.reference, oid.hash) ? 1 : 0; + s.is_initial = get_oid(s.reference, &oid) ? 1 : 0; if (!s.is_initial) hashcpy(s.sha1_commit, oid.hash); @@ -1652,10 +1653,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix) usage_with_options(builtin_commit_usage, builtin_commit_options); status_init_config(&s, git_commit_config); + s.commit_template = 1; status_format = STATUS_FORMAT_NONE; /* Ignore status.short */ s.colopts = 0; - if (get_sha1("HEAD", oid.hash)) + if (get_oid("HEAD", &oid)) current_head = NULL; else { current_head = lookup_commit_or_die(&oid, "HEAD"); @@ -1699,10 +1701,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!reflog_msg) reflog_msg = "commit (merge)"; pptr = commit_list_append(current_head, pptr); - fp = fopen(git_path_merge_head(), "r"); - if (fp == NULL) - die_errno(_("could not open '%s' for reading"), - git_path_merge_head()); + fp = xfopen(git_path_merge_head(), "r"); while (strbuf_getline_lf(&m, fp) != EOF) { struct commit *parent; @@ -1809,7 +1808,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) cfg = init_copy_notes_for_rewrite("amend"); if (cfg) { /* we are amending, so current_head is not NULL */ - copy_note_for_rewrite(cfg, current_head->object.oid.hash, oid.hash); + copy_note_for_rewrite(cfg, ¤t_head->object.oid, &oid); finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'"); } run_rewrite_hook(¤t_head->object.oid, &oid); diff --git a/builtin/config.c b/builtin/config.c index 7f6c25d4d9..70ff231e9c 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "color.h" #include "parse-options.h" #include "urlmatch.h" @@ -214,8 +215,7 @@ static int get_value(const char *key_, const char *regex_) key_regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { error("invalid key pattern: %s", key_); - free(key_regexp); - key_regexp = NULL; + FREE_AND_NULL(key_regexp); ret = CONFIG_INVALID_PATTERN; goto free_strings; } @@ -235,15 +235,14 @@ static int get_value(const char *key_, const char *regex_) regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(regexp, regex_, REG_EXTENDED)) { error("invalid pattern: %s", regex_); - free(regexp); - regexp = NULL; + FREE_AND_NULL(regexp); ret = CONFIG_INVALID_PATTERN; goto free_strings; } } - git_config_with_options(collect_config, &values, - &given_config_source, &config_options); + config_with_options(collect_config, &values, + &given_config_source, &config_options); ret = !values.nr; @@ -320,8 +319,8 @@ static void get_color(const char *var, const char *def_color) get_color_slot = var; get_color_found = 0; parsed_color[0] = '\0'; - git_config_with_options(git_get_color_config, NULL, - &given_config_source, &config_options); + config_with_options(git_get_color_config, NULL, + &given_config_source, &config_options); if (!get_color_found && def_color) { if (color_parse(def_color, parsed_color) < 0) @@ -352,8 +351,8 @@ static int get_colorbool(const char *var, int print) get_colorbool_found = -1; get_diff_color_found = -1; get_color_ui_found = -1; - git_config_with_options(git_get_colorbool_config, NULL, - &given_config_source, &config_options); + config_with_options(git_get_colorbool_config, NULL, + &given_config_source, &config_options); if (get_colorbool_found < 0) { if (!strcmp(get_colorbool_slot, "color.diff")) @@ -441,8 +440,8 @@ static int get_urlmatch(const char *var, const char *url) show_keys = 1; } - git_config_with_options(urlmatch_config_entry, &config, - &given_config_source, &config_options); + config_with_options(urlmatch_config_entry, &config, + &given_config_source, &config_options); ret = !values.nr; @@ -538,6 +537,10 @@ int cmd_config(int argc, const char **argv, const char *prefix) config_options.respect_includes = !given_config_source.file; else config_options.respect_includes = respect_includes_opt; + if (!nongit) { + config_options.commondir = get_git_common_dir(); + config_options.git_dir = get_git_dir(); + } if (end_null) { term = '\0'; @@ -582,9 +585,9 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (actions == ACTION_LIST) { check_argc(argc, 0, 0); - if (git_config_with_options(show_all_config, NULL, - &given_config_source, - &config_options) < 0) { + if (config_with_options(show_all_config, NULL, + &given_config_source, + &config_options) < 0) { if (given_config_source.file) die_errno("unable to read config file '%s'", given_config_source.file); diff --git a/builtin/count-objects.c b/builtin/count-objects.c index acb05940fc..1d82e61f2a 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -5,6 +5,7 @@ */ #include "cache.h" +#include "config.h" #include "dir.h" #include "builtin.h" #include "parse-options.h" diff --git a/builtin/credential.c b/builtin/credential.c index 0412fa00f0..879acfbcda 100644 --- a/builtin/credential.c +++ b/builtin/credential.c @@ -10,9 +10,9 @@ int cmd_credential(int argc, const char **argv, const char *prefix) const char *op; struct credential c = CREDENTIAL_INIT; - op = argv[1]; - if (!op) + if (argc != 2 || !strcmp(argv[1], "-h")) usage(usage_msg); + op = argv[1]; if (credential_read(&c, stdin) < 0) die("unable to read credential from stdin"); diff --git a/builtin/describe.c b/builtin/describe.c index 893c8789f4..89ea1cdd60 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "lockfile.h" #include "commit.h" #include "tag.h" @@ -53,8 +54,10 @@ static const char *prio_names[] = { N_("head"), N_("lightweight"), N_("annotated"), }; -static int commit_name_cmp(const struct commit_name *cn1, - const struct commit_name *cn2, const void *peeled) +static int commit_name_cmp(const void *unused_cmp_data, + const struct commit_name *cn1, + const struct commit_name *cn2, + const void *peeled) { return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled); } @@ -142,7 +145,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi return 0; for_each_string_list_item(item, &exclude_patterns) { - if (!wildmatch(item->string, path + 10, 0, NULL)) + if (!wildmatch(item->string, path + 10, 0)) return 0; } } @@ -158,7 +161,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi return 0; for_each_string_list_item(item, &patterns) { - if (!wildmatch(item->string, path + 10, 0, NULL)) + if (!wildmatch(item->string, path + 10, 0)) break; /* If we get here, no pattern matched. */ @@ -500,7 +503,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) return cmd_name_rev(args.argc, args.argv, prefix); } - hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, 0); + hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, NULL, 0); for_each_rawref(get_name, NULL); if (!names.size && !always) die(_("No names found, cannot describe anything.")); diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 15c61fd8d1..17bf84d18f 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "diff.h" #include "commit.h" #include "revision.h" @@ -20,9 +21,12 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) int result; unsigned options = 0; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage(diff_files_usage); + + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ init_revisions(&rev, prefix); gitmodules_config(); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; precompose_argv(argc, argv); diff --git a/builtin/diff-index.c b/builtin/diff-index.c index 1af373d002..185e6f9b58 100644 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "diff.h" #include "commit.h" #include "revision.h" @@ -17,9 +18,12 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) int i; int result; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage(diff_cache_usage); + + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ init_revisions(&rev, prefix); gitmodules_config(); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; precompose_argv(argc, argv); diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 5ea1c14317..31d2cb4107 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "diff.h" #include "commit.h" #include "log-tree.h" @@ -7,7 +8,7 @@ static struct rev_info log_tree_opt; -static int diff_tree_commit_sha1(const struct object_id *oid) +static int diff_tree_commit_oid(const struct object_id *oid) { struct commit *commit = lookup_commit_reference(oid); if (!commit) @@ -49,8 +50,8 @@ static int stdin_diff_trees(struct tree *tree1, const char *p) return -1; printf("%s %s\n", oid_to_hex(&tree1->object.oid), oid_to_hex(&tree2->object.oid)); - diff_tree_sha1(tree1->object.oid.hash, tree2->object.oid.hash, - "", &log_tree_opt.diffopt); + diff_tree_oid(&tree1->object.oid, &tree2->object.oid, + "", &log_tree_opt.diffopt); log_tree_diff_flush(&log_tree_opt); return 0; } @@ -98,16 +99,18 @@ static void diff_tree_tweak_rev(struct rev_info *rev, struct setup_revision_opt int cmd_diff_tree(int argc, const char **argv, const char *prefix) { - int nr_sha1; char line[1000]; struct object *tree1, *tree2; static struct rev_info *opt = &log_tree_opt; struct setup_revision_opt s_r_opt; int read_stdin = 0; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage(diff_tree_usage); + + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ init_revisions(opt, prefix); gitmodules_config(); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ opt->abbrev = 0; opt->diff = 1; opt->disable_stdin = 1; @@ -128,19 +131,20 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) } /* - * NOTE! We expect "a ^b" to be equal to "a..b", so we - * reverse the order of the objects if the second one - * is marked UNINTERESTING. + * NOTE! We expect "a..b" to expand to "^a b" but it is + * perfectly valid for revision range parser to yield "b ^a", + * which means the same thing. If we get the latter, i.e. the + * second one is marked UNINTERESTING, we recover the original + * order the user gave, i.e. "a..b", by swapping the trees. */ - nr_sha1 = opt->pending.nr; - switch (nr_sha1) { + switch (opt->pending.nr) { case 0: if (!read_stdin) usage(diff_tree_usage); break; case 1: tree1 = opt->pending.objects[0].item; - diff_tree_commit_sha1(&tree1->oid); + diff_tree_commit_oid(&tree1->oid); break; case 2: tree1 = opt->pending.objects[0].item; @@ -148,9 +152,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) if (tree2->flags & UNINTERESTING) { SWAP(tree2, tree1); } - diff_tree_sha1(tree1->oid.hash, - tree2->oid.hash, - "", &opt->diffopt); + diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt); log_tree_diff_flush(opt); break; } diff --git a/builtin/diff.c b/builtin/diff.c index 8c03ddaf58..7cde6abbcf 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -4,6 +4,7 @@ * Copyright (c) 2006 Junio C Hamano */ #include "cache.h" +#include "config.h" #include "lockfile.h" #include "color.h" #include "commit.h" @@ -20,23 +21,22 @@ #define DIFF_NO_INDEX_EXPLICIT 1 #define DIFF_NO_INDEX_IMPLICIT 2 -struct blobinfo { - struct object_id oid; - const char *name; - unsigned mode; -}; - static const char builtin_diff_usage[] = "git diff [<options>] [<commit> [<commit>]] [--] [<path>...]"; +static const char *blob_path(struct object_array_entry *entry) +{ + return entry->path ? entry->path : entry->name; +} + static void stuff_change(struct diff_options *opt, unsigned old_mode, unsigned new_mode, const struct object_id *old_oid, const struct object_id *new_oid, int old_oid_valid, int new_oid_valid, - const char *old_name, - const char *new_name) + const char *old_path, + const char *new_path) { struct diff_filespec *one, *two; @@ -47,25 +47,25 @@ static void stuff_change(struct diff_options *opt, if (DIFF_OPT_TST(opt, REVERSE_DIFF)) { SWAP(old_mode, new_mode); SWAP(old_oid, new_oid); - SWAP(old_name, new_name); + SWAP(old_path, new_path); } if (opt->prefix && - (strncmp(old_name, opt->prefix, opt->prefix_length) || - strncmp(new_name, opt->prefix, opt->prefix_length))) + (strncmp(old_path, opt->prefix, opt->prefix_length) || + strncmp(new_path, opt->prefix, opt->prefix_length))) return; - one = alloc_filespec(old_name); - two = alloc_filespec(new_name); - fill_filespec(one, old_oid->hash, old_oid_valid, old_mode); - fill_filespec(two, new_oid->hash, new_oid_valid, new_mode); + one = alloc_filespec(old_path); + two = alloc_filespec(new_path); + fill_filespec(one, old_oid, old_oid_valid, old_mode); + fill_filespec(two, new_oid, new_oid_valid, new_mode); diff_queue(&diff_queued_diff, one, two); } static int builtin_diff_b_f(struct rev_info *revs, int argc, const char **argv, - struct blobinfo *blob) + struct object_array_entry **blob) { /* Blob vs file in the working tree*/ struct stat st; @@ -84,14 +84,15 @@ static int builtin_diff_b_f(struct rev_info *revs, diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/"); - if (blob[0].mode == S_IFINVALID) - blob[0].mode = canon_mode(st.st_mode); + if (blob[0]->mode == S_IFINVALID) + blob[0]->mode = canon_mode(st.st_mode); stuff_change(&revs->diffopt, - blob[0].mode, canon_mode(st.st_mode), - &blob[0].oid, &null_oid, + blob[0]->mode, canon_mode(st.st_mode), + &blob[0]->item->oid, &null_oid, 1, 0, - path, path); + blob[0]->path ? blob[0]->path : path, + path); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; @@ -99,24 +100,24 @@ static int builtin_diff_b_f(struct rev_info *revs, static int builtin_diff_blobs(struct rev_info *revs, int argc, const char **argv, - struct blobinfo *blob) + struct object_array_entry **blob) { unsigned mode = canon_mode(S_IFREG | 0644); if (argc > 1) usage(builtin_diff_usage); - if (blob[0].mode == S_IFINVALID) - blob[0].mode = mode; + if (blob[0]->mode == S_IFINVALID) + blob[0]->mode = mode; - if (blob[1].mode == S_IFINVALID) - blob[1].mode = mode; + if (blob[1]->mode == S_IFINVALID) + blob[1]->mode = mode; stuff_change(&revs->diffopt, - blob[0].mode, blob[1].mode, - &blob[0].oid, &blob[1].oid, + blob[0]->mode, blob[1]->mode, + &blob[0]->item->oid, &blob[1]->item->oid, 1, 1, - blob[0].name, blob[1].name); + blob_path(blob[0]), blob_path(blob[1])); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; @@ -174,7 +175,7 @@ static int builtin_diff_tree(struct rev_info *revs, swap = 1; oid[swap] = &ent0->item->oid; oid[1 - swap] = &ent1->item->oid; - diff_tree_sha1(oid[0]->hash, oid[1]->hash, "", &revs->diffopt); + diff_tree_oid(oid[0], oid[1], "", &revs->diffopt); log_tree_diff_flush(revs); return 0; } @@ -194,7 +195,7 @@ static int builtin_diff_combined(struct rev_info *revs, revs->dense_combined_merges = revs->combine_merges = 1; for (i = 1; i < ents; i++) oid_array_append(&parents, &ent[i].item->oid); - diff_tree_combined(ent[0].item->oid.hash, &parents, + diff_tree_combined(&ent[0].item->oid, &parents, revs->dense_combined_merges, revs); oid_array_clear(&parents); return 0; @@ -259,7 +260,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) struct rev_info rev; struct object_array ent = OBJECT_ARRAY_INIT; int blobs = 0, paths = 0; - struct blobinfo blob[2]; + struct object_array_entry *blob[2]; int nongit = 0, no_index = 0; int result = 0; @@ -408,9 +409,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } else if (obj->type == OBJ_BLOB) { if (2 <= blobs) die(_("more than two blobs given: '%s'"), name); - oidcpy(&blob[blobs].oid, &obj->oid); - blob[blobs].name = name; - blob[blobs].mode = entry->mode; + blob[blobs] = entry; blobs++; } else { diff --git a/builtin/difftool.c b/builtin/difftool.c index b9a892f269..a1a26ba891 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -12,6 +12,7 @@ * Copyright (C) 2016 Johannes Schindelin */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "run-command.h" #include "exec_cmd.h" @@ -129,8 +130,10 @@ struct working_tree_entry { char path[FLEX_ARRAY]; }; -static int working_tree_entry_cmp(struct working_tree_entry *a, - struct working_tree_entry *b, void *keydata) +static int working_tree_entry_cmp(const void *unused_cmp_data, + struct working_tree_entry *a, + struct working_tree_entry *b, + void *unused_keydata) { return strcmp(a->path, b->path); } @@ -145,7 +148,9 @@ struct pair_entry { const char path[FLEX_ARRAY]; }; -static int pair_cmp(struct pair_entry *a, struct pair_entry *b, void *keydata) +static int pair_cmp(const void *unused_cmp_data, + struct pair_entry *a, struct pair_entry *b, + void *unused_keydata) { return strcmp(a->path, b->path); } @@ -173,7 +178,9 @@ struct path_entry { char path[FLEX_ARRAY]; }; -static int path_entry_cmp(struct path_entry *a, struct path_entry *b, void *key) +static int path_entry_cmp(const void *unused_cmp_data, + struct path_entry *a, struct path_entry *b, + void *key) { return strcmp(a->path, key ? key : b->path); } @@ -366,9 +373,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, wtdir_len = wtdir.len; hashmap_init(&working_tree_dups, - (hashmap_cmp_fn)working_tree_entry_cmp, 0); - hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, 0); - hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, 0); + (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0); + hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0); + hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0); child.no_stdin = 1; child.git_cmd = 1; @@ -579,9 +586,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, * files through the symlink. */ hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp, - wtindex.cache_nr); + NULL, wtindex.cache_nr); hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp, - wtindex.cache_nr); + NULL, wtindex.cache_nr); for (i = 0; i < wtindex.cache_nr; i++) { struct hashmap_entry dummy; diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 24e29ad7ea..d412c0a8f3 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -5,6 +5,7 @@ */ #include "builtin.h" #include "cache.h" +#include "config.h" #include "refs.h" #include "commit.h" #include "object.h" @@ -92,8 +93,9 @@ struct anonymized_entry { size_t anon_len; }; -static int anonymized_entry_cmp(const void *va, const void *vb, - const void *data) +static int anonymized_entry_cmp(const void *unused_cmp_data, + const void *va, const void *vb, + const void *unused_keydata) { const struct anonymized_entry *a = va, *b = vb; return a->orig_len != b->orig_len || @@ -112,7 +114,7 @@ static const void *anonymize_mem(struct hashmap *map, struct anonymized_entry key, *ret; if (!map->cmpfn) - hashmap_init(map, anonymized_entry_cmp, 0); + hashmap_init(map, anonymized_entry_cmp, NULL, 0); hashmap_entry_init(&key, memhash(orig, *len)); key.orig = orig; @@ -562,12 +564,12 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) get_object_mark(&commit->parents->item->object) != 0 && !full_tree) { parse_commit_or_die(commit->parents->item); - diff_tree_sha1(commit->parents->item->tree->object.oid.hash, - commit->tree->object.oid.hash, "", &rev->diffopt); + diff_tree_oid(&commit->parents->item->tree->object.oid, + &commit->tree->object.oid, "", &rev->diffopt); } else - diff_root_tree_sha1(commit->tree->object.oid.hash, - "", &rev->diffopt); + diff_root_tree_oid(&commit->tree->object.oid, + "", &rev->diffopt); /* Export the referenced blobs, and remember the marks. */ for (i = 0; i < diff_queued_diff.nr; i++) @@ -907,9 +909,7 @@ static void export_marks(char *file) static void import_marks(char *input_file) { char line[512]; - FILE *f = fopen(input_file, "r"); - if (!f) - die_errno("cannot read '%s'", input_file); + FILE *f = xfopen(input_file, "r"); while (fgets(line, sizeof(line), f)) { uint32_t mark; diff --git a/builtin/fetch.c b/builtin/fetch.c index d4d573b985..c87e59f3b1 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -2,6 +2,7 @@ * "git fetch" */ #include "cache.h" +#include "config.h" #include "refs.h" #include "commit.h" #include "builtin.h" @@ -36,7 +37,7 @@ static int prune = -1; /* unspecified */ #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */ static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative; -static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; +static int progress = -1; static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen; static int max_children = -1; static enum transport_family family; @@ -48,31 +49,25 @@ static struct strbuf default_rla = STRBUF_INIT; static struct transport *gtransport; static struct transport *gsecondary; static const char *submodule_prefix = ""; -static const char *recurse_submodules_default; +static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; +static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND; static int shown_url = 0; static int refmap_alloc, refmap_nr; static const char **refmap_array; -static int option_parse_recurse_submodules(const struct option *opt, - const char *arg, int unset) -{ - if (unset) { - recurse_submodules = RECURSE_SUBMODULES_OFF; - } else { - if (arg) - recurse_submodules = parse_fetch_recurse_submodules_arg(opt->long_name, arg); - else - recurse_submodules = RECURSE_SUBMODULES_ON; - } - return 0; -} - static int git_fetch_config(const char *k, const char *v, void *cb) { if (!strcmp(k, "fetch.prune")) { fetch_prune_config = git_config_bool(k, v); return 0; } + + if (!strcmp(k, "submodule.recurse")) { + int r = git_config_bool(k, v) ? + RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF; + recurse_submodules = r; + } + return git_default_config(k, v, cb); } @@ -108,9 +103,9 @@ static struct option builtin_fetch_options[] = { N_("number of submodules fetched in parallel")), OPT_BOOL('p', "prune", &prune, N_("prune remote-tracking branches no longer on remote")), - { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"), + { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, N_("on-demand"), N_("control recursive fetching of submodules"), - PARSE_OPT_OPTARG, option_parse_recurse_submodules }, + PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules }, OPT_BOOL(0, "dry-run", &dry_run, N_("dry run")), OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")), @@ -130,9 +125,11 @@ static struct option builtin_fetch_options[] = { PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 }, { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"), N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN }, - { OPTION_STRING, 0, "recurse-submodules-default", - &recurse_submodules_default, NULL, - N_("default mode for recursion"), PARSE_OPT_HIDDEN }, + { OPTION_CALLBACK, 0, "recurse-submodules-default", + &recurse_submodules_default, N_("on-demand"), + N_("default for recursive fetching of submodules " + "(lower priority than config files)"), + PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules }, OPT_BOOL(0, "update-shallow", &update_shallow, N_("accept refs that update .git/shallow")), { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"), @@ -242,9 +239,11 @@ static void find_non_local_tags(struct transport *transport, */ if (ends_with(ref->name, "^{}")) { if (item && - !has_object_file_with_flags(&ref->old_oid, HAS_SHA1_QUICK) && + !has_object_file_with_flags(&ref->old_oid, + OBJECT_INFO_QUICK) && !will_fetch(head, ref->old_oid.hash) && - !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) && + !has_sha1_file_with_flags(item->util, + OBJECT_INFO_QUICK) && !will_fetch(head, item->util)) item->util = NULL; item = NULL; @@ -258,7 +257,7 @@ static void find_non_local_tags(struct transport *transport, * fetch. */ if (item && - !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) && + !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) && !will_fetch(head, item->util)) item->util = NULL; @@ -279,7 +278,7 @@ static void find_non_local_tags(struct transport *transport, * checked to see if it needs fetching. */ if (item && - !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) && + !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) && !will_fetch(head, item->util)) item->util = NULL; @@ -941,7 +940,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map, for (ref = stale_refs; ref; ref = ref->next) string_list_append(&refnames, ref->name); - result = delete_refs(&refnames, 0); + result = delete_refs("fetch: prune", &refnames, 0); string_list_clear(&refnames, 0); } @@ -1340,10 +1339,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) deepen = 1; if (recurse_submodules != RECURSE_SUBMODULES_OFF) { - if (recurse_submodules_default) { - int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default); - set_config_fetch_recurse_submodules(arg); - } + set_config_fetch_recurse_submodules(recurse_submodules_default); gitmodules_config(); git_config(submodule_config, NULL); } diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 70137b0b7e..10cbb43416 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "refs.h" #include "commit.h" #include "diff.h" diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index eca365bf89..5d7c921a77 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "refs.h" #include "object.h" #include "parse-options.h" @@ -16,25 +17,25 @@ static char const * const for_each_ref_usage[] = { int cmd_for_each_ref(int argc, const char **argv, const char *prefix) { int i; - const char *format = "%(objectname) %(objecttype)\t%(refname)"; struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; - int maxcount = 0, quote_style = 0, icase = 0; + int maxcount = 0, icase = 0; struct ref_array array; struct ref_filter filter; + struct ref_format format = REF_FORMAT_INIT; struct option opts[] = { - OPT_BIT('s', "shell", "e_style, + OPT_BIT('s', "shell", &format.quote_style, N_("quote placeholders suitably for shells"), QUOTE_SHELL), - OPT_BIT('p', "perl", "e_style, + OPT_BIT('p', "perl", &format.quote_style, N_("quote placeholders suitably for perl"), QUOTE_PERL), - OPT_BIT(0 , "python", "e_style, + OPT_BIT(0 , "python", &format.quote_style, N_("quote placeholders suitably for python"), QUOTE_PYTHON), - OPT_BIT(0 , "tcl", "e_style, + OPT_BIT(0 , "tcl", &format.quote_style, N_("quote placeholders suitably for Tcl"), QUOTE_TCL), OPT_GROUP(""), OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), - OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), + OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")), OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), N_("field name to sort on"), &parse_opt_ref_sorting), OPT_CALLBACK(0, "points-at", &filter.points_at, @@ -51,16 +52,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) memset(&array, 0, sizeof(array)); memset(&filter, 0, sizeof(filter)); + format.format = "%(objectname) %(objecttype)\t%(refname)"; + + git_config(git_default_config, NULL); + parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0); if (maxcount < 0) { error("invalid --count argument: `%d'", maxcount); usage_with_options(for_each_ref_usage, opts); } - if (HAS_MULTI_BITS(quote_style)) { + if (HAS_MULTI_BITS(format.quote_style)) { error("more than one quoting style?"); usage_with_options(for_each_ref_usage, opts); } - if (verify_ref_format(format)) + if (verify_ref_format(&format)) usage_with_options(for_each_ref_usage, opts); if (!sorting) @@ -68,9 +73,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) sorting->ignore_case = icase; filter.ignore_case = icase; - /* for warn_ambiguous_refs */ - git_config(git_default_config, NULL); - filter.name_patterns = argv; filter.match_as_path = 1; filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN); @@ -79,7 +81,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) if (!maxcount || array.nr < maxcount) maxcount = array.nr; for (i = 0; i < maxcount; i++) - show_ref_array_item(array.items[i], format, quote_style); + show_ref_array_item(array.items[i], &format); ref_array_clear(&array); return 0; } diff --git a/builtin/fsck.c b/builtin/fsck.c index cb2ba6cd1b..a92f448186 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "commit.h" #include "tree.h" #include "blob.h" @@ -18,6 +19,8 @@ #define REACHABLE 0x0001 #define SEEN 0x0002 #define HAS_OBJ 0x0004 +/* This flag is set if something points to this object. */ +#define USED 0x0008 static int show_root; static int show_tags; @@ -167,18 +170,7 @@ static void mark_object_reachable(struct object *obj) static int traverse_one_object(struct object *obj) { - int result; - struct tree *tree = NULL; - - if (obj->type == OBJ_TREE) { - tree = (struct tree *)obj; - if (parse_tree(tree) < 0) - return 1; /* error already displayed */ - } - result = fsck_walk(obj, obj, &fsck_walk_options); - if (tree) - free_tree_buffer(tree); - return result; + return fsck_walk(obj, obj, &fsck_walk_options); } static int traverse_reachable(void) @@ -205,7 +197,7 @@ static int mark_used(struct object *obj, int type, void *data, struct fsck_optio { if (!obj) return 1; - obj->used = 1; + obj->flags |= USED; return 0; } @@ -254,7 +246,7 @@ static void check_unreachable_object(struct object *obj) } /* - * "!used" means that nothing at all points to it, including + * "!USED" means that nothing at all points to it, including * other unreachable objects. In other words, it's the "tip" * of some set of unreachable objects, usually a commit that * got dropped. @@ -265,7 +257,7 @@ static void check_unreachable_object(struct object *obj) * deleted a branch by mistake, this is a prime candidate to * start looking at, for example. */ - if (!obj->used) { + if (!(obj->flags & USED)) { if (show_dangling) printf("dangling %s %s\n", printable_type(obj), describe_object(obj)); @@ -280,8 +272,7 @@ static void check_unreachable_object(struct object *obj) free(filename); return; } - if (!(f = fopen(filename, "w"))) - die_errno("Could not open '%s'", filename); + f = xfopen(filename, "w"); if (obj->type == OBJ_BLOB) { if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1)) die_errno("Could not write '%s'", filename); @@ -390,7 +381,8 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type, errors_found |= ERROR_OBJECT; return error("%s: object corrupt or missing", oid_to_hex(oid)); } - obj->flags = HAS_OBJ; + obj->flags &= ~(REACHABLE | SEEN); + obj->flags |= HAS_OBJ; return fsck_obj(obj); } @@ -408,7 +400,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, add_decoration(fsck_walk_options.object_names, obj, xstrfmt("%s@{%"PRItime"}", refname, timestamp)); - obj->used = 1; + obj->flags |= USED; mark_object_reachable(obj); } else { error("%s: invalid reflog entry %s", refname, oid_to_hex(oid)); @@ -456,7 +448,7 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid, errors_found |= ERROR_REFS; } default_refs++; - obj->used = 1; + obj->flags |= USED; if (name_objects) add_decoration(fsck_walk_options.object_names, obj, xstrdup(refname)); @@ -524,7 +516,8 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data) return 0; /* keep checking other objects */ } - obj->flags = HAS_OBJ; + obj->flags &= ~(REACHABLE | SEEN); + obj->flags |= HAS_OBJ; if (fsck_obj(obj)) errors_found |= ERROR_OBJECT; return 0; @@ -537,7 +530,7 @@ static int fsck_cruft(const char *basename, const char *path, void *data) return 0; } -static int fsck_subdir(int nr, const char *path, void *progress) +static int fsck_subdir(unsigned int nr, const char *path, void *progress) { display_progress(progress, nr + 1); return 0; @@ -606,7 +599,7 @@ static int fsck_cache_tree(struct cache_tree *it) errors_found |= ERROR_REFS; return 1; } - obj->used = 1; + obj->flags |= USED; if (name_objects) add_decoration(fsck_walk_options.object_names, obj, xstrdup(":")); @@ -667,7 +660,7 @@ static struct option fsck_opts[] = { int cmd_fsck(int argc, const char **argv, const char *prefix) { - int i, heads; + int i; struct alternate_object_database *alt; errors_found = 0; @@ -735,25 +728,23 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) } } - heads = 0; for (i = 0; i < argc; i++) { const char *arg = argv[i]; - unsigned char sha1[20]; - if (!get_sha1(arg, sha1)) { - struct object *obj = lookup_object(sha1); + struct object_id oid; + if (!get_oid(arg, &oid)) { + struct object *obj = lookup_object(oid.hash); if (!obj || !(obj->flags & HAS_OBJ)) { - error("%s: object missing", sha1_to_hex(sha1)); + error("%s: object missing", oid_to_hex(&oid)); errors_found |= ERROR_OBJECT; continue; } - obj->used = 1; + obj->flags |= USED; if (name_objects) add_decoration(fsck_walk_options.object_names, obj, xstrdup(arg)); mark_object_reachable(obj); - heads++; continue; } error("invalid parameter: expected sha1, got '%s'", arg); @@ -785,7 +776,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) if (!blob) continue; obj = &blob->object; - obj->used = 1; + obj->flags |= USED; if (name_objects) add_decoration(fsck_walk_options.object_names, obj, diff --git a/builtin/gc.c b/builtin/gc.c index f484eda43c..e6b84475ae 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -11,6 +11,7 @@ */ #include "builtin.h" +#include "config.h" #include "tempfile.h" #include "lockfile.h" #include "parse-options.h" @@ -148,7 +149,7 @@ static int too_many_loose_objects(void) if (!dir) return 0; - auto_threshold = (gc_auto_threshold + 255) / 256; + auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256); while ((ent = readdir(dir)) != NULL) { if (strspn(ent->d_name, "0123456789abcdef") != 38 || ent->d_name[38] != '\0') @@ -413,8 +414,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix) if (report_last_gc_error()) return -1; + if (lock_repo_for_gc(force, &pid)) + return 0; if (gc_before_repack()) return -1; + delete_tempfile(&pidfile); + /* * failure to daemonize is ok, we'll continue * in foreground diff --git a/builtin/grep.c b/builtin/grep.c index c6c26e9b9e..3cbee04dc4 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -4,6 +4,8 @@ * Copyright (c) 2006 Junio C Hamano */ #include "cache.h" +#include "repository.h" +#include "config.h" #include "blob.h" #include "tree.h" #include "commit.h" @@ -73,14 +75,14 @@ static pthread_mutex_t grep_mutex; static inline void grep_lock(void) { - if (num_threads) - pthread_mutex_lock(&grep_mutex); + assert(num_threads); + pthread_mutex_lock(&grep_mutex); } static inline void grep_unlock(void) { - if (num_threads) - pthread_mutex_unlock(&grep_mutex); + assert(num_threads); + pthread_mutex_unlock(&grep_mutex); } /* Signalled when a new work_item is added to todo. */ @@ -224,7 +226,8 @@ static void start_threads(struct grep_opt *opt) int err; struct grep_opt *o = grep_opt_dup(opt); o->output = strbuf_out; - o->debug = 0; + if (i) + o->debug = 0; compile_grep_patterns(o); err = pthread_create(&threads[i], NULL, run, o); @@ -281,7 +284,7 @@ static int wait_all(void) static int grep_cmd_config(const char *var, const char *value, void *cb) { int st = grep_config(var, value, cb); - if (git_color_default_config(var, value, cb) < 0) + if (git_default_config(var, value, cb) < 0) st = -1; if (!strcmp(var, "grep.threads")) { @@ -289,8 +292,22 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) if (num_threads < 0) die(_("invalid number of threads specified (%d) for %s"), num_threads, var); +#ifdef NO_PTHREADS + else if (num_threads && num_threads != 1) { + /* + * TRANSLATORS: %s is the configuration + * variable for tweaking threads, currently + * grep.threads + */ + warning(_("no threads support, ignoring %s"), var); + num_threads = 0; + } +#endif } + if (!strcmp(var, "submodule.recurse")) + recurse_submodules = git_config_bool(var, value); + return st; } @@ -327,7 +344,7 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, #ifndef NO_PTHREADS if (num_threads) { - add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, oid); + add_work(opt, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); return 0; } else @@ -336,7 +353,7 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, struct grep_source gs; int hit; - grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, oid); + grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); hit = grep_source(opt, &gs); @@ -495,6 +512,8 @@ static void compile_submodule_options(const struct grep_opt *opt, break; case GREP_PATTERN_TYPE_UNSPECIFIED: break; + default: + die("BUG: Added a new grep pattern type without updating switch statement"); } for (pattern = opt->pattern_list; pattern != NULL; @@ -524,7 +543,7 @@ static void compile_submodule_options(const struct grep_opt *opt, * submodule process has its own thread pool. */ argv_array_pushf(&submodule_options, "--threads=%d", - (num_threads + 1) / 2); + DIV_ROUND_UP(num_threads, 2)); /* Add Pathspecs */ argv_array_push(&submodule_options, "--"); @@ -570,7 +589,7 @@ static int grep_submodule_launch(struct grep_opt *opt, * with the object's name: 'tree-name:filename'. In order to * provide uniformity of output we want to pass the name of the * parent project's object name to the submodule so the submodule can - * prefix its output with the parent's name and not its own SHA1. + * prefix its output with the parent's name and not its own OID. */ if (gs->identifier && end_of_base) argv_array_pushf(&cp.args, "--parent-basename=%.*s", @@ -583,12 +602,12 @@ static int grep_submodule_launch(struct grep_opt *opt, * If there is a tree identifier for the submodule, add the * rev after adding the submodule options but before the * pathspecs. To do this we listen for the '--' and insert the - * sha1 before pushing the '--' onto the child process argv + * oid before pushing the '--' onto the child process argv * array. */ if (gs->identifier && !strcmp("--", submodule_options.argv[i])) { - argv_array_push(&cp.args, sha1_to_hex(gs->identifier)); + argv_array_push(&cp.args, oid_to_hex(gs->identifier)); } argv_array_push(&cp.args, submodule_options.argv[i]); @@ -618,23 +637,23 @@ static int grep_submodule_launch(struct grep_opt *opt, /* * Prep grep structures for a submodule grep - * sha1: the sha1 of the submodule or NULL if using the working tree + * oid: the oid of the submodule or NULL if using the working tree * filename: name of the submodule including tree name of parent * path: location of the submodule */ -static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, +static int grep_submodule(struct grep_opt *opt, const struct object_id *oid, const char *filename, const char *path) { - if (!is_submodule_initialized(path)) + if (!is_submodule_active(the_repository, path)) return 0; if (!is_submodule_populated_gently(path, NULL)) { /* - * If searching history, check for the presense of the + * If searching history, check for the presence of the * submodule's gitdir before skipping the submodule. */ - if (sha1) { + if (oid) { const struct submodule *sub = - submodule_from_path(null_sha1, path); + submodule_from_path(&null_oid, path); if (sub) path = git_path("modules/%s", sub->name); @@ -647,7 +666,7 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, #ifndef NO_PTHREADS if (num_threads) { - add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, sha1); + add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, oid); return 0; } else #endif @@ -656,7 +675,7 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, int hit; grep_source_init(&gs, GREP_SOURCE_SUBMODULE, - filename, path, sha1); + filename, path, oid); hit = grep_submodule_launch(opt, &gs); grep_source_clear(&gs); @@ -775,7 +794,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, check_attr); free(data); } else if (recurse_submodules && S_ISGITLINK(entry.mode)) { - hit |= grep_submodule(opt, entry.oid->hash, base->buf, + hit |= grep_submodule(opt, entry.oid, base->buf, base->buf + tn_len); } @@ -843,7 +862,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, /* load the gitmodules file for this rev */ if (recurse_submodules) { submodule_free(); - gitmodules_config_sha1(real_obj->oid.hash); + gitmodules_config_oid(&real_obj->oid); } if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) { hit = 1; @@ -1151,10 +1170,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (!opt.pattern_list) die(_("no pattern given.")); - if (!opt.fixed && opt.ignore_case) - opt.regflags |= REG_ICASE; - - compile_grep_patterns(&opt); /* * We have to find "--" in a separate pass, because its presence @@ -1190,7 +1205,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) break; } - if (get_sha1_with_context(arg, 0, oid.hash, &oc)) { + if (get_oid_with_context(arg, GET_OID_RECORD_PATH, + &oid, &oc)) { if (seen_dashdash) die(_("unable to resolve revision: %s"), arg); break; @@ -1200,6 +1216,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (!seen_dashdash) verify_non_filename(prefix, arg); add_object_array_with_path(object, arg, &list, oc.mode, oc.path); + free(oc.path); } /* @@ -1226,10 +1243,23 @@ int cmd_grep(int argc, const char **argv, const char *prefix) num_threads = GREP_NUM_THREADS_DEFAULT; else if (num_threads < 0) die(_("invalid number of threads specified (%d)"), num_threads); + if (num_threads == 1) + num_threads = 0; #else + if (num_threads) + warning(_("no threads support, ignoring --threads")); num_threads = 0; #endif + if (!num_threads) + /* + * The compiled patterns on the main path are only + * used when not using threading. Otherwise + * start_threads() below calls compile_grep_patterns() + * for each thread. + */ + compile_grep_patterns(&opt); + #ifndef NO_PTHREADS if (num_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) diff --git a/builtin/hash-object.c b/builtin/hash-object.c index bbeaf20bcc..d04baf999a 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -5,6 +5,7 @@ * Copyright (C) Junio C Hamano, 2005 */ #include "builtin.h" +#include "config.h" #include "blob.h" #include "quote.h" #include "parse-options.h" diff --git a/builtin/help.c b/builtin/help.c index 49f7a07f85..334a8494ab 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -2,6 +2,7 @@ * Builtin help command */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "exec_cmd.h" #include "parse-options.h" diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 04b9dcaf0f..26828c1d82 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "delta.h" #include "pack.h" #include "csum-file.h" @@ -388,8 +389,7 @@ static struct base_data *alloc_base_data(void) static void free_base_data(struct base_data *c) { if (c->data) { - free(c->data); - c->data = NULL; + FREE_AND_NULL(c->data); get_thread_data()->base_cache_used -= c->size; } } @@ -605,8 +605,7 @@ static void *unpack_data(struct object_entry *obj, git_inflate_end(&stream); free(inbuf); if (consume) { - free(data); - data = NULL; + FREE_AND_NULL(data); } return data; } @@ -794,7 +793,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, if (startup_info->have_repository) { read_lock(); - collision_test_needed = has_sha1_file_with_flags(oid->hash, HAS_SHA1_QUICK); + collision_test_needed = + has_sha1_file_with_flags(oid->hash, OBJECT_INFO_QUICK); read_unlock(); } diff --git a/builtin/init-db.c b/builtin/init-db.c index 8a6acb0ec6..47823f9aa4 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "refs.h" #include "builtin.h" #include "exec_cmd.h" diff --git a/builtin/log.c b/builtin/log.c index a440601efe..cb7e0e61d7 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -5,6 +5,7 @@ * 2006 Junio Hamano */ #include "cache.h" +#include "config.h" #include "refs.h" #include "color.h" #include "commit.h" @@ -483,16 +484,20 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV)) return stream_blob_to_fd(1, oid, NULL, 0); - if (get_sha1_with_context(obj_name, 0, oidc.hash, &obj_context)) + if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH, + &oidc, &obj_context)) die(_("Not a valid object name %s"), obj_name); - if (!obj_context.path[0] || - !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) + if (!obj_context.path || + !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) { + free(obj_context.path); return stream_blob_to_fd(1, oid, NULL, 0); + } if (!buf) die(_("git show %s: bad file"), obj_name); write_or_die(1, buf, size); + free(obj_context.path); return 0; } @@ -842,8 +847,10 @@ static int open_next_file(struct commit *commit, const char *subject, if (output_directory) { strbuf_addstr(&filename, output_directory); if (filename.len >= - PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) + PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) { + strbuf_release(&filename); return error(_("name of output directory is too long")); + } strbuf_complete(&filename, '/'); } @@ -857,8 +864,11 @@ static int open_next_file(struct commit *commit, const char *subject, if (!quiet) printf("%s\n", filename.buf + outdir_offset); - if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) - return error(_("Cannot open patch file %s"), filename.buf); + if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) { + error_errno(_("Cannot open patch file %s"), filename.buf); + strbuf_release(&filename); + return -1; + } strbuf_release(&filename); return 0; @@ -1043,9 +1053,9 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, diff_setup_done(&opts); - diff_tree_sha1(origin->tree->object.oid.hash, - head->tree->object.oid.hash, - "", &opts); + diff_tree_oid(&origin->tree->object.oid, + &head->tree->object.oid, + "", &opts); diffcore_std(&opts); diff_flush(&opts); @@ -1298,7 +1308,7 @@ static struct commit *get_base_commit(const char *base_commit, if (rev_nr % 2) rev[i] = rev[2 * i]; - rev_nr = (rev_nr + 1) / 2; + rev_nr = DIV_ROUND_UP(rev_nr, 2); } if (!in_merge_bases(base, rev[0])) @@ -1354,7 +1364,7 @@ static void prepare_bases(struct base_tree_info *bases, struct object_id *patch_id; if (commit->util) continue; - if (commit_patch_id(commit, &diffopt, oid.hash, 0)) + if (commit_patch_id(commit, &diffopt, &oid, 0)) die(_("cannot get patch id")); ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id); patch_id = bases->patch_id + bases->nr_patch_id; diff --git a/builtin/ls-files.c b/builtin/ls-files.c index b376afc312..c6126eae55 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -5,7 +5,10 @@ * * Copyright (C) Linus Torvalds, 2005 */ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" +#include "repository.h" +#include "config.h" #include "quote.h" #include "dir.h" #include "builtin.h" @@ -31,10 +34,8 @@ static int line_terminator = '\n'; static int debug_mode; static int show_eol; static int recurse_submodules; -static struct argv_array submodule_options = ARGV_ARRAY_INIT; static const char *prefix; -static const char *super_prefix; static int max_prefix_len; static int prefix_len; static struct pathspec pathspec; @@ -53,17 +54,17 @@ static const char *tag_modified = ""; static const char *tag_skip_worktree = ""; static const char *tag_resolve_undo = ""; -static void write_eolinfo(const struct cache_entry *ce, const char *path) +static void write_eolinfo(const struct index_state *istate, + const struct cache_entry *ce, const char *path) { - if (!show_eol) - return; - else { + if (show_eol) { struct stat st; const char *i_txt = ""; const char *w_txt = ""; const char *a_txt = get_convert_attr_ascii(path); if (ce && S_ISREG(ce->ce_mode)) - i_txt = get_cached_convert_stats_ascii(ce->name); + i_txt = get_cached_convert_stats_ascii(istate, + ce->name); if (!lstat(path, &st) && S_ISREG(st.st_mode)) w_txt = get_wt_convert_stats_ascii(path); printf("i/%-5s w/%-5s attr/%-17s\t", i_txt, w_txt, a_txt); @@ -73,24 +74,48 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path) static void write_name(const char *name) { /* - * Prepend the super_prefix to name to construct the full_name to be - * written. - */ - struct strbuf full_name = STRBUF_INIT; - if (super_prefix) { - strbuf_addstr(&full_name, super_prefix); - strbuf_addstr(&full_name, name); - name = full_name.buf; - } - - /* * With "--full-name", prefix_len=0; this caller needs to pass * an empty string in that case (a NULL is good for ""). */ write_name_quoted_relative(name, prefix_len ? prefix : NULL, stdout, line_terminator); +} + +static const char *get_tag(const struct cache_entry *ce, const char *tag) +{ + static char alttag[4]; + + if (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) { + memcpy(alttag, tag, 3); + + if (isalpha(tag[0])) { + alttag[0] = tolower(tag[0]); + } else if (tag[0] == '?') { + alttag[0] = '!'; + } else { + alttag[0] = 'v'; + alttag[1] = tag[0]; + alttag[2] = ' '; + alttag[3] = 0; + } - strbuf_release(&full_name); + tag = alttag; + } + + return tag; +} + +static void print_debug(const struct cache_entry *ce) +{ + if (debug_mode) { + const struct stat_data *sd = &ce->ce_stat_data; + + printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); + printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); + printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); + printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); + printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); + } } static void show_dir_entry(const char *tag, struct dir_entry *ent) @@ -104,23 +129,25 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent) return; fputs(tag, stdout); - write_eolinfo(NULL, ent->name); + write_eolinfo(NULL, NULL, ent->name); write_name(ent->name); } -static void show_other_files(struct dir_struct *dir) +static void show_other_files(const struct index_state *istate, + const struct dir_struct *dir) { int i; for (i = 0; i < dir->nr; i++) { struct dir_entry *ent = dir->entries[i]; - if (!cache_name_is_other(ent->name, ent->len)) + if (!index_name_is_other(istate, ent->name, ent->len)) continue; show_dir_entry(tag_other, ent); } } -static void show_killed_files(struct dir_struct *dir) +static void show_killed_files(const struct index_state *istate, + const struct dir_struct *dir) { int i; for (i = 0; i < dir->nr; i++) { @@ -134,29 +161,29 @@ static void show_killed_files(struct dir_struct *dir) /* If ent->name is prefix of an entry in the * cache, it will be killed. */ - pos = cache_name_pos(ent->name, ent->len); + pos = index_name_pos(istate, ent->name, ent->len); if (0 <= pos) die("BUG: killed-file %.*s not found", ent->len, ent->name); pos = -pos - 1; - while (pos < active_nr && - ce_stage(active_cache[pos])) + while (pos < istate->cache_nr && + ce_stage(istate->cache[pos])) pos++; /* skip unmerged */ - if (active_nr <= pos) + if (istate->cache_nr <= pos) break; /* pos points at a name immediately after * ent->name in the cache. Does it expect * ent->name to be a directory? */ - len = ce_namelen(active_cache[pos]); + len = ce_namelen(istate->cache[pos]); if ((ent->len < len) && - !strncmp(active_cache[pos]->name, + !strncmp(istate->cache[pos]->name, ent->name, ent->len) && - active_cache[pos]->name[ent->len] == '/') + istate->cache[pos]->name[ent->len] == '/') killed = 1; break; } - if (0 <= cache_name_pos(ent->name, sp - ent->name)) { + if (0 <= index_name_pos(istate, ent->name, sp - ent->name)) { /* If any of the leading directories in * ent->name is registered in the cache, * ent->name will be killed. @@ -170,100 +197,41 @@ static void show_killed_files(struct dir_struct *dir) } } -/* - * Compile an argv_array with all of the options supported by --recurse_submodules - */ -static void compile_submodule_options(const char **argv, - const struct dir_struct *dir, - int show_tag) -{ - if (line_terminator == '\0') - argv_array_push(&submodule_options, "-z"); - if (show_tag) - argv_array_push(&submodule_options, "-t"); - if (show_valid_bit) - argv_array_push(&submodule_options, "-v"); - if (show_cached) - argv_array_push(&submodule_options, "--cached"); - if (show_eol) - argv_array_push(&submodule_options, "--eol"); - if (debug_mode) - argv_array_push(&submodule_options, "--debug"); - - /* Add Pathspecs */ - argv_array_push(&submodule_options, "--"); - for (; *argv; argv++) - argv_array_push(&submodule_options, *argv); -} +static void show_files(struct repository *repo, struct dir_struct *dir); -/** - * Recursively call ls-files on a submodule - */ -static void show_gitlink(const struct cache_entry *ce) +static void show_submodule(struct repository *superproject, + struct dir_struct *dir, const char *path) { - struct child_process cp = CHILD_PROCESS_INIT; - int status; - char *dir; - - prepare_submodule_repo_env(&cp.env_array); - argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT); - - if (prefix_len) - argv_array_pushf(&cp.env_array, "%s=%s", - GIT_TOPLEVEL_PREFIX_ENVIRONMENT, - prefix); - argv_array_pushf(&cp.args, "--super-prefix=%s%s/", - super_prefix ? super_prefix : "", - ce->name); - argv_array_push(&cp.args, "ls-files"); - argv_array_push(&cp.args, "--recurse-submodules"); - - /* add supported options */ - argv_array_pushv(&cp.args, submodule_options.argv); - - cp.git_cmd = 1; - dir = mkpathdup("%s/%s", get_git_work_tree(), ce->name); - cp.dir = dir; - status = run_command(&cp); - free(dir); - if (status) - exit(status); + struct repository submodule; + + if (repo_submodule_init(&submodule, superproject, path)) + return; + + if (repo_read_index(&submodule) < 0) + die("index file corrupt"); + + repo_read_gitmodules(&submodule); + + show_files(&submodule, dir); + + repo_clear(&submodule); } -static void show_ce_entry(const char *tag, const struct cache_entry *ce) +static void show_ce(struct repository *repo, struct dir_struct *dir, + const struct cache_entry *ce, const char *fullname, + const char *tag) { - struct strbuf name = STRBUF_INIT; - int len = max_prefix_len; - if (super_prefix) - strbuf_addstr(&name, super_prefix); - strbuf_addstr(&name, ce->name); - - if (len > ce_namelen(ce)) + if (max_prefix_len > strlen(fullname)) die("git ls-files: internal error - cache entry not superset of prefix"); if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && - submodule_path_match(&pathspec, name.buf, ps_matched)) { - show_gitlink(ce); - } else if (match_pathspec(&pathspec, name.buf, name.len, - len, ps_matched, + is_submodule_active(repo, ce->name)) { + show_submodule(repo, dir, ce->name); + } else if (match_pathspec(&pathspec, fullname, strlen(fullname), + max_prefix_len, ps_matched, S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) { - if (tag && *tag && show_valid_bit && - (ce->ce_flags & CE_VALID)) { - static char alttag[4]; - memcpy(alttag, tag, 3); - if (isalpha(tag[0])) - alttag[0] = tolower(tag[0]); - else if (tag[0] == '?') - alttag[0] = '!'; - else { - alttag[0] = 'v'; - alttag[1] = tag[0]; - alttag[2] = ' '; - alttag[3] = 0; - } - tag = alttag; - } + tag = get_tag(ce, tag); if (!show_stage) { fputs(tag, stdout); @@ -274,30 +242,20 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce) find_unique_abbrev(ce->oid.hash, abbrev), ce_stage(ce)); } - write_eolinfo(ce, ce->name); - write_name(ce->name); - if (debug_mode) { - const struct stat_data *sd = &ce->ce_stat_data; - - printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); - printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); - printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); - printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); - printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); - } + write_eolinfo(repo->index, ce, fullname); + write_name(fullname); + print_debug(ce); } - - strbuf_release(&name); } -static void show_ru_info(void) +static void show_ru_info(const struct index_state *istate) { struct string_list_item *item; - if (!the_index.resolve_undo) + if (!istate->resolve_undo) return; - for_each_string_list_item(item, the_index.resolve_undo) { + for_each_string_list_item(item, istate->resolve_undo) { const char *path = item->string; struct resolve_undo_info *ui = item->util; int i, len; @@ -319,88 +277,109 @@ static void show_ru_info(void) } } -static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce) +static int ce_excluded(struct dir_struct *dir, struct index_state *istate, + const char *fullname, const struct cache_entry *ce) { int dtype = ce_to_dtype(ce); - return is_excluded(dir, &the_index, ce->name, &dtype); + return is_excluded(dir, istate, fullname, &dtype); +} + +static void construct_fullname(struct strbuf *out, const struct repository *repo, + const struct cache_entry *ce) +{ + strbuf_reset(out); + if (repo->submodule_prefix) + strbuf_addstr(out, repo->submodule_prefix); + strbuf_addstr(out, ce->name); } -static void show_files(struct dir_struct *dir) +static void show_files(struct repository *repo, struct dir_struct *dir) { int i; + struct strbuf fullname = STRBUF_INIT; /* For cached/deleted files we don't need to even do the readdir */ if (show_others || show_killed) { if (!show_others) dir->flags |= DIR_COLLECT_KILLED_ONLY; - fill_directory(dir, &the_index, &pathspec); + fill_directory(dir, repo->index, &pathspec); if (show_others) - show_other_files(dir); + show_other_files(repo->index, dir); if (show_killed) - show_killed_files(dir); + show_killed_files(repo->index, dir); } if (show_cached || show_stage) { - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; + for (i = 0; i < repo->index->cache_nr; i++) { + const struct cache_entry *ce = repo->index->cache[i]; + + construct_fullname(&fullname, repo, ce); + if ((dir->flags & DIR_SHOW_IGNORED) && - !ce_excluded(dir, ce)) + !ce_excluded(dir, repo->index, fullname.buf, ce)) continue; if (show_unmerged && !ce_stage(ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; - show_ce_entry(ce_stage(ce) ? tag_unmerged : - (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce); + show_ce(repo, dir, ce, fullname.buf, + ce_stage(ce) ? tag_unmerged : + (ce_skip_worktree(ce) ? tag_skip_worktree : + tag_cached)); } } if (show_deleted || show_modified) { - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; + for (i = 0; i < repo->index->cache_nr; i++) { + const struct cache_entry *ce = repo->index->cache[i]; struct stat st; int err; + + construct_fullname(&fullname, repo, ce); + if ((dir->flags & DIR_SHOW_IGNORED) && - !ce_excluded(dir, ce)) + !ce_excluded(dir, repo->index, fullname.buf, ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; if (ce_skip_worktree(ce)) continue; - err = lstat(ce->name, &st); + err = lstat(fullname.buf, &st); if (show_deleted && err) - show_ce_entry(tag_removed, ce); - if (show_modified && ce_modified(ce, &st, 0)) - show_ce_entry(tag_modified, ce); + show_ce(repo, dir, ce, fullname.buf, tag_removed); + if (show_modified && ie_modified(repo->index, ce, &st, 0)) + show_ce(repo, dir, ce, fullname.buf, tag_modified); } } + + strbuf_release(&fullname); } /* * Prune the index to only contain stuff starting with "prefix" */ -static void prune_cache(const char *prefix, size_t prefixlen) +static void prune_index(struct index_state *istate, + const char *prefix, size_t prefixlen) { int pos; unsigned int first, last; - if (!prefix) + if (!prefix || !istate->cache_nr) return; - pos = cache_name_pos(prefix, prefixlen); + pos = index_name_pos(istate, prefix, prefixlen); if (pos < 0) pos = -pos-1; first = pos; - last = active_nr; + last = istate->cache_nr; while (last > first) { int next = (last + first) >> 1; - const struct cache_entry *ce = active_cache[next]; + const struct cache_entry *ce = istate->cache[next]; if (!strncmp(ce->name, prefix, prefixlen)) { first = next+1; continue; } last = next; } - memmove(active_cache, active_cache + pos, - (last - pos) * sizeof(struct cache_entry *)); - active_nr = last - pos; + MOVE_ARRAY(istate->cache, istate->cache + pos, last - pos); + istate->cache_nr = last - pos; } static int get_common_prefix_len(const char *common_prefix) @@ -430,7 +409,8 @@ static int get_common_prefix_len(const char *common_prefix) * that were given from the command line. We are not * going to write this index out. */ -void overlay_tree_on_cache(const char *tree_name, const char *prefix) +void overlay_tree_on_index(struct index_state *istate, + const char *tree_name, const char *prefix) { struct tree *tree; struct object_id oid; @@ -445,8 +425,8 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) die("bad tree-ish %s", tree_name); /* Hoist the unmerged entries up to stage #3 to make room */ - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; if (!ce_stage(ce)) continue; ce->ce_flags |= CE_STAGEMASK; @@ -459,11 +439,11 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) PATHSPEC_PREFER_CWD, prefix, matchbuf); } else memset(&pathspec, 0, sizeof(pathspec)); - if (read_tree(tree, 1, &pathspec)) + if (read_tree(tree, 1, &pathspec, istate)) die("unable to read tree entries %s", tree_name); - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; switch (ce_stage(ce)) { case 0: last_stage0 = ce; @@ -594,10 +574,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) prefix = cmd_prefix; if (prefix) prefix_len = strlen(prefix); - super_prefix = get_super_prefix(); git_config(git_default_config, NULL); - if (read_cache() < 0) + if (repo_read_index(the_repository) < 0) die("index file corrupt"); argc = parse_options(argc, argv, prefix, builtin_ls_files_options, @@ -631,7 +610,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) setup_work_tree(); if (recurse_submodules) - compile_submodule_options(argv, &dir, show_tag); + repo_read_gitmodules(the_repository); if (recurse_submodules && (show_stage || show_deleted || show_others || show_unmerged || @@ -649,7 +628,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) /* * Find common prefix for all pathspec's * This is used as a performance optimization which unfortunately cannot - * be done when recursing into submodules + * be done when recursing into submodules because when a pathspec is + * given which spans repository boundaries you can't simply remove the + * submodule entry because the pathspec may match something inside the + * submodule. */ if (recurse_submodules) max_prefix = NULL; @@ -657,7 +639,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) max_prefix = common_prefix(&pathspec); max_prefix_len = get_common_prefix_len(max_prefix); - prune_cache(max_prefix, max_prefix_len); + prune_index(the_repository->index, max_prefix, max_prefix_len); /* Treat unmatching pathspec elements as errors */ if (pathspec.nr && error_unmatch) @@ -678,11 +660,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) */ if (show_stage || show_unmerged) die("ls-files --with-tree is incompatible with -s or -u"); - overlay_tree_on_cache(with_tree, max_prefix); + overlay_tree_on_index(the_repository->index, with_tree, max_prefix); } - show_files(&dir); + + show_files(the_repository, &dir); + if (show_resolve_undo) - show_ru_info(); + show_ru_info(the_repository->index); if (ps_matched) { int bad; diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index b2d7d5ce68..c4be98ab9e 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -24,7 +24,7 @@ static int tail_match(const char **pattern, const char *path) pathbuf = xstrfmt("/%s", path); while ((p = *(pattern++)) != NULL) { - if (!wildmatch(p, pathbuf, 0, NULL)) { + if (!wildmatch(p, pathbuf, 0)) { free(pathbuf); return 1; } diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index ee7b293b11..ef965408e8 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "blob.h" #include "tree.h" #include "commit.h" diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 0c36a70ad8..6dbd167d3b 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "commit.h" #include "refs.h" #include "diff.h" diff --git a/builtin/merge-file.c b/builtin/merge-file.c index 47dde7c39c..b08803e611 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "xdiff/xdiff.h" #include "xdiff-interface.h" #include "parse-options.h" diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index bad6735c76..f12da292cf 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -347,12 +347,12 @@ static void merge_trees(struct tree_desc t[3], const char *base) static void *get_tree_descriptor(struct tree_desc *desc, const char *rev) { - unsigned char sha1[20]; + struct object_id oid; void *buf; - if (get_sha1(rev, sha1)) + if (get_oid(rev, &oid)) die("unknown rev %s", rev); - buf = fill_tree_descriptor(desc, sha1); + buf = fill_tree_descriptor(desc, oid.hash); if (!buf) die("%s is not a tree", rev); return buf; diff --git a/builtin/merge.c b/builtin/merge.c index a4a098f40f..d5797b8fe7 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "config.h" #include "parse-options.h" #include "builtin.h" #include "lockfile.h" @@ -415,7 +416,7 @@ static void finish(struct commit *head_commit, DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff_setup_done(&opts); - diff_tree_sha1(head->hash, new_head->hash, "", &opts); + diff_tree_oid(head, new_head, "", &opts); diffcore_std(&opts); diff_flush(&opts); } @@ -536,7 +537,7 @@ static void parse_branch_merge_options(char *bmo) die(_("Bad branch.%s.mergeoptions string: %s"), branch, split_cmdline_strerror(argc)); REALLOC_ARRAY(argv, argc + 2); - memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); + MOVE_ARRAY(argv + 1, argv, argc + 1); argc++; argv[0] = "branch.*.mergeoptions"; parse_options(argc, argv, NULL, builtin_merge_options, @@ -839,9 +840,7 @@ static int suggest_conflicts(void) struct strbuf msgbuf = STRBUF_INIT; filename = git_path_merge_msg(); - fp = fopen(filename, "a"); - if (!fp) - die_errno(_("Could not open '%s' for writing"), filename); + fp = xfopen(filename, "a"); append_conflicts_hint(&msgbuf); fputs(msgbuf.buf, fp); diff --git a/builtin/mv.c b/builtin/mv.c index 61d20037ad..dcf6736b5b 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -4,6 +4,7 @@ * Copyright (C) 2006 Johannes Schindelin */ #include "builtin.h" +#include "config.h" #include "pathspec.h" #include "lockfile.h" #include "dir.h" diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 7fc7e66e85..c41ea7c2a6 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "commit.h" #include "tag.h" #include "refs.h" @@ -129,7 +130,7 @@ static int subpath_matches(const char *path, const char *filter) const char *subpath = path; while (subpath) { - if (!wildmatch(filter, subpath, 0, NULL)) + if (!wildmatch(filter, subpath, 0)) return subpath - path; subpath = strchr(subpath, '/'); if (subpath) diff --git a/builtin/notes.c b/builtin/notes.c index f2847c41e0..4303848e04 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -8,6 +8,7 @@ */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "notes.h" #include "blob.h" @@ -109,11 +110,11 @@ static void free_note_data(struct note_data *d) strbuf_release(&d->buf); } -static int list_each_note(const unsigned char *object_sha1, - const unsigned char *note_sha1, char *note_path, +static int list_each_note(const struct object_id *object_oid, + const struct object_id *note_oid, char *note_path, void *cb_data) { - printf("%s %s\n", sha1_to_hex(note_sha1), sha1_to_hex(object_sha1)); + printf("%s %s\n", oid_to_hex(note_oid), oid_to_hex(object_oid)); return 0; } @@ -129,10 +130,10 @@ static void copy_obj_to_fd(int fd, const unsigned char *sha1) } } -static void write_commented_object(int fd, const unsigned char *object) +static void write_commented_object(int fd, const struct object_id *object) { const char *show_args[5] = - {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL}; + {"show", "--stat", "--no-notes", oid_to_hex(object), NULL}; struct child_process show = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; struct strbuf cbuf = STRBUF_INIT; @@ -145,7 +146,7 @@ static void write_commented_object(int fd, const unsigned char *object) show.git_cmd = 1; if (start_command(&show)) die(_("unable to start 'show' for object '%s'"), - sha1_to_hex(object)); + oid_to_hex(object)); if (strbuf_read(&buf, show.out, 0) < 0) die_errno(_("could not read 'show' output")); @@ -157,10 +158,10 @@ static void write_commented_object(int fd, const unsigned char *object) if (finish_command(&show)) die(_("failed to finish 'show' for object '%s'"), - sha1_to_hex(object)); + oid_to_hex(object)); } -static void prepare_note_data(const unsigned char *object, struct note_data *d, +static void prepare_note_data(const struct object_id *object, struct note_data *d, const unsigned char *old_note) { if (d->use_editor || !d->given) { @@ -243,16 +244,16 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset) { struct note_data *d = opt->value; char *buf; - unsigned char object[20]; + struct object_id object; enum object_type type; unsigned long len; if (d->buf.len) strbuf_addch(&d->buf, '\n'); - if (get_sha1(arg, object)) + if (get_oid(arg, &object)) die(_("failed to resolve '%s' as a valid ref."), arg); - if (!(buf = read_sha1_file(object, &type, &len))) { + if (!(buf = read_sha1_file(object.hash, &type, &len))) { free(buf); die(_("failed to read object '%s'."), arg); } @@ -292,7 +293,7 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd) } while (strbuf_getline_lf(&buf, stdin) != EOF) { - unsigned char from_obj[20], to_obj[20]; + struct object_id from_obj, to_obj; struct strbuf **split; int err; @@ -301,15 +302,15 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd) die(_("malformed input line: '%s'."), buf.buf); strbuf_rtrim(split[0]); strbuf_rtrim(split[1]); - if (get_sha1(split[0]->buf, from_obj)) + if (get_oid(split[0]->buf, &from_obj)) die(_("failed to resolve '%s' as a valid ref."), split[0]->buf); - if (get_sha1(split[1]->buf, to_obj)) + if (get_oid(split[1]->buf, &to_obj)) die(_("failed to resolve '%s' as a valid ref."), split[1]->buf); if (rewrite_cmd) - err = copy_note_for_rewrite(c, from_obj, to_obj); + err = copy_note_for_rewrite(c, &from_obj, &to_obj); else - err = copy_note(t, from_obj, to_obj, force, + err = copy_note(t, &from_obj, &to_obj, force, combine_notes_overwrite); if (err) { @@ -340,8 +341,10 @@ static struct notes_tree *init_notes_check(const char *subcommand, ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref; if (!starts_with(ref, "refs/notes/")) - /* TRANSLATORS: the first %s will be replaced by a - git notes command: 'add', 'merge', 'remove', etc.*/ + /* + * TRANSLATORS: the first %s will be replaced by a git + * notes command: 'add', 'merge', 'remove', etc. + */ die(_("refusing to %s notes in %s (outside of refs/notes/)"), subcommand, ref); return t; @@ -350,8 +353,8 @@ static struct notes_tree *init_notes_check(const char *subcommand, static int list(int argc, const char **argv, const char *prefix) { struct notes_tree *t; - unsigned char object[20]; - const unsigned char *note; + struct object_id object; + const struct object_id *note; int retval = -1; struct option options[] = { OPT_END() @@ -368,15 +371,15 @@ static int list(int argc, const char **argv, const char *prefix) t = init_notes_check("list", 0); if (argc) { - if (get_sha1(argv[0], object)) + if (get_oid(argv[0], &object)) die(_("failed to resolve '%s' as a valid ref."), argv[0]); - note = get_note(t, object); + note = get_note(t, &object); if (note) { - puts(sha1_to_hex(note)); + puts(oid_to_hex(note)); retval = 0; } else retval = error(_("no note found for object %s."), - sha1_to_hex(object)); + oid_to_hex(&object)); } else retval = for_each_note(t, 0, list_each_note, NULL); @@ -391,8 +394,8 @@ static int add(int argc, const char **argv, const char *prefix) int force = 0, allow_empty = 0; const char *object_ref; struct notes_tree *t; - unsigned char object[20], new_note[20]; - const unsigned char *note; + struct object_id object, new_note; + const struct object_id *note; struct note_data d = { 0, 0, NULL, STRBUF_INIT }; struct option options[] = { { OPTION_CALLBACK, 'm', "message", &d, N_("message"), @@ -423,11 +426,11 @@ static int add(int argc, const char **argv, const char *prefix) object_ref = argc > 1 ? argv[1] : "HEAD"; - if (get_sha1(object_ref, object)) + if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("add", NOTES_INIT_WRITABLE); - note = get_note(t, object); + note = get_note(t, &object); if (note) { if (!force) { @@ -437,7 +440,7 @@ static int add(int argc, const char **argv, const char *prefix) return error(_("Cannot add notes. " "Found existing notes for object %s. " "Use '-f' to overwrite existing notes"), - sha1_to_hex(object)); + oid_to_hex(&object)); } /* * Redirect to "edit" subcommand. @@ -450,19 +453,19 @@ static int add(int argc, const char **argv, const char *prefix) return append_edit(argc, argv, prefix); } fprintf(stderr, _("Overwriting existing notes for object %s\n"), - sha1_to_hex(object)); + oid_to_hex(&object)); } - prepare_note_data(object, &d, note); + prepare_note_data(&object, &d, note ? note->hash : NULL); if (d.buf.len || allow_empty) { - write_note_data(&d, new_note); - if (add_note(t, object, new_note, combine_notes_overwrite)) + write_note_data(&d, new_note.hash); + if (add_note(t, &object, &new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); commit_notes(t, "Notes added by 'git notes add'"); } else { fprintf(stderr, _("Removing note for object %s\n"), - sha1_to_hex(object)); - remove_note(t, object); + oid_to_hex(&object)); + remove_note(t, object.hash); commit_notes(t, "Notes removed by 'git notes add'"); } @@ -474,9 +477,9 @@ static int add(int argc, const char **argv, const char *prefix) 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 struct object_id *from_note, *note; const char *object_ref; - unsigned char object[20], from_obj[20]; + struct object_id object, from_obj; struct notes_tree *t; const char *rewrite_cmd = NULL; struct option options[] = { @@ -509,37 +512,37 @@ static int copy(int argc, const char **argv, const char *prefix) usage_with_options(git_notes_copy_usage, options); } - if (get_sha1(argv[0], from_obj)) + if (get_oid(argv[0], &from_obj)) die(_("failed to resolve '%s' as a valid ref."), argv[0]); object_ref = 1 < argc ? argv[1] : "HEAD"; - if (get_sha1(object_ref, object)) + if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("copy", NOTES_INIT_WRITABLE); - note = get_note(t, object); + note = get_note(t, &object); 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)); + oid_to_hex(&object)); goto out; } fprintf(stderr, _("Overwriting existing notes for object %s\n"), - sha1_to_hex(object)); + oid_to_hex(&object)); } - from_note = get_note(t, from_obj); + 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)); + "copy."), oid_to_hex(&from_obj)); goto out; } - if (add_note(t, object, from_note, combine_notes_overwrite)) + if (add_note(t, &object, from_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); commit_notes(t, "Notes added by 'git notes copy'"); out: @@ -552,8 +555,8 @@ static int append_edit(int argc, const char **argv, const char *prefix) int allow_empty = 0; const char *object_ref; struct notes_tree *t; - unsigned char object[20], new_note[20]; - const unsigned char *note; + struct object_id object, new_note; + const struct object_id *note; char *logmsg; const char * const *usage; struct note_data d = { 0, 0, NULL, STRBUF_INIT }; @@ -592,19 +595,19 @@ static int append_edit(int argc, const char **argv, const char *prefix) object_ref = 1 < argc ? argv[1] : "HEAD"; - if (get_sha1(object_ref, object)) + if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check(argv[0], NOTES_INIT_WRITABLE); - note = get_note(t, object); + note = get_note(t, &object); - prepare_note_data(object, &d, edit ? note : NULL); + prepare_note_data(&object, &d, edit && note ? note->hash : NULL); if (note && !edit) { /* Append buf to previous note contents */ unsigned long size; enum object_type type; - char *prev_buf = read_sha1_file(note, &type, &size); + char *prev_buf = read_sha1_file(note->hash, &type, &size); strbuf_grow(&d.buf, size + 1); if (d.buf.len && prev_buf && size) @@ -615,14 +618,14 @@ static int append_edit(int argc, const char **argv, const char *prefix) } if (d.buf.len || allow_empty) { - write_note_data(&d, new_note); - if (add_note(t, object, new_note, combine_notes_overwrite)) + write_note_data(&d, new_note.hash); + if (add_note(t, &object, &new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]); } else { fprintf(stderr, _("Removing note for object %s\n"), - sha1_to_hex(object)); - remove_note(t, object); + oid_to_hex(&object)); + remove_note(t, object.hash); logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]); } commit_notes(t, logmsg); @@ -637,8 +640,8 @@ 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; + struct object_id object; + const struct object_id *note; int retval; struct option options[] = { OPT_END() @@ -654,17 +657,17 @@ static int show(int argc, const char **argv, const char *prefix) object_ref = argc ? argv[0] : "HEAD"; - if (get_sha1(object_ref, object)) + if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("show", 0); - note = get_note(t, object); + note = get_note(t, &object); if (!note) retval = error(_("no note found for object %s."), - sha1_to_hex(object)); + oid_to_hex(&object)); else { - const char *show_args[3] = {"show", sha1_to_hex(note), NULL}; + const char *show_args[3] = {"show", oid_to_hex(note), NULL}; retval = execv_git_cmd(show_args); } free_notes(t); @@ -724,7 +727,7 @@ static int merge_commit(struct notes_merge_options *o) if (!o->local_ref) die(_("failed to resolve NOTES_MERGE_REF")); - if (notes_merge_commit(o, t, partial, oid.hash)) + if (notes_merge_commit(o, t, partial, &oid)) die(_("failed to finalize notes merge")); /* Reuse existing commit message in reflog message */ @@ -760,7 +763,7 @@ static int git_config_get_notes_strategy(const char *key, static int merge(int argc, const char **argv, const char *prefix) { struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT; - unsigned char result_sha1[20]; + struct object_id result_oid; struct notes_tree *t; struct notes_merge_options o; int do_merge = 0, do_commit = 0, do_abort = 0; @@ -842,16 +845,16 @@ static int merge(int argc, const char **argv, const char *prefix) remote_ref.buf, default_notes_ref()); strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */ - result = notes_merge(&o, t, result_sha1); + result = notes_merge(&o, t, &result_oid); - if (result >= 0) /* Merge resulted (trivially) in result_sha1 */ + if (result >= 0) /* Merge resulted (trivially) in result_oid */ /* Update default notes ref with new commit */ - update_ref(msg.buf, default_notes_ref(), result_sha1, NULL, + update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); else { /* Merge has unresolved conflicts */ const struct worktree *wt; /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */ - update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL, + update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */ wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref()); @@ -878,10 +881,10 @@ static int merge(int argc, const char **argv, const char *prefix) static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag) { int status; - unsigned char sha1[20]; - if (get_sha1(name, sha1)) + struct object_id oid; + if (get_oid(name, &oid)) return error(_("Failed to resolve '%s' as a valid ref."), name); - status = remove_note(t, sha1); + status = remove_note(t, oid.hash); if (status) fprintf(stderr, _("Object %s has no note\n"), name); else diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 80439047aa..c753e9237a 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "attr.h" #include "object.h" #include "blob.h" @@ -264,8 +265,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent * make sure no cached delta data remains from a * previous attempt before a pack split occurred. */ - free(entry->delta_data); - entry->delta_data = NULL; + FREE_AND_NULL(entry->delta_data); entry->z_delta_size = 0; } else if (entry->delta_data) { size = entry->delta_size; @@ -1289,7 +1289,7 @@ static int done_pbase_path_pos(unsigned hash) static int check_pbase_path(unsigned hash) { - int pos = (!done_pbase_paths) ? -1 : done_pbase_path_pos(hash); + int pos = done_pbase_path_pos(hash); if (0 <= pos) return 1; pos = -pos - 1; @@ -1298,9 +1298,8 @@ static int check_pbase_path(unsigned hash) done_pbase_paths_alloc); done_pbase_paths_num++; if (pos < done_pbase_paths_num) - memmove(done_pbase_paths + pos + 1, - done_pbase_paths + pos, - (done_pbase_paths_num - pos - 1) * sizeof(unsigned)); + MOVE_ARRAY(done_pbase_paths + pos + 1, done_pbase_paths + pos, + done_pbase_paths_num - pos - 1); done_pbase_paths[pos] = hash; return 0; } @@ -1375,12 +1374,10 @@ static void cleanup_preferred_base(void) if (!pbase_tree_cache[i]) continue; free(pbase_tree_cache[i]->tree_data); - free(pbase_tree_cache[i]); - pbase_tree_cache[i] = NULL; + FREE_AND_NULL(pbase_tree_cache[i]); } - free(done_pbase_paths); - done_pbase_paths = NULL; + FREE_AND_NULL(done_pbase_paths); done_pbase_paths_num = done_pbase_paths_alloc = 0; } @@ -1970,8 +1967,7 @@ static unsigned long free_unpacked(struct unpacked *n) n->index = NULL; if (n->data) { freed_mem += n->entry->size; - free(n->data); - n->data = NULL; + FREE_AND_NULL(n->data); } n->entry = NULL; n->depth = 0; @@ -2483,8 +2479,10 @@ static int git_pack_config(const char *k, const char *v, void *cb) die("invalid number of threads specified (%d)", delta_search_threads); #ifdef NO_PTHREADS - if (delta_search_threads != 1) + if (delta_search_threads != 1) { warning("no threads support, ignoring %s", k); + delta_search_threads = 0; + } #endif return 0; } diff --git a/builtin/patch-id.c b/builtin/patch-id.c index 81552e02e4..970d0d30b4 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result) { diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c index c026299e78..ac978ad401 100644 --- a/builtin/prune-packed.c +++ b/builtin/prune-packed.c @@ -10,7 +10,7 @@ static const char * const prune_packed_usage[] = { static struct progress *progress; -static int prune_subdir(int nr, const char *path, void *data) +static int prune_subdir(unsigned int nr, const char *path, void *data) { int *opts = data; display_progress(progress, nr + 1); diff --git a/builtin/prune.c b/builtin/prune.c index f0e2bff04c..c378690545 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -68,7 +68,7 @@ static int prune_cruft(const char *basename, const char *path, void *data) return 0; } -static int prune_subdir(int nr, const char *path, void *data) +static int prune_subdir(unsigned int nr, const char *path, void *data) { if (!show_only) rmdir(path); diff --git a/builtin/pull.c b/builtin/pull.c index 318c273eb3..9b86e519b1 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -6,6 +6,7 @@ * Fetch one or more remote refs and merge it/them into the current HEAD. */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "parse-options.h" #include "exec_cmd.h" @@ -15,6 +16,8 @@ #include "dir.h" #include "refs.h" #include "revision.h" +#include "submodule.h" +#include "submodule-config.h" #include "tempfile.h" #include "lockfile.h" #include "wt-status.h" @@ -77,6 +80,7 @@ static const char * const pull_usage[] = { /* Shared options */ static int opt_verbosity; static char *opt_progress; +static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; /* Options passed to git-merge or git-rebase */ static enum rebase_type opt_rebase = -1; @@ -101,7 +105,6 @@ static char *opt_upload_pack; static int opt_force; static char *opt_tags; static char *opt_prune; -static char *opt_recurse_submodules; static char *max_children; static int opt_dry_run; static char *opt_keep; @@ -116,6 +119,10 @@ static struct option pull_options[] = { OPT_PASSTHRU(0, "progress", &opt_progress, NULL, N_("force progress reporting"), PARSE_OPT_NOARG), + { OPTION_CALLBACK, 0, "recurse-submodules", + &recurse_submodules, N_("on-demand"), + N_("control for recursive fetching of submodules"), + PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules }, /* Options passed to git-merge or git-rebase */ OPT_GROUP(N_("Options related to merging")), @@ -187,10 +194,6 @@ static struct option pull_options[] = { OPT_PASSTHRU('p', "prune", &opt_prune, NULL, N_("prune remote-tracking branches no longer on remote"), PARSE_OPT_NOARG), - OPT_PASSTHRU(0, "recurse-submodules", &opt_recurse_submodules, - N_("on-demand"), - N_("control recursive fetching of submodules"), - PARSE_OPT_OPTARG), OPT_PASSTHRU('j', "jobs", &max_children, N_("n"), N_("number of submodules pulled in parallel"), PARSE_OPT_OPTARG), @@ -337,8 +340,7 @@ static void get_merge_heads(struct oid_array *merge_heads) struct strbuf sb = STRBUF_INIT; struct object_id oid; - if (!(fp = fopen(filename, "r"))) - die_errno(_("could not open '%s' for reading"), filename); + fp = xfopen(filename, "r"); while (strbuf_getline_lf(&sb, fp) != EOF) { if (get_oid_hex(sb.buf, &oid)) continue; /* invalid line: does not start with SHA1 */ @@ -484,8 +486,20 @@ static int run_fetch(const char *repo, const char **refspecs) argv_array_push(&args, opt_tags); if (opt_prune) argv_array_push(&args, opt_prune); - if (opt_recurse_submodules) - argv_array_push(&args, opt_recurse_submodules); + if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) + switch (recurse_submodules) { + case RECURSE_SUBMODULES_ON: + argv_array_push(&args, "--recurse-submodules=on"); + break; + case RECURSE_SUBMODULES_OFF: + argv_array_push(&args, "--recurse-submodules=no"); + break; + case RECURSE_SUBMODULES_ON_DEMAND: + argv_array_push(&args, "--recurse-submodules=on-demand"); + break; + default: + BUG("submodule recursion option not understood"); + } if (max_children) argv_array_push(&args, max_children); if (opt_dry_run) @@ -532,6 +546,30 @@ static int pull_into_void(const struct object_id *merge_head, return 0; } +static int rebase_submodules(void) +{ + struct child_process cp = CHILD_PROCESS_INIT; + + cp.git_cmd = 1; + cp.no_stdin = 1; + argv_array_pushl(&cp.args, "submodule", "update", + "--recursive", "--rebase", NULL); + + return run_command(&cp); +} + +static int update_submodules(void) +{ + struct child_process cp = CHILD_PROCESS_INIT; + + cp.git_cmd = 1; + cp.no_stdin = 1; + argv_array_pushl(&cp.args, "submodule", "update", + "--recursive", "--checkout", NULL); + + return run_command(&cp); +} + /** * Runs git-merge, returning its exit status. */ @@ -772,6 +810,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) struct oid_array merge_heads = OID_ARRAY_INIT; struct object_id orig_head, curr_head; struct object_id rebase_fork_point; + int autostash; if (!getenv("GIT_REFLOG_ACTION")) set_reflog_message(argc, argv); @@ -800,8 +839,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (!opt_rebase && opt_autostash != -1) die(_("--[no-]autostash option is only valid with --rebase.")); + autostash = config_autostash; if (opt_rebase) { - int autostash = config_autostash; if (opt_autostash != -1) autostash = opt_autostash; @@ -862,19 +901,36 @@ int cmd_pull(int argc, const char **argv, const char *prefix) die(_("Cannot rebase onto multiple branches.")); if (opt_rebase) { - struct commit_list *list = NULL; - struct commit *merge_head, *head; - - head = lookup_commit_reference(&orig_head); - commit_list_insert(head, &list); - merge_head = lookup_commit_reference(&merge_heads.oid[0]); - if (is_descendant_of(merge_head, list)) { - /* we can fast-forward this without invoking rebase */ - opt_ff = "--ff-only"; - return run_merge(); + int ret = 0; + if ((recurse_submodules == RECURSE_SUBMODULES_ON || + recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) && + submodule_touches_in_range(&rebase_fork_point, &curr_head)) + die(_("cannot rebase with locally recorded submodule modifications")); + if (!autostash) { + struct commit_list *list = NULL; + struct commit *merge_head, *head; + + head = lookup_commit_reference(&orig_head); + commit_list_insert(head, &list); + merge_head = lookup_commit_reference(&merge_heads.oid[0]); + if (is_descendant_of(merge_head, list)) { + /* we can fast-forward this without invoking rebase */ + opt_ff = "--ff-only"; + ret = run_merge(); + } } - return run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point); + ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point); + + if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON || + recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)) + ret = rebase_submodules(); + + return ret; } else { - return run_merge(); + int ret = run_merge(); + if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON || + recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)) + ret = update_submodules(); + return ret; } } diff --git a/builtin/push.c b/builtin/push.c index a597759d8f..03846e8379 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -2,6 +2,7 @@ * "git push" */ #include "cache.h" +#include "config.h" #include "refs.h" #include "run-command.h" #include "builtin.h" @@ -498,6 +499,10 @@ static int git_push_config(const char *k, const char *v, void *cb) const char *value; if (!git_config_get_value("push.recursesubmodules", &value)) recurse_submodules = parse_push_recurse_submodules_arg(k, value); + } else if (!strcmp(k, "submodule.recurse")) { + int val = git_config_bool(k, v) ? + RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF; + recurse_submodules = val; } return git_default_config(k, v, NULL); diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 78d3193659..d5f618d086 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -5,6 +5,7 @@ */ #include "cache.h" +#include "config.h" #include "lockfile.h" #include "object.h" #include "tree.h" @@ -21,7 +22,6 @@ static int nr_trees; static int read_empty; static struct tree *trees[MAX_UNPACK_TREES]; -static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int list_tree(struct object_id *oid) { @@ -99,21 +99,12 @@ static int debug_merge(const struct cache_entry * const *stages, return 0; } -static int option_parse_recurse_submodules(const struct option *opt, - const char *arg, int unset) +static int git_read_tree_config(const char *var, const char *value, void *cb) { - if (unset) { - recurse_submodules = RECURSE_SUBMODULES_OFF; - return 0; - } - if (arg) - recurse_submodules = - parse_update_recurse_submodules_arg(opt->long_name, - arg); - else - recurse_submodules = RECURSE_SUBMODULES_ON; + if (!strcmp(var, "submodule.recurse")) + return git_default_submodule_config(var, value, cb); - return 0; + return git_default_config(var, value, cb); } static struct lock_file lock_file; @@ -157,9 +148,9 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) N_("skip applying sparse checkout filter")), OPT_BOOL(0, "debug-unpack", &opts.debug_unpack, N_("debug unpack-trees")), - { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, + { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "checkout", "control recursive updating of submodules", - PARSE_OPT_OPTARG, option_parse_recurse_submodules }, + PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater }, OPT_END() }; @@ -168,18 +159,14 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) opts.src_index = &the_index; opts.dst_index = &the_index; - git_config(git_default_config, NULL); + git_config(git_read_tree_config, NULL); argc = parse_options(argc, argv, unused_prefix, read_tree_options, read_tree_usage, 0); - hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); + load_submodule_cache(); - if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) { - gitmodules_config(); - git_config(submodule_config, NULL); - set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON); - } + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); prefix_set = opts.prefix ? 1 : 0; if (1 < opts.merge + opts.reset + prefix_set) diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index ca1ebb2fa1..c82b4dce68 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "parse-options.h" #include "sequencer.h" diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index b1706a5731..14b6e09b42 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "lockfile.h" #include "pack.h" #include "refs.h" @@ -918,9 +919,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) */ static int head_has_history(void) { - unsigned char sha1[20]; + struct object_id oid; - return !get_sha1("HEAD", sha1); + return !get_oid("HEAD", &oid); } static const char *push_to_deploy(unsigned char *sha1, @@ -1137,7 +1138,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) } if (ref_transaction_delete(transaction, namespaced_name, - old_oid->hash, + old_oid ? old_oid->hash : NULL, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); @@ -1805,7 +1806,7 @@ static const char *unpack_with_sideband(struct shallow_info *si) static void prepare_shallow_update(struct command *commands, struct shallow_info *si) { - int i, j, k, bitmap_size = (si->ref->nr + 31) / 32; + int i, j, k, bitmap_size = DIV_ROUND_UP(si->ref->nr, 32); ALLOC_ARRAY(si->used_shallow, si->shallow->nr); assign_shallow_commits_to_refs(si, si->used_shallow, NULL); diff --git a/builtin/reflog.c b/builtin/reflog.c index 920c16dac0..e237d927a0 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "lockfile.h" #include "commit.h" #include "refs.h" @@ -485,7 +486,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c return; /* both given explicitly -- nothing to tweak */ for (ent = reflog_expire_cfg; ent; ent = ent->next) { - if (!wildmatch(ent->pattern, ref, 0, NULL)) { + if (!wildmatch(ent->pattern, ref, 0)) { if (!(slot & EXPIRE_TOTAL)) cb->expire_total = ent->expire_total; if (!(slot & EXPIRE_UNREACH)) diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index 11b48bfb41..bfb21ba7d2 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -3,6 +3,9 @@ #include "run-command.h" #include "pkt-line.h" +static const char usage_msg[] = + "git remote-ext <remote> <url>"; + /* * URL syntax: * 'command [arg1 [arg2 [...]]]' Invoke command with given arguments. @@ -193,7 +196,7 @@ static int command_loop(const char *child) int cmd_remote_ext(int argc, const char **argv, const char *prefix) { if (argc != 3) - die("Expected two arguments"); + usage(usage_msg); return command_loop(argv[2]); } diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c index 08d7121b6d..91dfe07e06 100644 --- a/builtin/remote-fd.c +++ b/builtin/remote-fd.c @@ -1,6 +1,9 @@ #include "builtin.h" #include "transport.h" +static const char usage_msg[] = + "git remote-fd <remote> <url>"; + /* * URL syntax: * 'fd::<inoutfd>[/<anything>]' Read/write socket pair @@ -57,7 +60,7 @@ int cmd_remote_fd(int argc, const char **argv, const char *prefix) char *end; if (argc != 3) - die("Expected two arguments"); + usage(usage_msg); input_fd = (int)strtoul(argv[2], &end, 10); diff --git a/builtin/remote.c b/builtin/remote.c index addf97ad29..6273c0c23c 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "parse-options.h" #include "transport.h" #include "remote.h" @@ -786,7 +787,7 @@ static int rm(int argc, const char **argv) strbuf_release(&buf); if (!result) - result = delete_refs(&branches, REF_NODEREF); + result = delete_refs("remote: remove", &branches, REF_NODEREF); string_list_clear(&branches, 0); if (skipped.nr) { @@ -1151,8 +1152,11 @@ static int show(int argc, const char **argv) url_nr = states.remote->url_nr; } for (i = 0; i < url_nr; i++) - /* TRANSLATORS: the colon ':' should align with - the one in " Fetch URL: %s" translation */ + /* + * TRANSLATORS: the colon ':' should align + * with the one in " Fetch URL: %s" + * translation. + */ printf_ln(_(" Push URL: %s"), url[i]); if (!i) printf_ln(_(" Push URL: %s"), _("(no URL)")); @@ -1301,7 +1305,7 @@ static int prune_remote(const char *remote, int dry_run) string_list_sort(&refs_to_prune); if (!dry_run) - result |= delete_refs(&refs_to_prune, 0); + result |= delete_refs("remote: prune", &refs_to_prune, 0); for_each_string_list_item(item, &states.stale) { const char *refname = item->util; diff --git a/builtin/repack.c b/builtin/repack.c index 38ba4ef825..f17a68a17d 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "dir.h" #include "parse-options.h" #include "run-command.h" diff --git a/builtin/replace.c b/builtin/replace.c index c921bc976f..f4a85a165b 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -9,6 +9,7 @@ */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "refs.h" #include "parse-options.h" @@ -40,7 +41,7 @@ static int show_reference(const char *refname, const struct object_id *oid, { struct show_data *data = cb_data; - if (!wildmatch(data->pattern, refname, 0, NULL)) { + if (!wildmatch(data->pattern, refname, 0)) { if (data->format == REPLACE_FORMAT_SHORT) printf("%s\n", refname); else if (data->format == REPLACE_FORMAT_MEDIUM) @@ -49,7 +50,7 @@ static int show_reference(const char *refname, const struct object_id *oid, struct object_id object; enum object_type obj_type, repl_type; - if (get_sha1(refname, object.hash)) + if (get_oid(refname, &object)) return error("Failed to resolve '%s' as a valid ref.", refname); obj_type = sha1_object_info(object.hash, NULL); @@ -364,7 +365,7 @@ static void check_one_mergetag(struct commit *commit, /* iterate over new parents */ for (i = 1; i < mergetag_data->argc; i++) { struct object_id oid; - if (get_sha1(mergetag_data->argv[i], oid.hash) < 0) + if (get_oid(mergetag_data->argv[i], &oid) < 0) die(_("Not a valid object name: '%s'"), mergetag_data->argv[i]); if (!oidcmp(&tag->tagged->oid, &oid)) return; /* found */ diff --git a/builtin/rerere.c b/builtin/rerere.c index 1bf72423bf..ffb66e2907 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "dir.h" #include "parse-options.h" #include "string-list.h" diff --git a/builtin/reset.c b/builtin/reset.c index 430602d102..046403ed68 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -8,6 +8,7 @@ * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano */ #include "builtin.h" +#include "config.h" #include "lockfile.h" #include "tag.h" #include "object.h" @@ -24,25 +25,6 @@ #include "submodule.h" #include "submodule-config.h" -static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; - -static int option_parse_recurse_submodules(const struct option *opt, - const char *arg, int unset) -{ - if (unset) { - recurse_submodules = RECURSE_SUBMODULES_OFF; - return 0; - } - if (arg) - recurse_submodules = - parse_update_recurse_submodules_arg(opt->long_name, - arg); - else - recurse_submodules = RECURSE_SUBMODULES_ON; - - return 0; -} - static const char * const git_reset_usage[] = { N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"), N_("git reset [-q] [<tree-ish>] [--] <paths>..."), @@ -237,8 +219,8 @@ static void parse_args(struct pathspec *pathspec, * has to be unambiguous. If there is a single argument, it * can not be a tree */ - else if ((!argv[1] && !get_sha1_committish(argv[0], unused.hash)) || - (argv[1] && !get_sha1_treeish(argv[0], unused.hash))) { + else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) || + (argv[1] && !get_oid_treeish(argv[0], &unused))) { /* * Ok, argv[0] looks like a commit/tree; it should not * be a filename. @@ -284,6 +266,14 @@ static int reset_refs(const char *rev, const struct object_id *oid) return update_ref_status; } +static int git_reset_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "submodule.recurse")) + return git_default_submodule_config(var, value, cb); + + return git_default_config(var, value, cb); +} + int cmd_reset(int argc, const char **argv, const char *prefix) { int reset_type = NONE, update_ref_status = 0, quiet = 0; @@ -303,34 +293,30 @@ int cmd_reset(int argc, const char **argv, const char *prefix) N_("reset HEAD, index and working tree"), MERGE), OPT_SET_INT(0, "keep", &reset_type, N_("reset HEAD but keep local changes"), KEEP), - { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, + { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "reset", "control recursive updating of submodules", - PARSE_OPT_OPTARG, option_parse_recurse_submodules }, + PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater }, OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")), OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that removed paths will be added later")), OPT_END() }; - git_config(git_default_config, NULL); + git_config(git_reset_config, NULL); argc = parse_options(argc, argv, prefix, options, git_reset_usage, PARSE_OPT_KEEP_DASHDASH); parse_args(&pathspec, argv, prefix, patch_mode, &rev); - if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) { - gitmodules_config(); - git_config(submodule_config, NULL); - set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON); - } + load_submodule_cache(); - unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash); + unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid); if (unborn) { /* reset on unborn branch: treat as reset to empty tree */ hashcpy(oid.hash, EMPTY_TREE_SHA1_BIN); } else if (!pathspec.nr) { struct commit *commit; - if (get_sha1_committish(rev, oid.hash)) + if (get_oid_committish(rev, &oid)) die(_("Failed to resolve '%s' as a valid revision."), rev); commit = lookup_commit_reference(&oid); if (!commit) @@ -338,7 +324,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) oidcpy(&oid, &commit->object.oid); } else { struct tree *tree; - if (get_sha1_treeish(rev, oid.hash)) + if (get_oid_treeish(rev, &oid)) die(_("Failed to resolve '%s' as a valid tree."), rev); tree = parse_tree_indirect(&oid); if (!tree) diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 718c6059c9..fee10d8567 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -121,6 +122,7 @@ static void show_commit(struct commit *commit, void *data) ctx.date_mode_explicit = revs->date_mode_explicit; ctx.fmt = revs->commit_format; ctx.output_encoding = get_log_output_encoding(); + ctx.color = revs->diffopt.use_color; pretty_print_commit(&ctx, commit, &buf); if (buf.len) { if (revs->commit_format != CMIT_FMT_ONELINE) @@ -277,6 +279,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) int use_bitmap_index = 0; const char *show_progress = NULL; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage(rev_list_usage); + git_config(git_default_config, NULL); init_revisions(&revs, prefix); revs.abbrev = DEFAULT_ABBREV; diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index efdc14473b..2bd28d3c08 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "commit.h" #include "refs.h" #include "quote.h" @@ -273,7 +274,7 @@ static int try_difference(const char *arg) return 0; } - if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) { + if (!get_oid_committish(this, &oid) && !get_oid_committish(next, &end)) { show_rev(NORMAL, &end, next); show_rev(symmetric ? NORMAL : REVERSED, &oid, this); if (symmetric) { @@ -327,7 +328,7 @@ static int try_parent_shorthands(const char *arg) return 0; *dotdot = 0; - if (get_sha1_committish(arg, oid.hash)) { + if (get_oid_committish(arg, &oid)) { *dotdot = '^'; return 0; } @@ -701,7 +702,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) } if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) { quiet = 1; - flags |= GET_SHA1_QUIETLY; + flags |= GET_OID_QUIETLY; continue; } if (opt_with_value(arg, "--short", &arg)) { @@ -910,7 +911,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) name++; type = REVERSED; } - if (!get_sha1_with_context(name, flags, oid.hash, &unused)) { + if (!get_oid_with_context(name, flags, &oid, &unused)) { if (verify) revs_count++; else diff --git a/builtin/revert.c b/builtin/revert.c index 345d9586a7..16028b9ea8 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "builtin.h" #include "parse-options.h" #include "diff.h" diff --git a/builtin/rm.c b/builtin/rm.c index 7c323d0123..52826d1379 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds 2006 */ #include "builtin.h" +#include "config.h" #include "lockfile.h" #include "dir.h" #include "cache-tree.h" @@ -129,7 +130,7 @@ static int check_local_mod(struct object_id *head, int index_only) ce = active_cache[pos]; if (lstat(ce->name, &st) < 0) { - if (errno != ENOENT && errno != ENOTDIR) + if (!is_missing_file_error(errno)) warning_errno(_("failed to stat '%s'"), ce->name); /* It already vanished from the working tree */ continue; diff --git a/builtin/send-pack.c b/builtin/send-pack.c index b8e2e74fe0..633e0c3cdd 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "commit.h" #include "refs.h" #include "pkt-line.h" diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 7cff1839fc..43c4799ea9 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "commit.h" #include "diff.h" #include "string-list.h" diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 4a6cc6f490..84547d6fba 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -1,10 +1,12 @@ #include "cache.h" +#include "config.h" #include "commit.h" #include "refs.h" #include "builtin.h" #include "color.h" #include "argv-array.h" #include "parse-options.h" +#include "dir.h" static const char* show_branch_usage[] = { N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n" @@ -391,7 +393,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid, /* If both heads/foo and tags/foo exists, get_sha1 would * get confused. */ - if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid)) + if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid)) ofs = 5; return append_ref(refname + ofs, oid, 0); } @@ -406,7 +408,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid, /* If both heads/foo and tags/foo exists, get_sha1 would * get confused. */ - if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid)) + if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid)) ofs = 5; return append_ref(refname + ofs, oid, 0); } @@ -421,14 +423,6 @@ static int append_tag_ref(const char *refname, const struct object_id *oid, static const char *match_ref_pattern = NULL; static int match_ref_slash = 0; -static int count_slash(const char *s) -{ - int cnt = 0; - while (*s) - if (*s++ == '/') - cnt++; - return cnt; -} static int append_matching_ref(const char *refname, const struct object_id *oid, int flag, void *cb_data) @@ -438,13 +432,13 @@ static int append_matching_ref(const char *refname, const struct object_id *oid, * refs/tags/v0.99.9a and friends. */ const char *tail; - int slash = count_slash(refname); + int slash = count_slashes(refname); for (tail = refname; *tail && match_ref_slash < slash; ) if (*tail++ == '/') slash--; if (!*tail) return 0; - if (wildmatch(match_ref_pattern, tail, 0, NULL)) + if (wildmatch(match_ref_pattern, tail, 0)) return 0; if (starts_with(refname, "refs/heads/")) return append_head_ref(refname, oid, flag, cb_data); @@ -520,7 +514,7 @@ static int show_independent(struct commit **rev, static void append_one_rev(const char *av) { struct object_id revkey; - if (!get_sha1(av, revkey.hash)) { + if (!get_oid(av, &revkey)) { append_ref(av, &revkey, 0); return; } @@ -529,7 +523,7 @@ static void append_one_rev(const char *av) int saved_matches = ref_name_cnt; match_ref_pattern = av; - match_ref_slash = count_slash(av); + match_ref_slash = count_slashes(av); for_each_ref(append_matching_ref, NULL); if (saved_matches == ref_name_cnt && ref_name_cnt < MAX_REVS) @@ -560,7 +554,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb) return 0; } - return git_color_default_config(var, value, cb); + return git_default_config(var, value, cb); } static int omit_in_dense(struct commit *commit, struct commit **rev, int n) @@ -814,7 +808,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) die(Q_("cannot handle more than %d rev.", "cannot handle more than %d revs.", MAX_REVS), MAX_REVS); - if (get_sha1(ref_name[num_rev], revkey.hash)) + if (get_oid(ref_name[num_rev], &revkey)) die(_("'%s' is not a valid ref."), ref_name[num_rev]); commit = lookup_commit_reference(&revkey); if (!commit) diff --git a/builtin/stripspace.c b/builtin/stripspace.c index 1e62a008cb..bdf0328869 100644 --- a/builtin/stripspace.c +++ b/builtin/stripspace.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "parse-options.h" #include "strbuf.h" diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 8cc648d85b..af871f14e7 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1,10 +1,11 @@ #include "builtin.h" +#include "repository.h" #include "cache.h" +#include "config.h" #include "parse-options.h" #include "quote.h" #include "pathspec.h" #include "dir.h" -#include "utf8.h" #include "submodule.h" #include "submodule-config.h" #include "string-list.h" @@ -279,7 +280,7 @@ static void module_list_active(struct module_list *list) for (i = 0; i < list->nr; i++) { const struct cache_entry *ce = list->entries[i]; - if (!is_submodule_initialized(ce->name)) + if (!is_submodule_active(the_repository, ce->name)) continue; ALLOC_GROW(active_modules.entries, @@ -325,7 +326,7 @@ static int module_list(int argc, const char **argv, const char *prefix) printf("%06o %s %d\t", ce->ce_mode, oid_to_hex(&ce->oid), ce_stage(ce)); - utf8_fprintf(stdout, "%s\n", ce->name); + fprintf(stdout, "%s\n", ce->name); } return 0; } @@ -349,7 +350,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet) } else displaypath = xstrdup(path); - sub = submodule_from_path(null_sha1, path); + sub = submodule_from_path(&null_oid, path); if (!sub) die(_("No url found for submodule path '%s' in .gitmodules"), @@ -361,7 +362,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet) * * Set active flag for the submodule being initialized */ - if (!is_submodule_initialized(path)) { + if (!is_submodule_active(the_repository, path)) { strbuf_reset(&sb); strbuf_addf(&sb, "submodule.%s.active", sub->name); git_config_set_gently(sb.buf, "true"); @@ -475,7 +476,7 @@ static int module_name(int argc, const char **argv, const char *prefix) usage(_("git submodule--helper name <path>")); gitmodules_config(); - sub = submodule_from_path(null_sha1, argv[1]); + sub = submodule_from_path(&null_oid, argv[1]); if (!sub) die(_("no submodule mapping found in .gitmodules for path '%s'"), @@ -794,7 +795,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, goto cleanup; } - sub = submodule_from_path(null_sha1, ce->name); + sub = submodule_from_path(&null_oid, ce->name); if (suc->recursive_prefix) displaypath = relative_path(suc->recursive_prefix, @@ -816,7 +817,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, } /* Check if the submodule has been initialized. */ - if (!is_submodule_initialized(ce->name)) { + if (!is_submodule_active(the_repository, ce->name)) { next_submodule_warn_missing(suc, out, displaypath); goto cleanup; } @@ -1037,7 +1038,7 @@ static int update_clone(int argc, const char **argv, const char *prefix) return 1; for_each_string_list_item(item, &suc.projectlines) - utf8_fprintf(stdout, "%s", item->string); + fprintf(stdout, "%s", item->string); return 0; } @@ -1059,7 +1060,7 @@ static const char *remote_submodule_branch(const char *path) gitmodules_config(); git_config(submodule_config, NULL); - sub = submodule_from_path(null_sha1, path); + sub = submodule_from_path(&null_oid, path); if (!sub) return NULL; @@ -1192,7 +1193,7 @@ static int is_active(int argc, const char **argv, const char *prefix) gitmodules_config(); - return !is_submodule_initialized(argv[1]); + return !is_submodule_active(the_repository, argv[1]); } #define SUPPORT_SUPER_PREFIX (1<<0) @@ -1221,9 +1222,8 @@ static struct cmd_struct commands[] = { int cmd_submodule__helper(int argc, const char **argv, const char *prefix) { int i; - if (argc < 2) - die(_("submodule--helper subcommand must be " - "called with a subcommand")); + if (argc < 2 || !strcmp(argv[1], "-h")) + usage("git submodule--helper <command>"); for (i = 0; i < ARRAY_SIZE(commands); i++) { if (!strcmp(argv[1], commands[i].cmd)) { diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c index 70addef158..df75cb9d4a 100644 --- a/builtin/symbolic-ref.c +++ b/builtin/symbolic-ref.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "config.h" #include "cache.h" #include "refs.h" #include "parse-options.h" diff --git a/builtin/tag.c b/builtin/tag.c index 1f74a56db7..e8a30e6110 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "refs.h" #include "tag.h" @@ -31,7 +32,8 @@ static const char * const git_tag_usage[] = { static unsigned int colopts; static int force_sign_annotate; -static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, const char *format) +static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, + struct ref_format *format) { struct ref_array array; char *to_free = NULL; @@ -42,23 +44,24 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con if (filter->lines == -1) filter->lines = 0; - if (!format) { + if (!format->format) { if (filter->lines) { to_free = xstrfmt("%s %%(contents:lines=%d)", "%(align:15)%(refname:lstrip=2)%(end)", filter->lines); - format = to_free; + format->format = to_free; } else - format = "%(refname:lstrip=2)"; + format->format = "%(refname:lstrip=2)"; } - verify_ref_format(format); + if (verify_ref_format(format)) + die(_("unable to parse format string")); filter->with_commit_tag_algo = 1; filter_refs(&array, filter, FILTER_REFS_TAGS); ref_array_sort(sorting, &array); for (i = 0; i < array.nr; i++) - show_ref_array_item(array.items[i], format, 0); + show_ref_array_item(array.items[i], format); ref_array_clear(&array); free(to_free); @@ -104,17 +107,17 @@ static int verify_tag(const char *name, const char *ref, const struct object_id *oid, const void *cb_data) { int flags; - const char *fmt_pretty = cb_data; + const struct ref_format *format = cb_data; flags = GPG_VERIFY_VERBOSE; - if (fmt_pretty) + if (format->format) flags = GPG_VERIFY_OMIT_STATUS; - if (gpg_verify_tag(oid->hash, name, flags)) + if (gpg_verify_tag(oid, name, flags)) return -1; - if (fmt_pretty) - pretty_print_ref(name, oid->hash, fmt_pretty); + if (format->format) + pretty_print_ref(name, oid->hash, format); return 0; } @@ -133,30 +136,6 @@ static const char tag_template_nocleanup[] = "Lines starting with '%c' will be kept; you may remove them" " yourself if you want to.\n"); -/* Parse arg given and add it the ref_sorting array */ -static int parse_sorting_string(const char *arg, struct ref_sorting **sorting_tail) -{ - struct ref_sorting *s; - int len; - - s = xcalloc(1, sizeof(*s)); - s->next = *sorting_tail; - *sorting_tail = s; - - if (*arg == '-') { - s->reverse = 1; - arg++; - } - if (skip_prefix(arg, "version:", &arg) || - skip_prefix(arg, "v:", &arg)) - s->version = 1; - - len = strlen(arg); - s->atom = parse_ref_filter_atom(arg, arg+len); - - return 0; -} - static int git_tag_config(const char *var, const char *value, void *cb) { int status; @@ -165,7 +144,7 @@ static int git_tag_config(const char *var, const char *value, void *cb) if (!strcmp(var, "tag.sort")) { if (!value) return config_error_nonbool(var); - parse_sorting_string(value, sorting_tail); + parse_ref_sorting(sorting_tail, value); return 0; } @@ -391,7 +370,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct strbuf err = STRBUF_INIT; struct ref_filter filter; static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; - const char *format = NULL; + struct ref_format format = REF_FORMAT_INIT; int icase = 0; struct option options[] = { OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'), @@ -430,7 +409,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT, parse_opt_object_name, (intptr_t) "HEAD" }, - OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), + OPT_STRING( 0 , "format", &format.format, N_("format"), + N_("format to use for the output")), OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), OPT_END() }; @@ -482,7 +462,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) run_column_filter(colopts, &copts); } filter.name_patterns = argv; - ret = list_tags(&filter, sorting, format); + ret = list_tags(&filter, sorting, &format); if (column_active(colopts)) stop_column_filter(); return ret; @@ -500,9 +480,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (cmdmode == 'd') return for_each_tag_name(argv, delete_tag, NULL); if (cmdmode == 'v') { - if (format) - verify_ref_format(format); - return for_each_tag_name(argv, verify_tag, format); + if (format.format && verify_ref_format(&format)) + usage_with_options(git_tag_usage, options); + return for_each_tag_name(argv, verify_tag, &format); } if (msg.given || msgfile) { diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c index 6fc6bcdf7f..281ca1db6c 100644 --- a/builtin/unpack-file.c +++ b/builtin/unpack-file.c @@ -1,6 +1,7 @@ #include "builtin.h" +#include "config.h" -static char *create_temp_file(unsigned char *sha1) +static char *create_temp_file(struct object_id *oid) { static char path[50]; void *buf; @@ -8,9 +9,9 @@ static char *create_temp_file(unsigned char *sha1) unsigned long size; int fd; - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); if (!buf || type != OBJ_BLOB) - die("unable to read blob object %s", sha1_to_hex(sha1)); + die("unable to read blob object %s", oid_to_hex(oid)); xsnprintf(path, sizeof(path), ".merge_file_XXXXXX"); fd = xmkstemp(path); @@ -22,15 +23,15 @@ static char *create_temp_file(unsigned char *sha1) int cmd_unpack_file(int argc, const char **argv, const char *prefix) { - unsigned char sha1[20]; + struct object_id oid; if (argc != 2 || !strcmp(argv[1], "-h")) usage("git unpack-file <sha1>"); - if (get_sha1(argv[1], sha1)) + if (get_oid(argv[1], &oid)) die("Not a valid object name %s", argv[1]); git_config(git_default_config, NULL); - puts(create_temp_file(sha1)); + puts(create_temp_file(&oid)); return 0; } diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 8bc9997767..689a29fac1 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "object.h" #include "delta.h" #include "pack.h" @@ -112,8 +113,7 @@ static void *get_data(unsigned long size) break; if (ret != Z_OK) { error("inflate returned %d", ret); - free(buf); - buf = NULL; + FREE_AND_NULL(buf); if (!recover) exit(1); has_errors = 1; diff --git a/builtin/update-index.c b/builtin/update-index.c index ebfc09faa0..56721cf03d 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "config.h" #include "lockfile.h" #include "quote.h" #include "cache-tree.h" @@ -257,7 +258,7 @@ static int remove_one_path(const char *path) */ static int process_lstat_error(const char *path, int err) { - if (err == ENOENT || err == ENOTDIR) + if (is_missing_file_error(err)) return remove_one_path(path); return error("lstat(\"%s\"): %s", path, strerror(err)); } diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 0b2ecf41ae..6b90c5dead 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "refs.h" #include "builtin.h" #include "parse-options.h" @@ -93,10 +94,10 @@ static char *parse_refname(struct strbuf *input, const char **next) * provided but cannot be converted to a SHA-1, die. flags can * include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY. */ -static int parse_next_sha1(struct strbuf *input, const char **next, - unsigned char *sha1, - const char *command, const char *refname, - int flags) +static int parse_next_oid(struct strbuf *input, const char **next, + struct object_id *oid, + const char *command, const char *refname, + int flags) { struct strbuf arg = STRBUF_INIT; int ret = 0; @@ -114,11 +115,11 @@ static int parse_next_sha1(struct strbuf *input, const char **next, (*next)++; *next = parse_arg(*next, &arg); if (arg.len) { - if (get_sha1(arg.buf, sha1)) + if (get_oid(arg.buf, oid)) goto invalid; } else { /* Without -z, an empty value means all zeros: */ - hashclr(sha1); + oidclr(oid); } } else { /* With -z, read the next NUL-terminated line */ @@ -132,13 +133,13 @@ static int parse_next_sha1(struct strbuf *input, const char **next, *next += arg.len; if (arg.len) { - if (get_sha1(arg.buf, sha1)) + if (get_oid(arg.buf, oid)) goto invalid; } else if (flags & PARSE_SHA1_ALLOW_EMPTY) { /* With -z, treat an empty value as all zeros: */ warning("%s %s: missing <newvalue>, treating as zero", command, refname); - hashclr(sha1); + oidclr(oid); } else { /* * With -z, an empty non-required value means @@ -181,26 +182,25 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, { struct strbuf err = STRBUF_INIT; char *refname; - unsigned char new_sha1[20]; - unsigned char old_sha1[20]; + struct object_id new_oid, old_oid; int have_old; refname = parse_refname(input, &next); if (!refname) die("update: missing <ref>"); - if (parse_next_sha1(input, &next, new_sha1, "update", refname, - PARSE_SHA1_ALLOW_EMPTY)) + if (parse_next_oid(input, &next, &new_oid, "update", refname, + PARSE_SHA1_ALLOW_EMPTY)) die("update %s: missing <newvalue>", refname); - have_old = !parse_next_sha1(input, &next, old_sha1, "update", refname, - PARSE_SHA1_OLD); + have_old = !parse_next_oid(input, &next, &old_oid, "update", refname, + PARSE_SHA1_OLD); if (*next != line_termination) die("update %s: extra input: %s", refname, next); if (ref_transaction_update(transaction, refname, - new_sha1, have_old ? old_sha1 : NULL, + new_oid.hash, have_old ? old_oid.hash : NULL, update_flags | create_reflog_flag, msg, &err)) die("%s", err.buf); @@ -217,22 +217,22 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, { struct strbuf err = STRBUF_INIT; char *refname; - unsigned char new_sha1[20]; + struct object_id new_oid; refname = parse_refname(input, &next); if (!refname) die("create: missing <ref>"); - if (parse_next_sha1(input, &next, new_sha1, "create", refname, 0)) + if (parse_next_oid(input, &next, &new_oid, "create", refname, 0)) die("create %s: missing <newvalue>", refname); - if (is_null_sha1(new_sha1)) + if (is_null_oid(&new_oid)) die("create %s: zero <newvalue>", refname); if (*next != line_termination) die("create %s: extra input: %s", refname, next); - if (ref_transaction_create(transaction, refname, new_sha1, + if (ref_transaction_create(transaction, refname, new_oid.hash, update_flags | create_reflog_flag, msg, &err)) die("%s", err.buf); @@ -249,18 +249,18 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, { struct strbuf err = STRBUF_INIT; char *refname; - unsigned char old_sha1[20]; + struct object_id old_oid; int have_old; refname = parse_refname(input, &next); if (!refname) die("delete: missing <ref>"); - if (parse_next_sha1(input, &next, old_sha1, "delete", refname, - PARSE_SHA1_OLD)) { + if (parse_next_oid(input, &next, &old_oid, "delete", refname, + PARSE_SHA1_OLD)) { have_old = 0; } else { - if (is_null_sha1(old_sha1)) + if (is_null_oid(&old_oid)) die("delete %s: zero <oldvalue>", refname); have_old = 1; } @@ -269,7 +269,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, die("delete %s: extra input: %s", refname, next); if (ref_transaction_delete(transaction, refname, - have_old ? old_sha1 : NULL, + have_old ? old_oid.hash : NULL, update_flags, msg, &err)) die("%s", err.buf); @@ -285,20 +285,20 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, { struct strbuf err = STRBUF_INIT; char *refname; - unsigned char old_sha1[20]; + struct object_id old_oid; refname = parse_refname(input, &next); if (!refname) die("verify: missing <ref>"); - if (parse_next_sha1(input, &next, old_sha1, "verify", refname, - PARSE_SHA1_OLD)) - hashclr(old_sha1); + if (parse_next_oid(input, &next, &old_oid, "verify", refname, + PARSE_SHA1_OLD)) + oidclr(&old_oid); if (*next != line_termination) die("verify %s: extra input: %s", refname, next); - if (ref_transaction_verify(transaction, refname, old_sha1, + if (ref_transaction_verify(transaction, refname, old_oid.hash, update_flags, &err)) die("%s", err.buf); @@ -354,7 +354,7 @@ static void update_refs_stdin(struct ref_transaction *transaction) int cmd_update_ref(int argc, const char **argv, const char *prefix) { const char *refname, *oldval; - unsigned char sha1[20], oldsha1[20]; + struct object_id oid, oldoid; int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0; unsigned int flags = 0; int create_reflog = 0; @@ -411,7 +411,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) refname = argv[0]; value = argv[1]; oldval = argv[2]; - if (get_sha1(value, sha1)) + if (get_oid(value, &oid)) die("%s: not a valid SHA1", value); } @@ -421,8 +421,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) * The empty string implies that the reference * must not already exist: */ - hashclr(oldsha1); - else if (get_sha1(oldval, oldsha1)) + oidclr(&oldoid); + else if (get_oid(oldval, &oldoid)) die("%s: not a valid old SHA1", oldval); } @@ -434,10 +434,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) * NULL_SHA1 as "don't care" here: */ return delete_ref(msg, refname, - (oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL, + (oldval && !is_null_oid(&oldoid)) ? oldoid.hash : NULL, flags); else - return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL, + return update_ref(msg, refname, oid.hash, oldval ? oldoid.hash : NULL, flags | create_reflog_flag, UPDATE_REFS_DIE_ON_ERR); } diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c index 6c8cc3edc1..873070e517 100644 --- a/builtin/update-server-info.c +++ b/builtin/update-server-info.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "builtin.h" #include "parse-options.h" diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c index cde06977b7..84532ae9a9 100644 --- a/builtin/upload-archive.c +++ b/builtin/upload-archive.c @@ -22,7 +22,7 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix) struct argv_array sent_argv = ARGV_ARRAY_INIT; const char *arg_cmd = "argument "; - if (argc != 2) + if (argc != 2 || !strcmp(argv[1], "-h")) usage(upload_archive_usage); if (!enter_repo(argv[1], 0)) @@ -76,6 +76,9 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix) { struct child_process writer = { argv }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage(upload_archive_usage); + /* * Set up sideband subprocess. * diff --git a/builtin/var.c b/builtin/var.c index aedbb53a2d..6c6f46b4ae 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "builtin.h" +#include "config.h" static const char var_usage[] = "git var (-l | <variable>)"; diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c index 05b734e6d1..ba38ac9b15 100644 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@ -6,6 +6,7 @@ * Based on git-verify-tag */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "commit.h" #include "run-command.h" diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c index c94e156932..c2a1a5c504 100644 --- a/builtin/verify-pack.c +++ b/builtin/verify-pack.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "config.h" #include "run-command.h" #include "parse-options.h" diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c index 5199553d91..ad7b79fa5c 100644 --- a/builtin/verify-tag.c +++ b/builtin/verify-tag.c @@ -6,6 +6,7 @@ * Based on git-verify-tag.sh */ #include "cache.h" +#include "config.h" #include "builtin.h" #include "tag.h" #include "run-command.h" @@ -31,11 +32,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) { int i = 1, verbose = 0, had_error = 0; unsigned flags = 0; - char *fmt_pretty = NULL; + struct ref_format format = REF_FORMAT_INIT; const struct option verify_tag_options[] = { OPT__VERBOSE(&verbose, N_("print tag contents")), OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW), - OPT_STRING( 0 , "format", &fmt_pretty, N_("format"), N_("format to use for the output")), + OPT_STRING(0, "format", &format.format, N_("format"), N_("format to use for the output")), OPT_END() }; @@ -49,26 +50,29 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) if (verbose) flags |= GPG_VERIFY_VERBOSE; - if (fmt_pretty) { - verify_ref_format(fmt_pretty); + if (format.format) { + if (verify_ref_format(&format)) + usage_with_options(verify_tag_usage, + verify_tag_options); flags |= GPG_VERIFY_OMIT_STATUS; } while (i < argc) { - unsigned char sha1[20]; + struct object_id oid; const char *name = argv[i++]; - if (get_sha1(name, sha1)) { + + if (get_oid(name, &oid)) { had_error = !!error("tag '%s' not found.", name); continue; } - if (gpg_verify_tag(sha1, name, flags)) { + if (gpg_verify_tag(&oid, name, flags)) { had_error = 1; continue; } - if (fmt_pretty) - pretty_print_ref(name, sha1, fmt_pretty); + if (format.format) + pretty_print_ref(name, oid.hash, &format); } return had_error; } diff --git a/builtin/worktree.c b/builtin/worktree.c index 793306ea51..c98e2ce5f5 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include "builtin.h" #include "dir.h" #include "parse-options.h" @@ -299,10 +300,8 @@ static int add_worktree(const char *path, const char *refname, } is_junk = 0; - free(junk_work_tree); - free(junk_git_dir); - junk_work_tree = NULL; - junk_git_dir = NULL; + FREE_AND_NULL(junk_work_tree); + FREE_AND_NULL(junk_git_dir); done: if (ret || !opts->keep_locked) { diff --git a/builtin/write-tree.c b/builtin/write-tree.c index 084c0df783..bd0a78aa3c 100644 --- a/builtin/write-tree.c +++ b/builtin/write-tree.c @@ -5,6 +5,7 @@ */ #include "builtin.h" #include "cache.h" +#include "config.h" #include "tree.h" #include "cache-tree.h" #include "parse-options.h" |