diff options
Diffstat (limited to 'builtin')
61 files changed, 3238 insertions, 1121 deletions
diff --git a/builtin/add.c b/builtin/add.c index db2dfa4350..dd18e5c9b6 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -374,11 +374,12 @@ static int add_files(struct dir_struct *dir, int flags) } 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; + } else { + check_embedded_repo(dir->entries[i]->name); } } return exit_status; diff --git a/builtin/am.c b/builtin/am.c index 58a2aef28b..78389d08b6 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -453,6 +453,7 @@ static int run_post_rewrite_hook(const struct am_state *state) cp.in = xopen(am_path(state, "rewritten"), O_RDONLY); cp.stdout_to_stderr = 1; + cp.trace2_hook_name = "post-rewrite"; ret = run_command(&cp); @@ -485,23 +486,24 @@ static int copy_notes_for_rebase(const struct am_state *state) while (!strbuf_getline_lf(&sb, fp)) { struct object_id from_obj, to_obj; + const char *p; - if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) { + if (sb.len != the_hash_algo->hexsz * 2 + 1) { ret = error(invalid_line, sb.buf); goto finish; } - if (get_oid_hex(sb.buf, &from_obj)) { + if (parse_oid_hex(sb.buf, &from_obj, &p)) { ret = error(invalid_line, sb.buf); goto finish; } - if (sb.buf[GIT_SHA1_HEXSZ] != ' ') { + if (*p != ' ') { ret = error(invalid_line, sb.buf); goto finish; } - if (get_oid_hex(sb.buf + GIT_SHA1_HEXSZ + 1, &to_obj)) { + if (get_oid_hex(p + 1, &to_obj)) { ret = error(invalid_line, sb.buf); goto finish; } @@ -1337,9 +1339,10 @@ static void write_index_patch(const struct am_state *state) struct rev_info rev_info; FILE *fp; - if (!get_oid_tree("HEAD", &head)) - tree = lookup_tree(the_repository, &head); - else + if (!get_oid("HEAD", &head)) { + struct commit *commit = lookup_commit_or_die(&head, "HEAD"); + tree = get_commit_tree(commit); + } else tree = lookup_tree(the_repository, the_repository->hash_algo->empty_tree); @@ -1500,11 +1503,11 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa * review them with extra care to spot mismerges. */ struct rev_info rev_info; - const char *diff_filter_str = "--diff-filter=AM"; repo_init_revisions(the_repository, &rev_info, NULL); rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS; - diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix); + rev_info.diffopt.filter |= diff_filter_bit('A'); + rev_info.diffopt.filter |= diff_filter_bit('M'); add_pending_oid(&rev_info, "HEAD", &our_tree, 0); diff_setup_done(&rev_info.diffopt); run_diff_index(&rev_info, 1); @@ -1579,6 +1582,7 @@ static void do_commit(const struct am_state *state) } author = fmt_ident(state->author_name, state->author_email, + WANT_AUTHOR_IDENT, state->ignore_date ? NULL : state->author_date, IDENT_STRICT); @@ -1640,11 +1644,8 @@ static int do_interactive(struct am_state *state) { assert(state->msg); - if (!isatty(0)) - die(_("cannot be interactive without stdin connected to a terminal.")); - for (;;) { - const char *reply; + char reply[64]; puts(_("Commit Body is:")); puts("--------------------------"); @@ -1656,11 +1657,11 @@ static int do_interactive(struct am_state *state) * in your translation. The program will only accept English * input at this point. */ - reply = git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO); + printf(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: ")); + if (!fgets(reply, sizeof(reply), stdin)) + die("unable to read from stdin; aborting"); - if (!reply) { - continue; - } else if (*reply == 'y' || *reply == 'Y') { + if (*reply == 'y' || *reply == 'Y') { return 0; } else if (*reply == 'a' || *reply == 'A') { state->interactive = 0; @@ -2119,6 +2120,10 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int *opt_value = PATCH_FORMAT_HG; else if (!strcmp(arg, "mboxrd")) *opt_value = PATCH_FORMAT_MBOXRD; + /* + * Please update $__git_patchformat in git-completion.bash + * when you add new options + */ else return error(_("Invalid value for --patch-format: %s"), arg); return 0; @@ -2327,6 +2332,9 @@ int cmd_am(int argc, const char **argv, const char *prefix) argv_array_push(&paths, mkpath("%s/%s", prefix, argv[i])); } + if (state.interactive && !paths.argc) + die(_("interactive mode requires patches on the command line")); + am_setup(&state, patch_format, paths.argv, keep_cr); argv_array_clear(&paths); diff --git a/builtin/blame.c b/builtin/blame.c index 581de0d832..21cde57e71 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -27,6 +27,7 @@ #include "object-store.h" #include "blame.h" #include "string-list.h" +#include "refs.h" static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"); @@ -814,7 +815,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) * and are only included here to get included in the "-h" * output: */ - { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, + { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, NULL, 0, parse_opt_unknown_cb }, OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL), OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")), @@ -993,6 +994,18 @@ parse_done: revs.disable_stdin = 1; setup_revisions(argc, argv, &revs, NULL); + if (!revs.pending.nr && is_bare_repository()) { + struct commit *head_commit; + struct object_id head_oid; + + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, + &head_oid, NULL) || + !(head_commit = lookup_commit_reference_gently(revs.repo, + &head_oid, 1))) + die("no such ref: HEAD"); + + add_pending_object(&revs, &head_commit->object, "HEAD"); + } init_scoreboard(&sb); sb.revs = &revs; diff --git a/builtin/branch.c b/builtin/branch.c index 1be727209b..d4359b33ac 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -443,6 +443,21 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin free(to_free); } +static void print_current_branch_name(void) +{ + int flags; + const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags); + const char *shortname; + if (!refname) + die(_("could not resolve HEAD")); + else if (!(flags & REF_ISSYMREF)) + return; + else if (skip_prefix(refname, "refs/heads/", &shortname)) + puts(shortname); + else + die(_("HEAD (%s) points outside of refs/heads/"), refname); +} + static void reject_rebase_or_bisect_branch(const char *target) { struct worktree **worktrees = get_worktrees(0); @@ -581,6 +596,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, copy = 0, force = 0, list = 0; + int show_current = 0; int reflog = 0, edit_description = 0; int quiet = 0, unset_upstream = 0; const char *new_upstream = NULL; @@ -620,6 +636,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) 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('l', "list", &list, N_("list branch names")), + OPT_BOOL(0, "show-current", &show_current, N_("show current branch name")), OPT_BOOL(0, "create-reflog", &reflog, N_("create the branch's reflog")), OPT_BOOL(0, "edit-description", &edit_description, N_("edit the description for the branch")), @@ -627,8 +644,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_MERGED(&filter, N_("print only branches that are merged")), OPT_NO_MERGED(&filter, N_("print only branches that are not merged")), OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")), - OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), - N_("field name to sort on"), &parse_opt_ref_sorting), + OPT_REF_SORT(sorting_tail), { OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"), N_("print only branches of the object"), 0, parse_opt_object_name @@ -662,14 +678,15 @@ 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 && !copy && !edit_description && !new_upstream && !unset_upstream && argc == 0) + if (!delete && !rename && !copy && !edit_description && !new_upstream && + !show_current && !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 + !!copy + !!new_upstream + + if (!!delete + !!rename + !!copy + !!new_upstream + !!show_current + list + unset_upstream > 1) usage_with_options(builtin_branch_usage, options); @@ -697,6 +714,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (!argc) die(_("branch name required")); return delete_branches(argc, argv, delete > 1, filter.kind, quiet); + } else if (show_current) { + print_current_branch_name(); + return 0; } else if (list) { /* git branch --local also shows HEAD when it is detached */ if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached) diff --git a/builtin/checkout.c b/builtin/checkout.c index 24b8593b93..ffa776c6e1 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -46,6 +46,7 @@ struct checkout_opts { int ignore_other_worktrees; int show_progress; int count_checkout_paths; + int overlay_mode; /* * If new checkout options are added, skip_merge_working_tree * should be updated accordingly. @@ -135,7 +136,8 @@ static int skip_same_name(const struct cache_entry *ce, int pos) return pos; } -static int check_stage(int stage, const struct cache_entry *ce, int pos) +static int check_stage(int stage, const struct cache_entry *ce, int pos, + int overlay_mode) { while (pos < active_nr && !strcmp(active_cache[pos]->name, ce->name)) { @@ -143,6 +145,8 @@ static int check_stage(int stage, const struct cache_entry *ce, int pos) return 0; pos++; } + if (!overlay_mode) + return 0; if (stage == 2) return error(_("path '%s' does not have our version"), ce->name); else @@ -168,7 +172,8 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos) } static int checkout_stage(int stage, const struct cache_entry *ce, int pos, - const struct checkout *state, int *nr_checkouts) + const struct checkout *state, int *nr_checkouts, + int overlay_mode) { while (pos < active_nr && !strcmp(active_cache[pos]->name, ce->name)) { @@ -177,6 +182,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos, NULL, nr_checkouts); pos++; } + if (!overlay_mode) { + unlink_entry(ce); + return 0; + } if (stage == 2) return error(_("path '%s' does not have our version"), ce->name); else @@ -251,6 +260,59 @@ static int checkout_merged(int pos, const struct checkout *state, int *nr_checko return status; } +static void mark_ce_for_checkout_overlay(struct cache_entry *ce, + char *ps_matched, + const struct checkout_opts *opts) +{ + ce->ce_flags &= ~CE_MATCHED; + if (!opts->ignore_skipworktree && ce_skip_worktree(ce)) + return; + if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) + /* + * "git checkout tree-ish -- path", but this entry + * is in the original index but is not in tree-ish + * or does not match the pathspec; it will not be + * checked out to the working tree. We will not do + * anything to this entry at all. + */ + return; + /* + * Either this entry came from the tree-ish we are + * checking the paths out of, or we are checking out + * of the index. + * + * If it comes from the tree-ish, we already know it + * matches the pathspec and could just stamp + * CE_MATCHED to it from update_some(). But we still + * need ps_matched and read_tree_recursive (and + * eventually tree_entry_interesting) cannot fill + * ps_matched yet. Once it can, we can avoid calling + * match_pathspec() for _all_ entries when + * opts->source_tree != NULL. + */ + if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) + ce->ce_flags |= CE_MATCHED; +} + +static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce, + char *ps_matched, + const struct checkout_opts *opts) +{ + ce->ce_flags &= ~CE_MATCHED; + if (!opts->ignore_skipworktree && ce_skip_worktree(ce)) + return; + if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) { + ce->ce_flags |= CE_MATCHED; + if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) + /* + * In overlay mode, but the path is not in + * tree-ish, which means we should remove it + * from the index and the working tree. + */ + ce->ce_flags |= CE_REMOVE | CE_WT_REMOVE; + } +} + static int checkout_paths(const struct checkout_opts *opts, const char *revision) { @@ -263,6 +325,8 @@ static int checkout_paths(const struct checkout_opts *opts, struct lock_file lock_file = LOCK_INIT; int nr_checkouts = 0, nr_unmerged = 0; + trace2_cmd_mode(opts->patch_mode ? "patch" : "path"); + if (opts->track != BRANCH_TRACK_UNSPECIFIED) die(_("'%s' cannot be used with updating paths"), "--track"); @@ -302,39 +366,17 @@ static int checkout_paths(const struct checkout_opts *opts, * Make sure all pathspecs participated in locating the paths * to be checked out. */ - for (pos = 0; pos < active_nr; pos++) { - struct cache_entry *ce = active_cache[pos]; - ce->ce_flags &= ~CE_MATCHED; - if (!opts->ignore_skipworktree && ce_skip_worktree(ce)) - continue; - if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) - /* - * "git checkout tree-ish -- path", but this entry - * is in the original index; it will not be checked - * out to the working tree and it does not matter - * if pathspec matched this entry. We will not do - * anything to this entry at all. - */ - continue; - /* - * Either this entry came from the tree-ish we are - * checking the paths out of, or we are checking out - * of the index. - * - * If it comes from the tree-ish, we already know it - * matches the pathspec and could just stamp - * CE_MATCHED to it from update_some(). But we still - * need ps_matched and read_tree_recursive (and - * eventually tree_entry_interesting) cannot fill - * ps_matched yet. Once it can, we can avoid calling - * match_pathspec() for _all_ entries when - * opts->source_tree != NULL. - */ - if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) - ce->ce_flags |= CE_MATCHED; - } + for (pos = 0; pos < active_nr; pos++) + if (opts->overlay_mode) + mark_ce_for_checkout_overlay(active_cache[pos], + ps_matched, + opts); + else + mark_ce_for_checkout_no_overlay(active_cache[pos], + ps_matched, + opts); - if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) { + if (report_path_error(ps_matched, &opts->pathspec)) { free(ps_matched); return 1; } @@ -353,7 +395,7 @@ static int checkout_paths(const struct checkout_opts *opts, if (opts->force) { warning(_("path '%s' is unmerged"), ce->name); } else if (opts->writeout_stage) { - errs |= check_stage(opts->writeout_stage, ce, pos); + errs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode); } else if (opts->merge) { errs |= check_stages((1<<2) | (1<<3), ce, pos); } else { @@ -383,13 +425,16 @@ static int checkout_paths(const struct checkout_opts *opts, if (opts->writeout_stage) errs |= checkout_stage(opts->writeout_stage, ce, pos, - &state, &nr_checkouts); + &state, + &nr_checkouts, opts->overlay_mode); else if (opts->merge) errs |= checkout_merged(pos, &state, &nr_unmerged); pos = skip_same_name(ce, pos) - 1; } } + remove_marked_cache_entries(&the_index, 1); + remove_scheduled_dirs(); errs |= finish_delayed_checkout(&state, &nr_checkouts); if (opts->count_checkout_paths) { @@ -572,6 +617,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts, */ /* + * opts->overlay_mode cannot be used with switching branches so is + * not tested here + */ + + /* * If we aren't creating a new branch any changes or updates will * happen in the existing branch. Since that could only be updating * the index and working directory, we don't want to skip those steps @@ -650,7 +700,7 @@ static int merge_working_tree(const struct checkout_opts *opts, topts.initial_checkout = is_cache_unborn(); topts.update = 1; topts.merge = 1; - topts.gently = opts->merge && old_branch_info->commit; + topts.quiet = opts->merge && old_branch_info->commit; topts.verbose_update = opts->show_progress; topts.fn = twoway_merge; if (opts->overwrite_ignore) { @@ -675,7 +725,10 @@ static int merge_working_tree(const struct checkout_opts *opts, */ struct tree *result; struct tree *work; + struct tree *old_tree; struct merge_options o; + struct strbuf sb = STRBUF_INIT; + if (!opts->merge) return 1; @@ -685,6 +738,19 @@ static int merge_working_tree(const struct checkout_opts *opts, */ if (!old_branch_info->commit) return 1; + old_tree = get_commit_tree(old_branch_info->commit); + + if (repo_index_has_changes(the_repository, old_tree, &sb)) + die(_("cannot continue with staged changes in " + "the following files:\n%s"), sb.buf); + strbuf_release(&sb); + + if (repo_index_has_changes(the_repository, + get_commit_tree(old_branch_info->commit), + &sb)) + warning(_("staged changes in the following files may be lost: %s"), + sb.buf); + strbuf_release(&sb); /* Do more real merge */ @@ -722,7 +788,7 @@ static int merge_working_tree(const struct checkout_opts *opts, ret = merge_trees(&o, get_commit_tree(new_branch_info->commit), work, - get_commit_tree(old_branch_info->commit), + old_tree, &result); if (ret < 0) exit(128); @@ -966,6 +1032,9 @@ static int switch_branches(const struct checkout_opts *opts, void *path_to_free; struct object_id rev; int flag, writeout_error = 0; + + trace2_cmd_mode("branch"); + memset(&old_branch_info, 0, sizeof(old_branch_info)); old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag); if (old_branch_info.path) @@ -1203,6 +1272,8 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts) int status; struct strbuf branch_ref = STRBUF_INIT; + trace2_cmd_mode("unborn"); |