diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/branch.c | 75 | ||||
-rw-r--r-- | builtin/checkout.c | 13 | ||||
-rw-r--r-- | builtin/commit.c | 20 | ||||
-rw-r--r-- | builtin/describe.c | 29 | ||||
-rw-r--r-- | builtin/diff-index.c | 1 | ||||
-rw-r--r-- | builtin/diff.c | 3 | ||||
-rw-r--r-- | builtin/fast-export.c | 49 | ||||
-rw-r--r-- | builtin/for-each-ref.c | 1 | ||||
-rw-r--r-- | builtin/fsck.c | 7 | ||||
-rw-r--r-- | builtin/get-tar-commit-id.c | 6 | ||||
-rw-r--r-- | builtin/name-rev.c | 1 | ||||
-rw-r--r-- | builtin/pack-objects.c | 4 | ||||
-rw-r--r-- | builtin/rebase--helper.c | 29 | ||||
-rw-r--r-- | builtin/receive-pack.c | 3 | ||||
-rw-r--r-- | builtin/reflog.c | 6 | ||||
-rw-r--r-- | builtin/rev-parse.c | 18 | ||||
-rw-r--r-- | builtin/tag.c | 10 | ||||
-rw-r--r-- | builtin/worktree.c | 24 |
18 files changed, 214 insertions, 85 deletions
diff --git a/builtin/branch.c b/builtin/branch.c index 355f9ef5da..b67593288c 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -28,6 +28,7 @@ static const char * const builtin_branch_usage[] = { N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"), N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."), N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"), + N_("git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"), N_("git branch [<options>] [-r | -a] [--points-at]"), N_("git branch [<options>] [-r | -a] [--format]"), NULL @@ -216,7 +217,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, if (!head_rev) die(_("Couldn't look up commit object for HEAD")); } - for (i = 0; i < argc; i++, strbuf_release(&bname)) { + for (i = 0; i < argc; i++, strbuf_reset(&bname)) { char *target = NULL; int flags = 0; @@ -281,8 +282,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, } free(name); + strbuf_release(&bname); - return(ret); + return ret; } static int calc_maxwidth(struct ref_array *refs, int remote_bonus) @@ -352,7 +354,7 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r strbuf_addf(&obname, "%%(objectname:short=%d)", filter->abbrev); strbuf_addf(&local, "%%(align:%d,left)%%(refname:lstrip=2)%%(end)", maxwidth); - strbuf_addf(&local, "%s", branch_get_color(BRANCH_COLOR_RESET)); + strbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET)); strbuf_addf(&local, " %s ", obname.buf); if (filter->verbose > 1) @@ -456,15 +458,19 @@ static void reject_rebase_or_bisect_branch(const char *target) free_worktrees(worktrees); } -static void rename_branch(const char *oldname, const char *newname, int force) +static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force) { struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; int recovery = 0; int clobber_head_ok; - if (!oldname) - die(_("cannot rename the current branch while not on any.")); + if (!oldname) { + if (copy) + die(_("cannot copy the current branch while not on any.")); + else + die(_("cannot rename the current branch while not on any.")); + } if (strbuf_check_branch_ref(&oldref, oldname)) { /* @@ -487,16 +493,29 @@ static void rename_branch(const char *oldname, const char *newname, int force) reject_rebase_or_bisect_branch(oldref.buf); - strbuf_addf(&logmsg, "Branch: renamed %s to %s", - oldref.buf, newref.buf); + if (copy) + strbuf_addf(&logmsg, "Branch: copied %s to %s", + oldref.buf, newref.buf); + else + strbuf_addf(&logmsg, "Branch: renamed %s to %s", + oldref.buf, newref.buf); - if (rename_ref(oldref.buf, newref.buf, logmsg.buf)) + if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch rename failed")); + if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf)) + die(_("Branch copy failed")); - if (recovery) - warning(_("Renamed a misnamed branch '%s' away"), oldref.buf + 11); + if (recovery) { + if (copy) + warning(_("Copied a misnamed branch '%s' away"), + oldref.buf + 11); + else + warning(_("Renamed a misnamed branch '%s' away"), + oldref.buf + 11); + } - if (replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf)) + if (!copy && + replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch renamed to %s, but HEAD is not updated!"), newname); strbuf_release(&logmsg); @@ -505,8 +524,10 @@ static void rename_branch(const char *oldname, const char *newname, int force) strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", newref.buf + 11); strbuf_release(&newref); - if (git_config_rename_section(oldsection.buf, newsection.buf) < 0) + if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0) die(_("Branch is renamed, but update of config-file failed")); + if (copy && strcmp(oldname, newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0) + die(_("Branch is copied, but update of config-file failed")); strbuf_release(&oldsection); strbuf_release(&newsection); } @@ -544,7 +565,7 @@ static int edit_branch_description(const char *branch_name) int cmd_branch(int argc, const char **argv, const char *prefix) { - int delete = 0, rename = 0, force = 0, list = 0; + int delete = 0, rename = 0, copy = 0, force = 0, list = 0; int reflog = 0, edit_description = 0; int quiet = 0, unset_upstream = 0; const char *new_upstream = NULL; @@ -581,6 +602,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2), OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1), OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2), + OPT_BIT('c', "copy", ©, N_("copy a branch and its reflog"), 1), + OPT_BIT('C', NULL, ©, N_("copy a branch, even if target exists"), 2), OPT_BOOL(0, "list", &list, N_("list branch names")), OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")), OPT_BOOL(0, "edit-description", &edit_description, @@ -624,14 +647,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, 0); - if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0) + if (!delete && !rename && !copy && !edit_description && !new_upstream && !unset_upstream && argc == 0) list = 1; if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr || filter.no_commit) list = 1; - if (!!delete + !!rename + !!new_upstream + + if (!!delete + !!rename + !!copy + !!new_upstream + list + unset_upstream > 1) usage_with_options(builtin_branch_usage, options); @@ -649,6 +672,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (force) { delete *= 2; rename *= 2; + copy *= 2; } if (delete) { @@ -703,20 +727,29 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (edit_branch_description(branch_name)) return 1; + } else if (copy) { + if (!argc) + die(_("branch name required")); + else if (argc == 1) + copy_or_rename_branch(head, argv[0], 1, copy > 1); + else if (argc == 2) + copy_or_rename_branch(argv[0], argv[1], 1, copy > 1); + else + die(_("too many branches for a copy operation")); } else if (rename) { if (!argc) die(_("branch name required")); else if (argc == 1) - rename_branch(head, argv[0], rename > 1); + copy_or_rename_branch(head, argv[0], 0, rename > 1); else if (argc == 2) - rename_branch(argv[0], argv[1], rename > 1); + copy_or_rename_branch(argv[0], argv[1], 0, rename > 1); else - die(_("too many branches for a rename operation")); + die(_("too many arguments for a rename operation")); } else if (new_upstream) { struct branch *branch = branch_get(argv[0]); if (argc > 1) - die(_("too many branches to set new upstream")); + die(_("too many arguments to set new upstream")); if (!branch) { if (!argc || !strcmp(argv[0], "HEAD")) @@ -739,7 +772,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) struct strbuf buf = STRBUF_INIT; if (argc > 1) - die(_("too many branches to unset upstream")); + die(_("too many arguments to unset upstream")); if (!branch) { if (!argc || !strcmp(argv[0], "HEAD")) diff --git a/builtin/checkout.c b/builtin/checkout.c index d091f06274..fc4f8fd2ea 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -797,9 +797,14 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new) for_each_ref(add_pending_uninteresting_ref, &revs); add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING); + /* Save pending objects, so they can be cleaned up later. */ refs = revs.pending; revs.leak_pending = 1; + /* + * prepare_revision_walk (together with .leak_pending = 1) makes us + * the sole owner of the list of pending objects. + */ if (prepare_revision_walk(&revs)) die(_("internal error in revision walk")); if (!(old->object.flags & UNINTERESTING)) @@ -807,8 +812,10 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new) else describe_detached_head(_("Previous HEAD position was"), old); + /* Clean up objects used, as they will be reused. */ clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS); - free(refs.objects); + + object_array_clear(&refs); } static int switch_branches(const struct checkout_opts *opts, @@ -1117,9 +1124,8 @@ static int checkout_branch(struct checkout_opts *opts, if (new->path && !opts->force_detach && !opts->new_branch && !opts->ignore_other_worktrees) { - struct object_id oid; int flag; - char *head_ref = resolve_refdup("HEAD", 0, oid.hash, &flag); + char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag); if (head_ref && (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path))) die_if_checked_out(new->path, 1); @@ -1291,6 +1297,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) strbuf_release(&buf); } + UNLEAK(opts); if (opts.patch_mode || opts.pathspec.nr) return checkout_paths(&opts, new.name); else diff --git a/builtin/commit.c b/builtin/commit.c index 39d5b7f6c7..d75b3805ea 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -335,7 +335,7 @@ static void refresh_cache_or_die(int refresh_flags) static const char *prepare_index(int argc, const char **argv, const char *prefix, const struct commit *current_head, int is_status) { - struct string_list partial; + struct string_list partial = STRING_LIST_INIT_DUP; struct pathspec pathspec; int refresh_flags = REFRESH_QUIET; const char *ret; @@ -380,7 +380,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix warning(_("Failed to update main cache tree")); commit_style = COMMIT_NORMAL; - return get_lock_file_path(&index_lock); + ret = get_lock_file_path(&index_lock); + goto out; } /* @@ -403,7 +404,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) die(_("unable to write new_index file")); commit_style = COMMIT_NORMAL; - return get_lock_file_path(&index_lock); + ret = get_lock_file_path(&index_lock); + goto out; } /* @@ -429,7 +431,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix rollback_lock_file(&index_lock); } commit_style = COMMIT_AS_IS; - return get_index_file(); + ret = get_index_file(); + goto out; } /* @@ -460,7 +463,6 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix die(_("cannot do a partial commit during a cherry-pick.")); } - string_list_init(&partial, 1); if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec)) exit(1); @@ -490,6 +492,9 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix discard_cache(); ret = get_lock_file_path(&false_lock); read_cache_from(ret); +out: + string_list_clear(&partial, 0); + clear_pathspec(&pathspec); return ret; } @@ -1387,7 +1392,10 @@ int cmd_status(int argc, const char **argv, const char *prefix) read_cache_preload(&s.pathspec); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL); - fd = hold_locked_index(&index_lock, 0); + if (use_optional_locks()) + fd = hold_locked_index(&index_lock, 0); + else + fd = -1; s.is_initial = get_oid(s.reference, &oid) ? 1 : 0; if (!s.is_initial) diff --git a/builtin/describe.c b/builtin/describe.c index 3dc1836480..29075dbd0f 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -129,13 +129,24 @@ static void add_to_known_names(const char *path, static int get_name(const char *path, const struct object_id *oid, int flag, void *cb_data) { - int is_tag = starts_with(path, "refs/tags/"); + int is_tag = 0; struct object_id peeled; int is_annotated, prio; - - /* Reject anything outside refs/tags/ unless --all */ - if (!all && !is_tag) + const char *path_to_match = NULL; + + if (skip_prefix(path, "refs/tags/", &path_to_match)) { + is_tag = 1; + } else if (all) { + if ((exclude_patterns.nr || patterns.nr) && + !skip_prefix(path, "refs/heads/", &path_to_match) && + !skip_prefix(path, "refs/remotes/", &path_to_match)) { + /* Only accept reference of known type if there are match/exclude patterns */ + return 0; + } + } else { + /* Reject anything outside refs/tags/ unless --all */ return 0; + } /* * If we're given exclude patterns, first exclude any tag which match @@ -144,11 +155,8 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi if (exclude_patterns.nr) { struct string_list_item *item; - if (!is_tag) - return 0; - for_each_string_list_item(item, &exclude_patterns) { - if (!wildmatch(item->string, path + 10, 0)) + if (!wildmatch(item->string, path_to_match, 0)) return 0; } } @@ -161,11 +169,8 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi int found = 0; struct string_list_item *item; - if (!is_tag) - return 0; - for_each_string_list_item(item, &patterns) { - if (!wildmatch(item->string, path + 10, 0)) { + if (!wildmatch(item->string, path_to_match, 0)) { found = 1; break; } diff --git a/builtin/diff-index.c b/builtin/diff-index.c index 9d772f8f27..522f4fdffd 100644 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@ -56,5 +56,6 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) return -1; } result = run_diff_index(&rev, cached); + UNLEAK(rev); return diff_result_code(&rev.diffopt, result); } diff --git a/builtin/diff.c b/builtin/diff.c index 7e3ebcea38..f5bbd4d757 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -464,5 +464,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) result = diff_result_code(&rev.diffopt, result); if (1 < rev.diffopt.skip_stat_unmatch) refresh_index_quietly(); + UNLEAK(rev); + UNLEAK(ent); + UNLEAK(blob); return result; } diff --git a/builtin/fast-export.c b/builtin/fast-export.c index d412c0a8f3..2fb60d6d48 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -344,6 +344,7 @@ static void show_filemodify(struct diff_queue_struct *q, struct diff_options *options, void *data) { int i; + struct string_list *changed = data; /* * Handle files below a directory first, in case they are all deleted @@ -359,20 +360,31 @@ static void show_filemodify(struct diff_queue_struct *q, case DIFF_STATUS_DELETED: printf("D "); print_path(spec->path); + string_list_insert(changed, spec->path); putchar('\n'); break; case DIFF_STATUS_COPIED: case DIFF_STATUS_RENAMED: - printf("%c ", q->queue[i]->status); - print_path(ospec->path); - putchar(' '); - print_path(spec->path); - putchar('\n'); - - if (!oidcmp(&ospec->oid, &spec->oid) && - ospec->mode == spec->mode) - break; + /* + * If a change in the file corresponding to ospec->path + * has been observed, we cannot trust its contents + * because the diff is calculated based on the prior + * contents, not the current contents. So, declare a + * copy or rename only if there was no change observed. + */ + if (!string_list_has_string(changed, ospec->path)) { + printf("%c ", q->queue[i]->status); + print_path(ospec->path); + putchar(' '); + print_path(spec->path); + string_list_insert(changed, spec->path); + putchar('\n'); + + if (!oidcmp(&ospec->oid, &spec->oid) && + ospec->mode == spec->mode) + break; + } /* fallthrough */ case DIFF_STATUS_TYPE_CHANGED: @@ -393,6 +405,7 @@ static void show_filemodify(struct diff_queue_struct *q, get_object_mark(object)); } print_path(spec->path); + string_list_insert(changed, spec->path); putchar('\n'); break; @@ -528,7 +541,8 @@ static void anonymize_ident_line(const char **beg, const char **end) *end = out->buf + out->len; } -static void handle_commit(struct commit *commit, struct rev_info *rev) +static void handle_commit(struct commit *commit, struct rev_info *rev, + struct string_list *paths_of_changed_objects) { int saved_output_format = rev->diffopt.output_format; const char *commit_buffer; @@ -615,6 +629,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) if (full_tree) printf("deleteall\n"); log_tree_diff_flush(rev); + string_list_clear(paths_of_changed_objects, 0); rev->diffopt.output_format = saved_output_format; printf("\n"); @@ -630,15 +645,15 @@ static void *anonymize_tag(const void *old, size_t *len) return strbuf_detach(&out, len); } -static void handle_tail(struct object_array *commits, struct rev_info *revs) +static void handle_tail(struct object_array *commits, struct rev_info *revs, + struct string_list *paths_of_changed_objects) { struct commit *commit; while (commits->nr) { - commit = (struct commit *)commits->objects[commits->nr - 1].item; + commit = (struct commit *)object_array_pop(commits); if (has_unshown_parent(commit)) return; - handle_commit(commit, revs); - commits->nr--; + handle_commit(commit, revs, paths_of_changed_objects); } } @@ -977,6 +992,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) char *export_filename = NULL, *import_filename = NULL; uint32_t lastimportid; struct string_list refspecs_list = STRING_LIST_INIT_NODUP; + struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP; struct option options[] = { OPT_INTEGER(0, "progress", &progress, N_("show progress after <n> objects")), @@ -1049,14 +1065,15 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (prepare_revision_walk(&revs)) die("revision walk setup failed"); revs.diffopt.format_callback = show_filemodify; + revs.diffopt.format_callback_data = &paths_of_changed_objects; DIFF_OPT_SET(&revs.diffopt, RECURSIVE); while ((commit = get_revision(&revs))) { if (has_unshown_parent(commit)) { add_object_array(&commit->object, NULL, &commits); } else { - handle_commit(commit, &revs); - handle_tail(&commits, &revs); + handle_commit(commit, &revs, &paths_of_changed_objects); + handle_tail(&commits, &revs, &paths_of_changed_objects); } } diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 5d7c921a77..e931be9ce4 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -36,6 +36,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) OPT_GROUP(""), OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")), + OPT__COLOR(&format.use_color, N_("respect format colors")), 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, diff --git a/builtin/fsck.c b/builtin/fsck.c index 1e4c471b41..56afe405b8 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -182,12 +182,7 @@ static int traverse_reachable(void) if (show_progress) progress = start_delayed_progress(_("Checking connectivity"), 0); while (pending.nr) { - struct object_array_entry *entry; - struct object *obj; - - entry = pending.objects + --pending.nr; - obj = entry->item; - result |= traverse_one_object(obj); + result |= traverse_one_object(object_array_pop(&pending)); display_progress(progress, ++nr); } stop_progress(&progress); diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c index 6d9a79f9b3..2706fcfaf2 100644 --- a/builtin/get-tar-commit-id.c +++ b/builtin/get-tar-commit-id.c @@ -26,8 +26,10 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix) usage(builtin_get_tar_commit_id_usage); n = read_in_full(0, buffer, HEADERSIZE); - if (n < HEADERSIZE) - die("git get-tar-commit-id: read error"); + if (n < 0) + die_errno("git get-tar-commit-id: read error"); + if (n != HEADERSIZE) + die_errno("git get-tar-commit-id: EOF before reading tar header"); if (header->typeflag[0] != 'g') return 1; if (!skip_prefix(content, "52 comment=", &comment)) diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 598da6c8bc..9e088ebd11 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -494,5 +494,6 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) always, allow_undefined, data.name_only); } + UNLEAK(revs); return 0; } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index f721137eaf..5ee2c48ffb 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2563,8 +2563,8 @@ struct in_pack_object { }; struct in_pack { - int alloc; - int nr; + unsigned int alloc; + unsigned int nr; struct in_pack_object *array; }; diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index c82b4dce68..f8519363a3 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -12,15 +12,30 @@ static const char * const builtin_rebase_helper_usage[] = { int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; + int keep_empty = 0; enum { - CONTINUE = 1, ABORT + CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_SHA1S, EXPAND_SHA1S, + CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH } command = 0; struct option options[] = { OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), + OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), OPT_CMDMODE(0, "abort", &command, N_("abort rebase"), ABORT), + OPT_CMDMODE(0, "make-script", &command, + N_("make rebase script"), MAKE_SCRIPT), + OPT_CMDMODE(0, "shorten-ids", &command, + N_("shorten SHA-1s in the todo list"), SHORTEN_SHA1S), + OPT_CMDMODE(0, "expand-ids", &command, + N_("expand SHA-1s in the todo list"), EXPAND_SHA1S), + OPT_CMDMODE(0, "check-todo-list", &command, + N_("check the todo list"), CHECK_TODO_LIST), + OPT_CMDMODE(0, "skip-unnecessary-picks", &command, + N_("skip unnecessary picks"), SKIP_UNNECESSARY_PICKS), + OPT_CMDMODE(0, "rearrange-squash", &command, + N_("rearrange fixup/squash lines"), REARRANGE_SQUASH), OPT_END() }; @@ -37,5 +52,17 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) return !!sequencer_continue(&opts); if (command == ABORT && argc == 1) return !!sequencer_remove_state(&opts); + if (command == MAKE_SCRIPT && argc > 1) + return !!sequencer_make_script(keep_empty, stdout, argc, argv); + if (command == SHORTEN_SHA1S && argc == 1) + return !!transform_todo_ids(1); + if (command == EXPAND_SHA1S && argc == 1) + return !!transform_todo_ids(0); + if (command == CHECK_TODO_LIST && argc == 1) + return !!check_todo_list(); + if (command == SKIP_UNNECESSARY_PICKS && argc == 1) + return !!skip_unnecessary_picks(); + if (command == REARRANGE_SQUASH && argc == 1) + return !!rearrange_squash(); usage_with_options(builtin_rebase_helper_usage, options); } diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 29a0f3b75f..cc48767405 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1458,7 +1458,6 @@ static void execute_commands(struct command *commands, { struct check_connected_options opt = CHECK_CONNECTED_INIT; struct command *cmd; - struct object_id oid; struct iterate_data data; struct async muxer; int err_fd = 0; @@ -1515,7 +1514,7 @@ static void execute_commands(struct command *commands, check_aliased_updates(commands); free(head_name_to_free); - head_name = head_name_to_free = resolve_refdup("HEAD", 0, oid.hash, NULL); + head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL); if (use_atomic) execute_commands_atomic(commands, si); diff --git a/builtin/reflog.c b/builtin/reflog.c index e237d927a0..2067cca5b1 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -126,7 +126,7 @@ static int commit_is_complete(struct commit *commit) struct commit *c; struct commit_list *parent; - c = (struct commit *)study.objects[--study.nr].item; + c = (struct commit *)object_array_pop(&study); if (!c->object.parsed && !parse_object(&c->object.oid)) c->object.flags |= INCOMPLETE; @@ -182,8 +182,8 @@ static int commit_is_complete(struct commit *commit) found.objects[i].item->flags |= SEEN; } /* free object arrays */ - free(study.objects); - free(found.objects); + object_array_clear(&study); + object_array_clear(&found); return !is_incomplete; } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index b9c13d3d9d..a8d7e6f7ae 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -387,6 +387,14 @@ static const char *skipspaces(const char *s) return s; } +static char *findspace(const char *s) +{ + for (; *s; s++) + if (isspace(*s)) + return (char*)s; + return NULL; +} + static int cmd_parseopt(int argc, const char **argv, const char *prefix) { static int keep_dashdash = 0, stop_at_non_option = 0; @@ -434,7 +442,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) /* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */ while (strbuf_getline(&sb, stdin) != EOF) { const char *s; - const char *help; + char *help; struct option *o; if (!sb.len) @@ -444,15 +452,17 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) memset(opts + onb, 0, sizeof(opts[onb])); o = &opts[onb++]; - help = strchr(sb.buf, ' '); - if (!help || *sb.buf == ' ') { + help = findspace(sb.buf); + if (!help || sb.buf == help) { o->type = OPTION_GROUP; o->help = xstrdup(skipspaces(sb.buf)); continue; } + *help = '\0'; + o->type = OPTION_CALLBACK; - o->help = xstrdup(skipspaces(help)); + o->help = xstrdup(skipspaces(help+1)); o->value = &parsed; o->flags = PARSE_OPT_NOARG; o->callback = &parseopt_dump; diff --git a/builtin/tag.c b/builtin/tag.c index c627794181..695cb0778e 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -411,6 +411,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) }, OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")), + OPT__COLOR(&format.use_color, N_("respect format colors")), OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), OPT_END() }; @@ -552,9 +553,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (force && !is_null_oid(&prev) && oidcmp(&prev, &object)) printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV)); - strbuf_release(&err); - strbuf_release(&buf); - strbuf_release(&ref); - strbuf_release(&reflog_msg); + UNLEAK(buf); + UNLEAK(ref); + UNLEAK(reflog_msg); + UNLEAK(msg); + UNLEAK(err); return 0; } diff --git a/builtin/worktree.c b/builtin/worktree.c index de26849f55..7b9307aa58 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -38,7 +38,9 @@ static int prune_worktree(const char *id, struct strbuf *reason) { struct stat st; char *path; - int fd, len; + int fd; + size_t len; + ssize_t read_result; if (!is_directory(git_path("worktrees/%s", id))) { strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id); @@ -56,10 +58,26 @@ static int prune_worktree(const char *id, struct strbuf *reason) id, strerror(errno)); return 1; } - len = st.st_size; + len = xsize_t(st.st_size); path = xmallocz(len); - read_in_full(fd, path, len); + + read_result = read_in_full(fd, path, len); + if (read_result < 0) { + strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"), + id, strerror(errno)); + close(fd); + free(path); + return 1; + } close(fd); + + if (read_result != len) { + strbuf_addf(reason, + _("Removing worktrees/%s: short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"), + id, (uintmax_t)len, (uintmax_t)read_result); + free(path); + return 1; + } while (len && (path[len - 1] == '\n' || path[len - 1] == '\r')) len--; if (!len) { |