diff options
Diffstat (limited to 'builtin')
54 files changed, 929 insertions, 729 deletions
diff --git a/builtin/add.c b/builtin/add.c index 352b85e8db..1074e32349 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "builtin.h" +#include "lockfile.h" #include "dir.h" #include "pathspec.h" #include "exec_cmd.h" @@ -283,7 +284,7 @@ static int add_files(struct dir_struct *dir, int flags) for (i = 0; i < dir->ignored_nr; i++) fprintf(stderr, "%s\n", dir->ignored[i]->name); fprintf(stderr, _("Use -f if you really want to add them.\n")); - die(_("no files added")); + exit_status = 1; } for (i = 0; i < dir->nr; i++) diff --git a/builtin/apply.c b/builtin/apply.c index 4bb31fd6ae..dfd7a34117 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -7,6 +7,7 @@ * */ #include "cache.h" +#include "lockfile.h" #include "cache-tree.h" #include "quote.h" #include "blob.h" @@ -435,7 +436,7 @@ static unsigned long linelen(const char *buffer, unsigned long size) static int is_dev_null(const char *str) { - return !memcmp("/dev/null", str, 9) && isspace(str[9]); + return skip_prefix(str, "/dev/null", &str) && isspace(*str); } #define TERM_SPACE 1 @@ -3722,7 +3723,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename) if (!preimage_sha1_in_gitlink_patch(patch, sha1)) ; /* ok, the textual part looks sane */ else - die("sha1 information is lacking or useless for submoule %s", + die("sha1 information is lacking or useless for submodule %s", name); } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) { ; /* ok */ @@ -4174,7 +4175,7 @@ static int write_out_results(struct patch *list) if (cpath.nr) { struct string_list_item *item; - sort_string_list(&cpath); + string_list_sort(&cpath); for_each_string_list_item(item, &cpath) fprintf(stderr, "U %s\n", item->string); string_list_clear(&cpath, 0); diff --git a/builtin/blame.c b/builtin/blame.c index 699109b4a9..0374fe8056 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2286,7 +2286,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, commit->date = now; parent_tail = &commit->parents; - if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL)) + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL)) die("no such ref: HEAD"); parent_tail = append_parent(parent_tail, head_sha1); diff --git a/builtin/branch.c b/builtin/branch.c index 9e4666f0c5..dc6f0b266c 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -62,39 +62,40 @@ static unsigned char merge_filter_ref[20]; static struct string_list output = STRING_LIST_INIT_DUP; static unsigned int colopts; -static int parse_branch_color_slot(const char *var, int ofs) +static int parse_branch_color_slot(const char *slot) { - if (!strcasecmp(var+ofs, "plain")) + if (!strcasecmp(slot, "plain")) return BRANCH_COLOR_PLAIN; - if (!strcasecmp(var+ofs, "reset")) + if (!strcasecmp(slot, "reset")) return BRANCH_COLOR_RESET; - if (!strcasecmp(var+ofs, "remote")) + if (!strcasecmp(slot, "remote")) return BRANCH_COLOR_REMOTE; - if (!strcasecmp(var+ofs, "local")) + if (!strcasecmp(slot, "local")) return BRANCH_COLOR_LOCAL; - if (!strcasecmp(var+ofs, "current")) + if (!strcasecmp(slot, "current")) return BRANCH_COLOR_CURRENT; - if (!strcasecmp(var+ofs, "upstream")) + if (!strcasecmp(slot, "upstream")) return BRANCH_COLOR_UPSTREAM; return -1; } static int git_branch_config(const char *var, const char *value, void *cb) { + const char *slot_name; + if (starts_with(var, "column.")) return git_column_config(var, value, "branch", &colopts); if (!strcmp(var, "color.branch")) { branch_use_color = git_config_colorbool(var, value); return 0; } - if (starts_with(var, "color.branch.")) { - int slot = parse_branch_color_slot(var, 13); + if (skip_prefix(var, "color.branch.", &slot_name)) { + int slot = parse_branch_color_slot(slot_name); if (slot < 0) return 0; if (!value) return config_error_nonbool(var); - color_parse(value, var, branch_colors[slot]); - return 0; + return color_parse(value, branch_colors[slot]); } return git_color_default_config(var, value, cb); } @@ -129,7 +130,8 @@ static int branch_merged(int kind, const char *name, branch->merge[0] && branch->merge[0]->dst && (reference_name = reference_name_to_free = - resolve_refdup(branch->merge[0]->dst, sha1, 1, NULL)) != NULL) + resolve_refdup(branch->merge[0]->dst, RESOLVE_REF_READING, + sha1, NULL)) != NULL) reference_rev = lookup_commit_reference(sha1); } if (!reference_rev) @@ -233,9 +235,12 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, free(name); name = mkpathdup(fmt, bname.buf); - target = resolve_ref_unsafe(name, sha1, 0, &flags); - if (!target || - (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) { + target = resolve_ref_unsafe(name, + RESOLVE_REF_READING + | RESOLVE_REF_NO_RECURSE + | RESOLVE_REF_ALLOW_BAD_NAME, + sha1, &flags); + if (!target) { error(remote_branch ? _("remote branch '%s' not found.") : _("branch '%s' not found."), bname.buf); @@ -243,7 +248,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, continue; } - if (!(flags & REF_ISSYMREF) && + if (!(flags & (REF_ISSYMREF|REF_ISBROKEN)) && check_branch_commit(bname.buf, name, sha1, head_rev, kinds, force)) { ret = 1; @@ -263,8 +268,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, ? _("Deleted remote branch %s (was %s).\n") : _("Deleted branch %s (was %s).\n"), bname.buf, - (flags & REF_ISSYMREF) - ? target + (flags & REF_ISBROKEN) ? "broken" + : (flags & REF_ISSYMREF) ? target : find_unique_abbrev(sha1, DEFAULT_ABBREV)); } delete_branch_config(bname.buf); @@ -297,7 +302,7 @@ static char *resolve_symref(const char *src, const char *prefix) int flag; const char *dst; - dst = resolve_ref_unsafe(src, sha1, 0, &flag); + dst = resolve_ref_unsafe(src, 0, sha1, &flag); if (!(dst && (flag & REF_ISSYMREF))) return NULL; if (prefix) @@ -335,20 +340,18 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, static struct { int kind; const char *prefix; - int pfxlen; } ref_kind[] = { - { REF_LOCAL_BRANCH, "refs/heads/", 11 }, - { REF_REMOTE_BRANCH, "refs/remotes/", 13 }, + { REF_LOCAL_BRANCH, "refs/heads/" }, + { REF_REMOTE_BRANCH, "refs/remotes/" }, }; /* Detect kind */ for (i = 0; i < ARRAY_SIZE(ref_kind); i++) { prefix = ref_kind[i].prefix; - if (strncmp(refname, prefix, ref_kind[i].pfxlen)) - continue; - kind = ref_kind[i].kind; - refname += ref_kind[i].pfxlen; - break; + if (skip_prefix(refname, prefix, &refname)) { + kind = ref_kind[i].kind; + break; + } } if (ARRAY_SIZE(ref_kind) <= i) return 0; @@ -797,7 +800,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_create = 0, list = 0; + int delete = 0, rename = 0, force = 0, list = 0; int verbose = 0, abbrev = -1, detached = 0; int reflog = 0, edit_description = 0; int quiet = 0, unset_upstream = 0; @@ -845,7 +848,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")), OPT_BOOL(0, "edit-description", &edit_description, N_("edit the description for the branch")), - OPT__FORCE(&force_create, N_("force creation (when already exists)")), + OPT__FORCE(&force, N_("force creation, move/rename, deletion")), { OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref, N_("commit"), N_("print only not merged branches"), @@ -869,16 +872,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix) track = git_branch_track; - head = resolve_refdup("HEAD", head_sha1, 0, NULL); + head = resolve_refdup("HEAD", 0, head_sha1, NULL); if (!head) die(_("Failed to resolve HEAD as a valid ref.")); - if (!strcmp(head, "HEAD")) { + if (!strcmp(head, "HEAD")) detached = 1; - } else { - if (!starts_with(head, "refs/heads/")) - die(_("HEAD not found below refs/heads!")); - head += 11; - } + else if (!skip_prefix(head, "refs/heads/", &head)) + die(_("HEAD not found below refs/heads!")); hashcpy(merge_filter_ref, head_sha1); @@ -891,7 +891,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (with_commit || merge_filter != NO_FILTER) list = 1; - if (!!delete + !!rename + !!force_create + !!new_upstream + + if (!!delete + !!rename + !!new_upstream + list + unset_upstream > 1) usage_with_options(builtin_branch_usage, options); @@ -904,6 +904,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix) colopts = 0; } + if (force) { + delete *= 2; + rename *= 2; + } + if (delete) { if (!argc) die(_("branch name required")); @@ -1020,7 +1025,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) branch_existed = ref_exists(branch->refname); create_branch(head, argv[0], (argc == 2) ? argv[1] : head, - force_create, reflog, 0, quiet, track); + force, reflog, 0, quiet, track); /* * We only show the instructions if the user gave us diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 707330499f..31b133b357 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -4,12 +4,8 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" -#include "exec_cmd.h" -#include "tag.h" -#include "tree.h" #include "builtin.h" #include "parse-options.h" -#include "diff.h" #include "userdiff.h" #include "streaming.h" @@ -79,11 +75,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) if (type_from_string(exp_type) == OBJ_BLOB) { unsigned char blob_sha1[20]; if (sha1_object_info(sha1, NULL) == OBJ_TAG) { - enum object_type type; - unsigned long size; char *buffer = read_sha1_file(sha1, &type, &size); - if (memcmp(buffer, "object ", 7) || - get_sha1_hex(buffer + 7, blob_sha1)) + const char *target; + if (!skip_prefix(buffer, "object ", &target) || + get_sha1_hex(target, blob_sha1)) die("%s not a valid tag", sha1_to_hex(sha1)); free(buffer); } else diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 05edd9e1df..031780f49e 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -5,7 +5,7 @@ * */ #include "builtin.h" -#include "cache.h" +#include "lockfile.h" #include "quote.h" #include "cache-tree.h" #include "parse-options.h" @@ -18,7 +18,7 @@ static char topath[4][TEMPORARY_FILENAME_LENGTH + 1]; static struct checkout state; -static void write_tempfile_record(const char *name, int prefix_length) +static void write_tempfile_record(const char *name, const char *prefix) { int i; @@ -35,14 +35,14 @@ static void write_tempfile_record(const char *name, int prefix_length) fputs(topath[checkout_stage], stdout); putchar('\t'); - write_name_quoted(name + prefix_length, stdout, line_termination); + write_name_quoted_relative(name, prefix, stdout, line_termination); for (i = 0; i < 4; i++) { topath[i][0] = 0; } } -static int checkout_file(const char *name, int prefix_length) +static int checkout_file(const char *name, const char *prefix) { int namelen = strlen(name); int pos = cache_name_pos(name, namelen); @@ -71,7 +71,7 @@ static int checkout_file(const char *name, int prefix_length) if (did_checkout) { if (to_tempfile) - write_tempfile_record(name, prefix_length); + write_tempfile_record(name, prefix); return errs > 0 ? -1 : 0; } @@ -106,7 +106,7 @@ static void checkout_all(const char *prefix, int prefix_length) if (last_ce && to_tempfile) { if (ce_namelen(last_ce) != ce_namelen(ce) || memcmp(last_ce->name, ce->name, ce_namelen(ce))) - write_tempfile_record(last_ce->name, prefix_length); + write_tempfile_record(last_ce->name, prefix); } if (checkout_entry(ce, &state, to_tempfile ? topath[ce_stage(ce)] : NULL) < 0) @@ -114,7 +114,7 @@ static void checkout_all(const char *prefix, int prefix_length) last_ce = ce; } if (last_ce && to_tempfile) - write_tempfile_record(last_ce->name, prefix_length); + write_tempfile_record(last_ce->name, prefix); if (errs) /* we have already done our error reporting. * exit with the same code as die(). @@ -248,7 +248,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) if (read_from_stdin) die("git checkout-index: don't mix '--stdin' and explicit filenames"); p = prefix_path(prefix, prefix_length, arg); - checkout_file(p, prefix_length); + checkout_file(p, prefix); if (p < arg || p > arg + strlen(arg)) free((char *)p); } @@ -268,7 +268,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) strbuf_swap(&buf, &nbuf); } p = prefix_path(prefix, prefix_length, buf.buf); - checkout_file(p, prefix_length); + checkout_file(p, prefix); if (p < buf.buf || p > buf.buf + buf.len) free((char *)p); } diff --git a/builtin/checkout.c b/builtin/checkout.c index 8afdf2b5c4..52d6cbb0a8 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1,5 +1,5 @@ -#include "cache.h" #include "builtin.h" +#include "lockfile.h" #include "parse-options.h" #include "refs.h" #include "commit.h" @@ -62,23 +62,41 @@ static int post_checkout_hook(struct commit *old, struct commit *new, } -static int update_some(const unsigned char *sha1, const char *base, int baselen, +static int update_some(const unsigned char *sha1, struct strbuf *base, const char *pathname, unsigned mode, int stage, void *context) { int len; struct cache_entry *ce; + int pos; if (S_ISDIR(mode)) return READ_TREE_RECURSIVE; - len = baselen + strlen(pathname); + len = base->len + strlen(pathname); ce = xcalloc(1, cache_entry_size(len)); hashcpy(ce->sha1, sha1); - memcpy(ce->name, base, baselen); - memcpy(ce->name + baselen, pathname, len - baselen); + memcpy(ce->name, base->buf, base->len); + memcpy(ce->name + base->len, pathname, len - base->len); ce->ce_flags = create_ce_flags(0) | CE_UPDATE; ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); + + /* + * If the entry is the same as the current index, we can leave the old + * entry in place. Whether it is UPTODATE or not, checkout_entry will + * do the right thing. + */ + pos = cache_name_pos(ce->name, ce->ce_namelen); + if (pos >= 0) { + struct cache_entry *old = active_cache[pos]; + if (ce->ce_mode == old->ce_mode && + !hashcmp(ce->sha1, old->sha1)) { + old->ce_flags |= CE_UPDATE; + free(ce); + return 0; + } + } + add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); return 0; } @@ -355,7 +373,7 @@ static int checkout_paths(const struct checkout_opts *opts, if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); - read_ref_full("HEAD", rev, 0, &flag); + read_ref_full("HEAD", 0, rev, &flag); head = lookup_commit_reference_gently(rev, 1); errs |= post_checkout_hook(head, head, 0); @@ -775,7 +793,7 @@ static int switch_branches(const struct checkout_opts *opts, unsigned char rev[20]; int flag, writeout_error = 0; memset(&old, 0, sizeof(old)); - old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag); + old.path = path_to_free = resolve_refdup("HEAD", 0, rev, &flag); old.commit = lookup_commit_reference_gently(rev, 1); if (!(flag & REF_ISSYMREF)) old.path = NULL; @@ -1072,7 +1090,7 @@ static int checkout_branch(struct checkout_opts *opts, unsigned char rev[20]; int flag; - if (!read_ref_full("HEAD", rev, 0, &flag) && + if (!read_ref_full("HEAD", 0, rev, &flag) && (flag & REF_ISSYMREF) && is_null_sha1(rev)) return switch_unborn_to_new_branch(opts); } @@ -1150,10 +1168,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) const char *argv0 = argv[0]; if (!argc || !strcmp(argv0, "--")) die (_("--track needs a branch name")); - if (starts_with(argv0, "refs/")) - argv0 += 5; - if (starts_with(argv0, "remotes/")) - argv0 += 8; + skip_prefix(argv0, "refs/", &argv0); + skip_prefix(argv0, "remotes/", &argv0); argv0 = strchr(argv0, '/'); if (!argv0 || !argv0[1]) die (_("Missing branch name; try -b")); diff --git a/builtin/clean.c b/builtin/clean.c index 3beeea6ec0..7e7fdcfe54 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -100,6 +100,8 @@ static int parse_clean_color_slot(const char *var) static int git_clean_config(const char *var, const char *value, void *cb) { + const char *slot_name; + if (starts_with(var, "column.")) return git_column_config(var, value, "clean", &colopts); @@ -109,15 +111,13 @@ static int git_clean_config(const char *var, const char *value, void *cb) clean_use_color = git_config_colorbool(var, value); return 0; } - if (starts_with(var, "color.interactive.")) { - int slot = parse_clean_color_slot(var + - strlen("color.interactive.")); + if (skip_prefix(var, "color.interactive.", &slot_name)) { + int slot = parse_clean_color_slot(slot_name); if (slot < 0) return 0; if (!value) return config_error_nonbool(var); - color_parse(value, var, clean_colors[slot]); - return 0; + return color_parse(value, clean_colors[slot]); } if (!strcmp(var, "clean.requireforce")) { @@ -321,7 +321,7 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen) switch (stuff->type) { default: - die("Bad type of menu_staff when print menu"); + die("Bad type of menu_stuff when print menu"); case MENU_STUFF_TYPE_MENU_ITEM: menu_item = (struct menu_item *)stuff->stuff; for (i = 0; i < stuff->nr; i++, menu_item++) { diff --git a/builtin/clone.c b/builtin/clone.c index 3927edfb6e..316c75d0b3 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -9,6 +9,7 @@ */ #include "builtin.h" +#include "lockfile.h" #include "parse-options.h" #include "fetch-pack.h" #include "refs.h" @@ -48,6 +49,7 @@ static int option_verbosity; static int option_progress = -1; static struct string_list option_config; static struct string_list option_reference; +static int option_dissociate; static int opt_parse_reference(const struct option *opt, const char *arg, int unset) { @@ -93,6 +95,8 @@ static struct option builtin_clone_options[] = { N_("create a shallow clone of that depth")), OPT_BOOL(0, "single-branch", &option_single_branch, N_("clone only one branch, HEAD or --branch")), + OPT_BOOL(0, "dissociate", &option_dissociate, + N_("use --reference only while cloning")), OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), N_("separate git dir from working tree")), OPT_STRING_LIST('c', "config", &option_config, N_("key=value"), @@ -390,7 +394,6 @@ static void clone_local(const char *src_repo, const char *dest_repo) static const char *junk_work_tree; static const char *junk_git_dir; -static pid_t junk_pid; static enum { JUNK_LEAVE_NONE, JUNK_LEAVE_REPO, @@ -417,8 +420,6 @@ static void remove_junk(void) break; } - if (getpid() != junk_pid) - return; if (junk_git_dir) { strbuf_addstr(&sb, junk_git_dir); remove_dir_recursively(&sb, 0); @@ -622,7 +623,7 @@ static int checkout(void) if (option_no_checkout) return 0; - head = resolve_refdup("HEAD", sha1, 1, NULL); + head = resolve_refdup("HEAD", RESOLVE_REF_READING, sha1, NULL); if (!head) { warning(_("remote HEAD refers to nonexistent ref, " "unable to checkout.\n")); @@ -737,6 +738,16 @@ static void write_refspec_config(const char *src_ref_prefix, strbuf_release(&value); } +static void dissociate_from_references(void) +{ + static const char* argv[] = { "repack", "-a", "-d", NULL }; + + if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN)) + die(_("cannot repack to clean up")); + if (unlink(git_path("objects/info/alternates")) && errno != ENOENT) + die_errno(_("cannot unlink temporary alternates file")); +} + int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; @@ -759,8 +770,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) struct refspec *refspec; const char *fetch_pattern; - junk_pid = getpid(); - packet_trace_identity("clone"); argc = parse_options(argc, argv, prefix, builtin_clone_options, builtin_clone_usage, 0); @@ -884,6 +893,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_reference.nr) setup_reference(); + else if (option_dissociate) { + warning(_("--dissociate given, but there is no --reference")); + option_dissociate = 0; + } fetch_pattern = value.buf; refspec = parse_fetch_refspec(1, &fetch_pattern); @@ -997,6 +1010,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) transport_unlock_pack(transport); transport_disconnect(transport); + if (option_dissociate) + dissociate_from_references(); + junk_mode = JUNK_LEAVE_REPO; err = checkout(); diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 8a66c74e0f..25aa2cdef3 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -66,10 +66,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) continue; } - if (!memcmp(arg, "-S", 2)) { - sign_commit = arg + 2; + if (skip_prefix(arg, "-S", &sign_commit)) continue; - } if (!strcmp(arg, "--no-gpg-sign")) { sign_commit = NULL; diff --git a/builtin/commit.c b/builtin/commit.c index b1cf284240..5cd1478ebf 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -6,6 +6,7 @@ */ #include "cache.h" +#include "lockfile.h" #include "cache-tree.h" #include "color.h" #include "dir.h" @@ -315,8 +316,8 @@ static void refresh_cache_or_die(int refresh_flags) die_resolve_conflict("commit"); } -static char *prepare_index(int argc, const char **argv, const char *prefix, - const struct commit *current_head, int is_status) +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 pathspec pathspec; @@ -341,7 +342,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, die(_("unable to create temporary index")); old_index_env = getenv(INDEX_ENVIRONMENT); - setenv(INDEX_ENVIRONMENT, index_lock.filename, 1); + setenv(INDEX_ENVIRONMENT, index_lock.filename.buf, 1); if (interactive_add(argc, argv, prefix, patch_interactive) != 0) die(_("interactive add failed")); @@ -352,7 +353,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, unsetenv(INDEX_ENVIRONMENT); discard_cache(); - read_cache_from(index_lock.filename); + read_cache_from(index_lock.filename.buf); if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) { if (reopen_lock_file(&index_lock) < 0) die(_("unable to write index file")); @@ -362,7 +363,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, warning(_("Failed to update main cache tree")); commit_style = COMMIT_NORMAL; - return index_lock.filename; + return index_lock.filename.buf; } /* @@ -385,7 +386,7 @@ static 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 index_lock.filename; + return index_lock.filename.buf; } /* @@ -472,9 +473,9 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, die(_("unable to write temporary index file")); discard_cache(); - read_cache_from(false_lock.filename); + read_cache_from(false_lock.filename.buf); - return false_lock.filename; + return false_lock.filename.buf; } static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn, @@ -521,6 +522,12 @@ static int is_a_merge(const struct commit *current_head) return !!(current_head->parents && current_head->parents->next); } +static void assert_split_ident(struct ident_split *id, const struct strbuf *buf) +{ + if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin) + die("BUG: unable to parse our own ident: %s", buf->buf); +} + static void export_one(const char *var, const char *s, const char *e, int hack) { struct strbuf buf = STRBUF_INIT; @@ -531,20 +538,6 @@ static void export_one(const char *var, const char *s, const char *e, int hack) strbuf_release(&buf); } -static int sane_ident_split(struct ident_split *person) -{ - if (!person->name_begin || !person->name_end || - person->name_begin == person->name_end) - return 0; /* no human readable name */ - if (!person->mail_begin || !person->mail_end || - person->mail_begin == person->mail_end) - return 0; /* no usable mail */ - if (!person->date_begin || !person->date_end || - !person->tz_begin || !person->tz_end) - return 0; - return 1; -} - static int parse_force_date(const char *in, struct strbuf *out) { strbuf_addch(out, '@'); @@ -616,25 +609,15 @@ static void determine_author_info(struct strbuf *author_ident) } strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT)); - if (!split_ident_line(&author, author_ident->buf, author_ident->len) && - sane_ident_split(&author)) { - export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0); - export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0); - export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@'); - } - + assert_split_ident(&author, author_ident); + export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0); + export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0); + export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@'); free(name); free(email); free(date); } -static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf) -{ - if (split_ident_line(id, buf->buf, buf->len) || - !sane_ident_split(id)) - die(_("Malformed ident string: '%s'"), buf->buf); -} - static int author_date_is_interesting(void) { return author_message || force_date; @@ -793,32 +776,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (clean_message_contents) stripspace(&sb, 0); - if (signoff) { - /* - * See if we have a Conflicts: block at the end. If yes, count - * its size, so we can ignore it. - */ - int ignore_footer = 0; - int i, eol, previous = 0; - const char *nl; - - for (i = 0; i < sb.len; i++) { - nl = memchr(sb.buf + i, '\n', sb.len - i); - if (nl) - eol = nl - sb.buf; - else - eol = sb.len; - if (starts_with(sb.buf + previous, "\nConflicts:\n")) { - ignore_footer = sb.len - previous; - break; - } - while (i < eol) - i++; - previous = eol; - } - - append_signoff(&sb, ignore_footer, 0); - } + if (signoff) + append_signoff(&sb, ignore_non_trailer(&sb), 0); if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno(_("could not write commit template")); @@ -873,8 +832,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix, status_printf_ln(s, GIT_COLOR_NORMAL, "%s", only_include_assumed); - split_ident_or_die(&ai, author_ident); - split_ident_or_die(&ci, &committer_ident); + /* + * These should never fail because they come from our own + * fmt_ident. They may fail the sane_ident test, but we know + * that the name and mail pointers will at least be valid, + * which is enough for our tests and printing here. + */ + assert_split_ident(&ai, author_ident); + assert_split_ident(&ci, &committer_ident); if (ident_cmp(&ai, &ci)) status_printf_ln(s, GIT_COLOR_NORMAL, @@ -1265,22 +1230,21 @@ static int dry_run_commit(int argc, const char **argv, const char *prefix, return commitable ? 0 : 1; } -static int parse_status_slot(const char *var, int offset) +static int parse_status_slot(const char *slot) { - if (!strcasecmp(var+offset, "header")) + if (!strcasecmp(slot, "header")) return WT_STATUS_HEADER; - if (!strcasecmp(var+offset, "branch")) + if (!strcasecmp(slot, "branch")) return WT_STATUS_ONBRANCH; - if (!strcasecmp(var+offset, "updated") - || !strcasecmp(var+offset, "added")) + if (!strcasecmp(slot, "updated") || !strcasecmp(slot, "added")) return WT_STATUS_UPDATED; - if (!strcasecmp(var+offset, "changed")) + if (!strcasecmp(slot, "changed")) return WT_STATUS_CHANGED; - if (!strcasecmp(var+offset, "untracked")) + if (!strcasecmp(slot, "untracked")) return WT_STATUS_UNTRACKED; - if (!strcasecmp(var+offset, "nobranch")) + if (!strcasecmp(slot, "nobranch")) return WT_STATUS_NOBRANCH; - if (!strcasecmp(var+offset, "unmerged")) + if (!strcasecmp(slot, "unmerged")) return WT_STATUS_UNMERGED; return -1; } @@ -1288,6 +1252,7 @@ static int parse_status_slot(const char *var, int offset) static int git_status_config(const char *k, const char *v, void *cb) { struct wt_status *s = cb; + const char *slot_name; if (starts_with(k, "column.")) return git_column_config(k, v, "status", &s->colopts); @@ -1317,14 +1282,14 @@ static int git_status_config(const char *k, const char *v, void *cb) s->display_comment_prefix = git_config_bool(k, v); return 0; } - if (starts_with(k, "status.color.") || starts_with(k, "color.status.")) { - int slot = parse_status_slot(k, 13); + if (skip_prefix(k, "status.color.", &slot_name) || + skip_prefix(k, "color.status.", &slot_name)) { + int slot = parse_status_slot(slot_name); if (slot < 0) return 0; if (!v) return config_error_nonbool(k); - color_parse(v, k, s->color_palette[slot]); - return 0; + return color_parse(v, s->color_palette[slot]); } if (!strcmp(k, "status.relativepaths")) { s->relative_paths = git_config_bool(k, v); @@ -1506,14 +1471,12 @@ static void print_summary(const char *prefix, const unsigned char *sha1, rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); - head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL); - printf("[%s%s ", - starts_with(head, "refs/heads/") ? - head + 11 : - !strcmp(head, "HEAD") ? - _("detached HEAD") : - head, - initial_commit ? _(" (root-commit)") : ""); + head = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL); + if (!strcmp(head, "HEAD")) + head = _("detached HEAD"); + else + skip_prefix(head, "refs/heads/", &head); + printf("[%s%s ", head, initial_commit ? _(" (root-commit)") : ""); if (!log_tree_commit(&rev, commit)) { rev.always_show_header = 1; @@ -1804,8 +1767,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) ref_transaction_update(transaction, "HEAD", sha1, current_head ? current_head->object.sha1 : NULL, - 0, !!current_head, &err) || - ref_transaction_commit(transaction, sb.buf, &err)) { + 0, !!current_head, sb.buf, &err) || + ref_transaction_commit(transaction, &err)) { rollback_index_files(); die("%s", err.buf); } diff --git a/builtin/config.c b/builtin/config.c index 37305e93e9..15a7bea936 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -69,8 +69,8 @@ static struct option builtin_config_options[] = { OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST), OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), - OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")), - OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")), + OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR), + OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL), OPT_GROUP(N_("Type")), OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL), OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT), @@ -296,21 +296,25 @@ static int git_get_color_config(const char *var, const char *value, void *cb) if (!strcmp(var, get_color_slot)) { if (!value) config_error_nonbool(var); - color_parse(value, var, parsed_color); + if (color_parse(value, parsed_color) < 0) + return -1; get_color_found = 1; } return 0; } -static void get_color(const char *def_color) +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, respect_includes); - if (!get_color_found && def_color) - color_parse(def_color, "command line", parsed_color); + if (!get_color_found && def_color) { + if (color_parse(def_color, parsed_color) < 0) + die(_("unable to parse default color value")); + } fputs(parsed_color, stdout); } @@ -330,8 +334,9 @@ static int git_get_colorbool_config(const char *var, const char *value, return 0; } -static int get_colorbool(int print) +static int get_colorbool(const char *var, int print) { + get_colorbool_slot = var; get_colorbool_found = -1; get_diff_color_found = -1; get_color_ui_found = -1; @@ -529,12 +534,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_with_options(builtin_config_usage, builtin_config_options); } - if (get_color_slot) - actions |= ACTION_GET_COLOR; - if (get_colorbool_slot) - actions |= ACTION_GET_COLORBOOL; - - if ((get_color_slot || get_colorbool_slot) && types) { + if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && types) { error("--get-color and variable type are incoherent"); usage_with_options(builtin_config_usage, builtin_config_options); } @@ -565,8 +565,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) } } else if (actions == ACTION_EDIT) { - const char *config_file = given_config_source.file ? - given_config_source.file : git_path("config"); + char *config_file; + check_argc(argc, 0, 0); if (!given_config_source.file && nongit) die("not in a git directory"); @@ -575,6 +575,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (given_config_source.blob) die("editing blobs is not supported"); git_config(git_default_config, NULL); + config_file = xstrdup(given_config_source.file ? + given_config_source.file : git_path("config")); if (use_global_config) { int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666); if (fd) { @@ -587,6 +589,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) die_errno(_("cannot create configuration file %s"), config_file); } launch_editor(config_file, NULL, NULL); + free(config_file); } else if (actions == ACTION_SET) { int ret; @@ -680,12 +683,14 @@ int cmd_config(int argc, const char **argv, const char *prefix) die("No such section!"); } else if (actions == ACTION_GET_COLOR) { - get_color(argv[0]); + check_argc(argc, 1, 2); + get_color(argv[0], argv[1]); } else if (actions == ACTION_GET_COLORBOOL) { - if (argc == 1) - color_stdout_is_tty = git_config_bool("command line", argv[0]); - return get_colorbool(argc != 0); + check_argc(argc, 1, 2); + if (argc == 2) + color_stdout_is_tty = git_config_bool("command line", argv[1]); + return get_colorbool(argv[0], argc == 2); } return 0; diff --git a/builtin/count-objects.c b/builtin/count-objects.c index a7f70cb858..e47ef0b1af 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -11,6 +11,9 @@ static unsigned long garbage; static off_t size_garbage; +static int verbose; +static unsigned long loose, packed, packed_loose; +static off_t loose_size; static void real_report_garbage(const char *desc, const char *path) { @@ -21,61 +24,31 @@ static void real_report_garbage(const char *desc, const char *path) garbage++; } -static void count_objects(DIR *d, char *path, int len, int verbose, - unsigned long *loose, - off_t *loose_size, - unsigned long *packed_loose) +static void loose_garbage(const char *path) { - struct dirent *ent; - while ((ent = readdir(d)) != NULL) { - char hex[41]; - unsigned char sha1[20]; - const char *cp; - int bad = 0; + if (verbose) + report_garbage("garbage found", path); +} - if (is_dot_or_dotdot(ent->d_name)) - continue; - for (cp = ent->d_name; *cp; cp++) { - int ch = *cp; - if (('0' <= ch && ch <= '9') || - ('a' <= ch && ch <= 'f')) - continue; - bad = 1; - break; - } - if (cp - ent->d_name != 38) - bad = 1; - else { - struct stat st; - memcpy(path + len + 3, ent->d_name, 38); - path[len + 2] = '/'; - path[len + 41] = 0; - if (lstat(path, &st) || !S_ISREG(st.st_mode)) - bad = 1; - else - (*loose_size) += xsize_t(on_disk_bytes(st)); - } - if (bad) { - if (verbose) { - struct strbuf sb = STRBUF_INIT; - strbuf_addf(&sb, "%.*s/%s", - len + 2, path, ent->d_name); - report_garbage("garbage found", sb.buf); - strbuf_release(&sb); - } - continue; - } - (*loose)++; - if (!verbose) - continue; - memcpy(hex, path+len, 2); - memcpy(hex+2, ent->d_name, 38); - hex[40] = 0; - if (get_sha1_hex(hex, sha1)) - die("internal error"); - if (has_sha1_pack(sha1)) - (*packed_loose)++; +static int count_loose(const unsigned char *sha1, const char *path, void *data) +{ + struct stat st; + + if (lstat(path, &st) || !S_ISREG(st.st_mode)) + loose_garbage(path); + else { + loose_size += on_disk_bytes(st); + loose++; + if (verbose && has_sha1_pack(sha1)) + packed_loose++; } + return 0; +} + +static int count_cruft(const char *basename, const char *path, void *data) +{ + loose_garbage(path); + return 0; } static char const * const count_objects_usage[] = { @@ -85,12 +58,7 @@ static char const * const count_objects_usage[] = { int cmd_count_objects(int argc, const char **argv, const char *prefix) { - int i, verbose = 0, human_readable = 0; - const char *objdir = get_object_directory(); - int len = strlen(objdir); - char *path = xmalloc(len + 50); - unsigned long loose = 0, packed = 0, packed_loose = 0; - off_t loose_size = 0; + int human_readable = 0; struct option opts[] = { OPT__VERBOSE(&verbose, N_("be verbose")), OPT_BOOL('H', "human-readable", &human_readable, @@ -104,19 +72,10 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) usage_with_options(count_objects_usage, opts); if (verbose) report_garbage = real_report_garbage; - memcpy(path, objdir, len); - if (len && objdir[len-1] != '/') - path[len++] = '/'; - for (i = 0; i < 256; i++) { - DIR *d; - sprintf(path + len, "%02x", i); - d = opendir(path); - if (!d) - continue; - count_objects(d, path, len, verbose, - &loose, &loose_size, &packed_loose); - closedir(d); - } + + for_each_loose_file_in_objdir(get_object_directory(), + count_loose, count_cruft, NULL, NULL); + if (verbose) { struct packed_git *p; unsigned long num_pack = 0; diff --git a/builtin/describe.c b/builtin/describe.c index ee6a3b998f..9103193b4f 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "lockfile.h" #include "commit.h" #include "tag.h" #include "refs.h" diff --git a/builtin/diff.c b/builtin/diff.c index 0f247d2400..4326fa56bf 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -4,6 +4,7 @@ * Copyright (c) 2006 Junio C Hamano */ #include "cache.h" +#include "lockfile.h" #include "color.h" #include "commit.h" #include "blob.h" diff --git a/builtin/fetch.c b/builtin/fetch.c index 159fb7e916..7b84d35d83 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -68,7 +68,7 @@ static int git_fetch_config(const char *k, const char *v, void *cb) fetch_prune_config = git_config_bool(k, v); return 0; } - return 0; + return git_default_config(k, v, cb); } static int parse_refmap_arg(const struct option *opt, const char *arg, int unset) @@ -404,23 +404,37 @@ static int s_update_ref(const char *action, { char msg[1024]; char *rla = getenv("GIT_REFLOG_ACTION"); - static struct ref_lock *lock; + struct ref_transaction *transaction; + struct strbuf err = STRBUF_INIT; + int ret, df_conflict = 0; if (dry_run) return 0; if (!rla) rla = default_rla.buf; snprintf(msg, sizeof(msg), "%s: %s", rla, action); - lock = lock_any_ref_for_update(ref->name, - check_old ? ref->old_sha1 : NULL, - 0, NULL); - if (!lock) - return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT : - STORE_REF_ERROR_OTHER; - if (write_ref_sha1(lock, ref->new_sha1, msg) < 0) - return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT : - STORE_REF_ERROR_OTHER; + + transaction = ref_transaction_begin(&err); + if (!transaction || + ref_transaction_update(transaction, ref->name, ref->new_sha1, + ref->old_sha1, 0, check_old, msg, &err)) + goto fail; + + ret = ref_transaction_commit(transaction, &err); + if (ret) { + df_conflict = (ret == TRANSACTION_NAME_CONFLICT); + goto fail; + } + + ref_transaction_free(transaction); + strbuf_release(&err); return 0; +fail: + ref_transaction_free(transaction); + error("%s", err.buf); + strbuf_release(&err); + return df_conflict ? STORE_REF_ERROR_DF_CONFLICT + : STORE_REF_ERROR_OTHER; } #define REFCOL_WIDTH 10 diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 79df05ef52..af7919e51e 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -216,8 +216,7 @@ static void add_branch_desc(struct strbuf *out, const char *name) strbuf_addf(out, " : %.*s", (int)(ep - bp), bp); bp = ep; } - if (out->buf[out->len - 1] != '\n') - strbuf_addch(out, '\n'); + strbuf_complete_line(out); } strbuf_release(&desc); } @@ -602,7 +601,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out, /* get current branch */ current_branch = current_branch_to_free = - resolve_refdup("HEAD", head_sha1, 1, NULL); + resolve_refdup("HEAD", RESOLVE_REF_READING, head_sha1, NULL); if (!current_branch) die("No current branch"); if (starts_with(current_branch, "refs/heads/")) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index fda0f04712..a0123f6146 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -635,7 +635,8 @@ static void populate_value(struct refinfo *ref) if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) { unsigned char unused1[20]; - ref->symref = resolve_refdup(ref->refname, unused1, 1, NULL); + ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING, + unused1, NULL); if (!ref->symref) ref->symref = ""; } @@ -671,7 +672,8 @@ static void populate_value(struct refinfo *ref) } else if (starts_with(name, "color:")) { char color[COLOR_MAXLEN] = ""; - color_parse(name + 6, "--format", color); + if (color_parse(name + 6, color) < 0) + die(_("unable to parse format")); v->s = xstrdup(color); continue; } else if (!strcmp(name, "flag")) { @@ -693,7 +695,8 @@ static void populate_value(struct refinfo *ref) const char *head; unsigned char sha1[20]; - head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); + head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, + sha1, NULL); if (!strcmp(ref->refname, head)) v->s = "*"; else @@ -714,7 +717,10 @@ static void populate_value(struct refinfo *ref) starts_with(name, "upstream")) { char buf[40]; - stat_tracking_info(branch, &num_ours, &num_theirs); + if (stat_tracking_info(branch, &num_ours, + &num_theirs) != 1) + continue; + if (!num_ours && !num_theirs) v->s = ""; else if (!num_ours) { @@ -732,7 +738,11 @@ static void populate_value(struct refinfo *ref) } else if (!strcmp(formatp, "trackshort") && starts_with(name, "upstream")) { assert(branch); - stat_tracking_info(branch, &num_ours, &num_theirs); + + if (stat_tracking_info(branch, &num_ours, + &num_theirs) != 1) + continue; + if (!num_ours && !num_theirs) v->s = "="; else if (!num_ours) @@ -837,6 +847,11 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f struct refinfo *ref; int cnt; + if (flag & REF_BAD_NAME) { + warning("ignoring ref with broken name %s", refname); + return 0; + } + if (*cb->grab_pattern) { const char **pattern; int namelen = strlen(refname); @@ -1004,7 +1019,8 @@ static void show_ref(struct refinfo *info, const char *format, int quote_style) struct atom_value resetv; char color[COLOR_MAXLEN] = ""; - color_parse("reset", "--format", color); + if (color_parse("reset", color) < 0) + die("BUG: couldn't parse 'reset' as a color"); resetv.s = color; print_value(&resetv, quote_style); } @@ -1066,7 +1082,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) OPT_BIT(0 , "python", "e_style, N_("quote placeholders suitably for python"), QUOTE_PYTHON), OPT_BIT(0 , "tcl", "e_style, - N_("quote placeholders suitably for tcl"), QUOTE_TCL), + N_("quote placeholders suitably for Tcl"), QUOTE_TCL), OPT_GROUP(""), OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), diff --git a/builtin/fsck.c b/builtin/fsck.c index e9ba576c1f..a27515aeaa 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -556,7 +556,7 @@ static int fsck_head_link(void) if (verbose) fprintf(stderr, "Checking HEAD link\n"); - head_points_at = resolve_ref_unsafe("HEAD", head_sha1, 0, &flag); + head_points_at = resolve_ref_unsafe("HEAD", 0, head_sha1, &flag); if (!head_points_at) return error("Invalid HEAD"); if (!strcmp(head_points_at, "HEAD")) diff --git a/builtin/gc.c b/builtin/gc.c index ced1456e1e..005adbebea 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -11,7 +11,7 @@ */ #include "builtin.h" -#include "cache.h" +#include "lockfile.h" #include "parse-options.h" #include "run-command.h" #include "sigchain.h" diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c index aa72596083..6f4147ad02 100644 --- a/builtin/get-tar-commit-id.c +++ b/builtin/get-tar-commit-id.c @@ -19,6 +19,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix) char buffer[HEADERSIZE]; struct ustar_header *header = (struct ustar_header *)buffer; char *content = buffer + RECORDSIZE; + const char *comment; ssize_t n; if (argc != 1) @@ -29,10 +30,10 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix) die("git get-tar-commit-id: read error"); if (header->typeflag[0] != 'g') return 1; - if (memcmp(content, "52 comment=", 11)) + if (!skip_prefix(content, "52 comment=", &comment)) return 1; - n = write_in_full(1, content + 11, 41); + n = write_in_full(1, comment, 41); if (n < 41) die_errno("git get-tar-commit-id: write error"); diff --git a/builtin/grep.c b/builtin/grep.c index c86a142f30..4063882f06 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -456,10 +456,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, } static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, - struct object *obj, const char *name, struct object_context *oc) + struct object *obj, const char *name, const char *path) { if (obj->type == OBJ_BLOB) - return grep_sha1(opt, obj->sha1, name, 0, oc ? oc->path : NULL); + return grep_sha1(opt, obj->sha1, name, 0, path); if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) { struct tree_desc tree; void *data; @@ -501,7 +501,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, for (i = 0; i < nr; i++) { struct object *real_obj; real_obj = deref_tag(list->objects[i].item, NULL, 0); - if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].context)) { + if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) { hit = 1; if (opt->status_only) break; @@ -821,7 +821,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) struct object *object = parse_object_or_die(sha1, arg); if (!seen_dashdash) verify_non_filename(prefix, arg); - add_object_array_with_context(object, arg, &list, xmemdupz(&oc, sizeof(struct object_context))); + add_object_array_with_path(object, arg, &list, oc.mode, oc.path); continue; } if (!strcmp(arg, "--")) { diff --git a/builtin/help.c b/builtin/help.c index 8343b4027d..e78c135e01 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -321,16 +321,18 @@ static void setup_man_path(void) { struct strbuf new_path = STRBUF_INIT; const char *old_path = getenv("MANPATH"); + char *git_man_path = system_path(GIT_MAN_PATH); /* We should always put ':' after our path. If there is no * old_path, the ':' at the end will let 'man' to try * system-wide paths after ours to find the manual page. If * there is old_path, we need ':' as delimiter. */ - strbuf_addstr(&new_path, system_path(GIT_MAN_PATH)); + strbuf_addstr(&new_path, git_man_path); strbuf_addch(&new_path, ':'); if (old_path) strbuf_addstr(&new_path, old_path); + free(git_man_path); setenv("MANPATH", new_path.buf, 1); strbuf_release(&new_path); @@ -380,8 +382,10 @@ static void show_info_page(const char *git_cmd) static void get_html_page_path(struct strbuf *page_path, const char *page) { struct stat st; + char *to_free = NULL; + if (!html_path) - html_path = system_path(GIT_HTML_PATH); + html_path = to_free = system_path(GIT_HTML_PATH); /* Check that we have a git documentation directory. */ if (!strstr(html_path, "://")) { @@ -392,6 +396,7 @@ static void get_html_page_path(struct strbuf *page_path, const char *page) strbuf_init(page_path, 0); strbuf_addf(page_path, "%s/%s.html", html_path, page); + free(to_free); } /* @@ -421,6 +426,7 @@ static struct { const char *help; } common_guides[] = { { "attributes", N_("Defining attributes per path") }, + { "everyday", N_("Everyday Git With 20 Commands Or So") }, { "glossary", N_("A Git glossary") }, { "ignore", N_("Specifies intentionally untracked files to ignore") }, { "modules", N_("Defining submodule properties") }, diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 792c66ca59..4632117671 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -185,6 +185,9 @@ static void cleanup_thread(void) #define deepest_delta_lock() #define deepest_delta_unlock() +#define type_cas_lock() +#define type_cas_unlock() + #endif @@ -444,7 +447,7 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size, if (type == OBJ_BLOB && size > big_file_threshold) buf = fixed_buf; else - buf = xmalloc(size); + buf = xmallocz(size); memset(&stream, 0, sizeof(stream)); git_inflate_init(&stream); @@ -549,7 +552,7 @@ static void *unpack_data(struct object_entry *obj, git_zstream stream; int status; - data = xmalloc(consume ? 64*1024 : obj->size); + data = xmallocz(consume ? 64*1024 : obj->size); inbuf = xmalloc((len < 64*1024) ? len : 64*1024); memset(&stream, 0, sizeof(stream)); diff --git a/builtin/init-db.c b/builtin/init-db.c index 587a5055ed..9966522b4a 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -119,15 +119,18 @@ static void copy_templates(const char *template_dir) DIR *dir; const char *git_dir = get_git_dir(); int len = strlen(git_dir); + char *to_free = NULL; if (!template_dir) template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); if (!template_dir) template_dir = init_db_template_dir; if (!template_dir) - template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR); - if (!template_dir[0]) + template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR); + if (!template_dir[0]) { + free(to_free); return; + } template_len = strlen(template_dir); if (PATH_MAX <= (template_len+strlen("/config"))) die(_("insanely long template path %s"), template_dir); @@ -139,7 +142,7 @@ static void copy_templates(const char *template_dir) dir = opendir(template_path); if (!dir) { warning(_("templates not found %s"), template_dir); - return; + goto free_return; } /* Make sure that template is from the correct vintage */ @@ -155,8 +158,7 @@ static void copy_templates(const char *template_dir) "a wrong format version %d from '%s'"), repository_format_version, template_dir); - closedir(dir); - return; + goto close_free_return; } memcpy(path, git_dir, len); @@ -166,7 +168,10 @@ static void copy_templates(const char *template_dir) copy_templates_1(path, len, template_path, template_len, dir); +close_free_return: closedir(dir); +free_return: + free(to_free); } static int git_init_db_config(const char *k, const char *v, void *cb) @@ -254,7 +259,10 @@ static int create_default_files(const char *template_path) struct stat st2; filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) && !lstat(path, &st2) && - st1.st_mode != st2.st_mode); + st1.st_mode != st2.st_mode && + !chmod(path, st1.st_mode)); + if (filemode && !reinit && (st1.st_mode & S_IXUSR)) + filemode = 0; } git_config_set("core.filemode", filemode ? "true" : "false"); diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c new file mode 100644 index 0000000000..46838d24a9 --- /dev/null +++ b/builtin/interpret-trailers.c @@ -0,0 +1,44 @@ +/* + * Builtin "git interpret-trailers" + * + * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org> + * + */ + +#include "cache.h" +#include "builtin.h" +#include "parse-options.h" +#include "string-list.h" +#include "trailer.h" + +static const char * const git_interpret_trailers_usage[] = { + N_("git interpret-trailers [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"), + NULL +}; + +int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) +{ + int trim_empty = 0; + struct string_list trailers = STRING_LIST_INIT_DUP; + + struct option options[] = { + OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")), + OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"), + N_("trailer(s) to add")), + OPT_END() + }; + + argc = parse_options(argc, argv, prefix, options, + git_interpret_trailers_usage, 0); + + if (argc) { + int i; + for (i = 0; i < argc; i++) + process_trailers(argv[i], trim_empty, &trailers); + } else + process_trailers(NULL, trim_empty, &trailers); + + string_list_clear(&trailers, 0); + + return 0; +} diff --git a/builtin/log.c b/builtin/log.c index 2fb34c7de9..923ffe72ce 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -38,8 +38,8 @@ static const char *fmt_patch_subject_prefix = "PATCH"; static const char *fmt_pretty; static const char * const builtin_log_usage[] = { - N_("git log [<options>] [<revision range>] [[--] <path>...]\n") - N_(" or: git show [options] <object>..."), + N_("git log [<options>] [<revision range>] [[--] <path>...]"), + N_("git show [options] <object>..."), NULL }; @@ -368,6 +368,8 @@ static int cmd_log_walk(struct rev_info *rev) static int git_log_config(const char *var, const char *value, void *cb) { + const char *slot_name; + if (!strcmp(var, "format.pretty")) return git_config_string(&fmt_pretty, var, value); if (!strcmp(var, "format.subjectprefix")) @@ -388,8 +390,8 @@ static int git_log_config(const char *var, const char *value, void *cb) default_show_root = git_config_bool(var, value); return 0; } - if (starts_with(var, "color.decorate.")) - return parse_decorate_color_config(var, 15, value); + if (skip_prefix(var, "color.decorate.", &slot_name)) + return parse_decorate_color_config(var, slot_name, value); if (!strcmp(var, "log.mailmap")) { use_mailmap_config = git_config_bool(var, value); return 0; @@ -487,7 +489,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev) } static int show_tree_object(const unsigned char *sha1, - const char *base, int baselen, + struct strbuf *base, const char *pathname, unsigned mode, int stage, void *context) { printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : ""); @@ -1398,7 +1400,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (check_head) { unsigned char sha1[20]; const char *ref, *v; - ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL); + ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, + sha1, NULL); if (ref && skip_prefix(ref, "refs/heads/", &v)) branch_name = xstrdup(v); else diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 51184dfa2e..3b04a0f082 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -61,10 +61,11 @@ static int show_recursive(const char *base, int baselen, const char *pathname) } } -static int show_tree(const unsigned char *sha1, const char *base, int baselen, +static int show_tree(const unsigned char *sha1, struct strbuf *base, const char *pathname, unsigned mode, int stage, void *context) { int retval = 0; + int baselen; const char *type = blob_type; if (S_ISGITLINK(mode)) { @@ -79,7 +80,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, */ type = commit_type; } else if (S_ISDIR(mode)) { - if (show_recursive(base, baselen, pathname)) { + if (show_recursive(base->buf, base->len, pathname)) { retval = READ_TREE_RECURSIVE; if (!(ls_options & LS_SHOW_TREES)) return retval; @@ -89,10 +90,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, else if (ls_options & LS_TREE_ONLY) return 0; - if (chomp_prefix && - (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix))) - return 0; - if (!(ls_options & LS_NAME_ONLY)) { if (ls_options & LS_SHOW_SIZE) { char size_text[24]; @@ -112,8 +109,12 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, printf("%06o %s %s\t", mode, type, find_unique_abbrev(sha1, abbrev)); } - write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix, - pathname, stdout, line_termination); + baselen = base->len; + strbuf_addstr(base, pathname); + write_name_quoted_relative(base->buf, + chomp_prefix ? ls_tree_prefix : NULL, + stdout, line_termination); + strbuf_setlen(base, baselen); return retval; } @@ -173,7 +174,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) * cannot be lifted until it is converted to use * match_pathspec() or tree_entry_interesting() */ - parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE, + parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE | + PATHSPEC_EXCLUDE, PATHSPEC_PREFER_CWD, prefix, argv + 1); for (i = 0; i < pathspec.nr; i++) diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c index 6a14d2985d..c8a47c173d 100644 --- a/builtin/mailinfo.c +++ b/builtin/mailinfo.c @@ -15,6 +15,7 @@ static const char *metainfo_charset; static struct strbuf line = STRBUF_INIT; static struct strbuf name = STRBUF_INIT; static struct strbuf email = STRBUF_INIT; +static char *message_id; static enum { TE_DONTCARE, TE_QP, TE_BASE64 @@ -24,6 +25,7 @@ static struct strbuf charset = STRBUF_INIT; static int patch_lines; static struct strbuf **p_hdr_data, **s_hdr_data; static int use_scissors; +static int add_message_id; static int use_inbody_headers = 1; #define MAX_HDR_PARSED 10 @@ -198,6 +200,12 @@ static void handle_content_type(struct strbuf *line) } } +static void handle_message_id(const struct strbuf *line) +{ + if (add_message_id) + message_id = strdup(line->buf); +} + static void handle_content_transfer_encoding(const struct strbuf *line) { if (strcasestr(line->buf, "base64")) @@ -342,6 +350,14 @@ static int check_header(const struct strbuf *line, ret = 1; goto check_header_out; } + if (cmp_header(line, "Message-Id")) { + len = strlen("Message-Id: "); + strbuf_add(&sb, line->buf + len, line->len - len); + decode_header(&sb); + handle_message_id(&sb); + ret = 1; + goto check_header_out; + } /* for inbody stuff */ if (starts_with(line->buf, ">From") && isspace(line->buf[5])) { @@ -816,6 +832,8 @@ static int handle_commit_msg(struct strbuf *line) } if (patchbreak(line)) { + if (message_id) + fprintf(cmitmsg, "Message-Id: %s\n", message_id); fclose(cmitmsg); cmitmsg = NULL; return 1; @@ -1013,7 +1031,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused) } static const char mailinfo_usage[] = - "git mailinfo [-k|-b] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info"; + "git mailinfo [-k|-b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info"; int cmd_mailinfo(int argc, const char **argv, const char *prefix) { @@ -1032,6 +1050,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix) keep_subject = 1; else if (!strcmp(argv[1], "-b")) keep_non_patch_brackets_in_subject = 1; + else if (!strcmp(argv[1], "-m") || !strcmp(argv[1], "--message-id")) + add_message_id = 1; else if (!strcmp(argv[1], "-u")) metainfo_charset = def_charset; else if (!strcmp(argv[1], "-n")) diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c index 763cda098c..8e02ea109a 100644 --- a/builtin/mailsplit.c +++ b/builtin/mailsplit.c @@ -59,7 +59,6 @@ static int split_one(FILE *mbox, const char *name, int allow_bare) int is_bare = !is_from_line(buf.buf, buf.len); if (is_bare && !allow_bare) { - unlink(name); fprintf(stderr, "corrupt mailbox\n"); exit(1); } diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 0ecde8da30..fdebef6fa1 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -10,7 +10,7 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all) { struct commit_list *result; - result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0); + result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1); if (!result) return 1; @@ -176,7 +176,7 @@ static int handle_fork_point(int argc, const char **argv) for (i = 0; i < revs.nr; i++) revs.commit[i]->object.flags &= ~TMP_MARK; - bases = get_merge_bases_many(derived, revs.nr, revs.commit, 0); + bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit); /* * There should be one and only one merge base, when we found diff --git a/builtin/merge.c b/builtin/merge.c index dff043dac3..c638fd5a9a 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -9,6 +9,7 @@ #include "cache.h" #include "parse-options.h" #include "builtin.h" +#include "lockfile.h" #include "run-command.h" #include "diff.h" #include "refs.h" @@ -28,6 +29,7 @@ #include "remote.h" #include "fmt-merge-msg.h" #include "gpg-interface.h" +#include "sequencer.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -656,19 +658,18 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, struct commit_list *remoteheads, struct commit *head, const char *head_arg) { - struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + static struct lock_file lock; - hold_locked_index(lock, 1); + hold_locked_index(&lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && - write_locked_index(&the_index, lock, COMMIT_LOCK)) + write_locked_index(&the_index, &lock, COMMIT_LOCK)) return error(_("Unable to write index.")); - rollback_lock_file(lock); + rollback_lock_file(&lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean, x; struct commit *result; - struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); struct commit_list *reversed = NULL; struct merge_options o; struct commit_list *j; @@ -696,13 +697,13 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); - hold_locked_index(lock, 1); + hold_locked_index(&lock, 1); clean = merge_recursive(&o, head, remoteheads->item, reversed, &result); if (active_cache_changed && - write_locked_index(&the_index, lock, COMMIT_LOCK)) + write_locked_index(&the_index, &lock, COMMIT_LOCK)) die (_("unable to write %s"), get_index_file()); - rollback_lock_file(lock); + rollback_lock_file(&lock); return clean ? 0 : 1; } else { return try_merge_command(strategy, xopts_nr, xopts, @@ -880,28 +881,20 @@ static int finish_automerge(struct commit *head, return 0; } -static int suggest_conflicts(int renormalizing) +static int suggest_conflicts(void) { const char *filename; FILE *fp; - int pos; + 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); - fprintf(fp, "\nConflicts:\n"); - for (pos = 0; pos < active_nr; pos++) { - const struct cache_entry *ce = active_cache[pos]; - - if (ce_stage(ce)) { - fprintf(fp, "\t%s\n", ce->name); - while (pos + 1 < active_nr && - !strcmp(ce->name, - active_cache[pos + 1]->name)) - pos++; - } - } + + append_conflicts_hint(&msgbuf); + fputs(msgbuf.buf, fp); + strbuf_release(&msgbuf); fclose(fp); rerere(allow_rerere_auto); printf(_("Automatic merge failed; " @@ -1101,7 +1094,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * Check if we are _not_ on a detached HEAD, i.e. if there is a * current branch. */ - branch = branch_to_free = resolve_refdup("HEAD", head_sha1, 0, &flag); + branch = branch_to_free = resolve_refdup("HEAD", 0, head_sha1, &flag); if (branch && starts_with(branch, "refs/heads/")) branch += 11; if (!branch || is_null_sha1(head_sha1)) @@ -1320,7 +1313,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (!remoteheads) ; /* already up-to-date */ else if (!remoteheads->next) - common = get_merge_bases(head_commit, remoteheads->item, 1); + common = get_merge_bases(head_commit, remoteheads->item); else { struct commit_list *list = remoteheads; commit_list_insert(head_commit, &list); @@ -1417,7 +1410,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * merge_bases again, otherwise "git merge HEAD^ * HEAD^^" would be missed. */ - common_one = get_merge_bases(head_commit, j->item, 1); + common_one = get_merge_bases(head_commit, j->item); if (hashcmp(common_one->item->object.sha1, j->item->object.sha1)) { up_to_date = 0; @@ -1550,7 +1543,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) fprintf(stderr, _("Automatic merge went well; " "stopped before committing as requested\n")); else - ret = suggest_conflicts(option_renormalize); + ret = suggest_conflicts(); done: free(branch_to_free); diff --git a/builtin/mv.c b/builtin/mv.c index 8883baa903..563d05ba1a 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -3,8 +3,8 @@ * * Copyright (C) 2006 Johannes Schindelin */ -#include "cache.h" #include "builtin.h" +#include "lockfile.h" #include "dir.h" #include "cache-tree.h" #include "string-list.h" diff --git a/builtin/notes.c b/builtin/notes.c index 67d0bb14f8..a9f37d0456 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -22,10 +22,10 @@ static const char * const git_notes_usage[] = { N_("git notes [--ref <notes_ref>] [list [<object>]]"), - N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes_ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"), - N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), - N_("git notes [--ref <notes_ref>] edit [<object>]"), + N_("git notes [--ref <notes_ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes_ref>] edit [--allow-empty] [<object>]"), N_("git notes [--ref <notes_ref>] show [<object>]"), N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"), N_("git notes merge --commit [-v | -q]"), @@ -92,12 +92,22 @@ static const char * const git_notes_get_ref_usage[] = { static const char note_template[] = "\nWrite/edit the notes for the following object:\n"; -struct msg_arg { +struct note_data { int given; int use_editor; + char *edit_path; struct strbuf buf; }; +static void free_note_data(struct note_data *d) +{ + if (d->edit_path) { + unlink_or_warn(d->edit_path); + free(d->edit_path); + } + strbuf_release(&d->buf); +} + static int list_each_note(const unsigned char *object_sha1, const unsigned char *note_sha1, char *note_path, void *cb_data) @@ -106,7 +116,7 @@ static int list_each_note(const unsigned char *object_sha1, return 0; } -static void write_note_data(int fd, const unsigned char *sha1) +static void copy_obj_to_fd(int fd, const unsigned char *sha1) { unsigned long size; enum object_type type; @@ -149,26 +159,23 @@ static void write_commented_object(int fd, const unsigned char *object) sha1_to_hex(object)); } -static void create_note(const unsigned char *object, struct msg_arg *msg, - int append_only, const unsigned char *prev, - unsigned char *result) +static void prepare_note_data(const unsigned char *object, struct note_data *d, + const unsigned char *old_note) { - char *path = NULL; - - if (msg->use_editor || !msg->given) { + if (d->use_editor || !d->given) { int fd; struct strbuf buf = STRBUF_INIT; /* write the template message before editing: */ - path = git_pathdup("NOTES_EDITMSG"); - fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); + d->edit_path = git_pathdup("NOTES_EDITMSG"); + fd = open(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) - die_errno(_("could not create file '%s'"), path); + die_errno(_("could not create file '%s'"), d->edit_path); - if (msg->given) - write_or_die(fd, msg->buf.buf, msg->buf.len); - else if (prev && !append_only) - write_note_data(fd, prev); + if (d->given) + write_or_die(fd, d->buf.buf, d->buf.len); + else if (old_note) + copy_obj_to_fd(fd, old_note); strbuf_addch(&buf, '\n'); strbuf_add_commented_lines(&buf, note_template, strlen(note_template)); @@ -179,94 +186,71 @@ static void create_note(const unsigned char *object, struct msg_arg *msg, close(fd); strbuf_release(&buf); - strbuf_reset(&(msg->buf)); - - if (launch_editor(path, &(msg->buf), NULL)) { - die(_("Please supply the note contents using either -m" \ - " or -F option")); - } - stripspace(&(msg->buf), 1); - } - - if (prev && append_only) { - /* Append buf to previous note contents */ - unsigned long size; - enum object_type type; - char *prev_buf = read_sha1_file(prev, &type, &size); + strbuf_reset(&d->buf); - strbuf_grow(&(msg->buf), size + 1); - if (msg->buf.len && prev_buf && size) - strbuf_insert(&(msg->buf), 0, "\n", 1); - if (prev_buf && size) - strbuf_insert(&(msg->buf), 0, prev_buf, size); - free(prev_buf); - } - - if (!msg->buf.len) { - fprintf(stderr, _("Removing note for object %s\n"), - sha1_to_hex(object)); - hashclr(result); - } else { - if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) { - error(_("unable to write note object")); - if (path) - error(_("The note contents have been left in %s"), - path); - exit(128); + if (launch_editor(d->edit_path, &d->buf, NULL)) { + die(_("Please supply the note contents using either -m or -F option")); } + stripspace(&d->buf, 1); } +} - if (path) { - unlink_or_warn(path); - free(path); +static void write_note_data(struct note_data *d, unsigned char *sha1) +{ + if (write_sha1_file(d->buf.buf, d->buf.len, blob_type, sha1)) { + error(_("unable to write note object")); + if (d->edit_path) + error(_("The note contents have been left in %s"), + d->edit_path); + exit(128); } } static int parse_msg_arg(const struct option *opt, const char *arg, int unset) { - struct msg_arg *msg = opt->value; + struct note_data *d = opt->value; - strbuf_grow(&(msg->buf), strlen(arg) + 2); - if (msg->buf.len) - strbuf_addch(&(msg->buf), '\n'); - strbuf_addstr(&(msg->buf), arg); - stripspace(&(msg->buf), 0); + strbuf_grow(&d->buf, strlen(arg) + 2); + if (d->buf.len) + strbuf_addch(&d->buf, '\n'); + strbuf_addstr(&d->buf, arg); + stripspace(&d->buf, 0); - msg->given = 1; + d->given = 1; return 0; } static int parse_file_arg(const struct option *opt, const char *arg, int unset) { - struct msg_arg *msg = opt->value; + struct note_data *d = opt->value; - if (msg->buf.len) - strbuf_addch(&(msg->buf), '\n'); + if (d->buf.len) + strbuf_addch(&d->buf, '\n'); if (!strcmp(arg, "-")) { - if (strbuf_read(&(msg->buf), 0, 1024) < 0) + if (strbuf_read(&d->buf, 0, 1024) < 0) die_errno(_("cannot read '%s'"), arg); - } else if (strbuf_read_file(&(msg->buf), arg, 1024) < 0) + } else if (strbuf_read_file(&d->buf, arg, 1024) < 0) die_errno(_("could not open or read '%s'"), arg); - stripspace(&(msg->buf), 0); + stripspace(&d->buf, 0); - msg->given = 1; + d->given = 1; return 0; } static int parse_reuse_arg(const struct option *opt, const char *arg, int unset) { - struct msg_arg *msg = opt->value; + struct note_data *d = opt->value; char *buf; unsigned char object[20]; enum object_type type; unsigned long len; - if (msg->buf.len) - strbuf_addch(&(msg->buf), '\n'); + if (d->buf.len) + strbuf_addch(&d->buf, '\n'); if (get_sha1(arg, object)) die(_("Failed to resolve '%s' as a valid ref."), arg); - if (!(buf = read_sha1_file(object, &type, &len)) || !len) { + if (!(buf = read_sha1_file(object, &type, &len))) { free(buf); die(_("Failed to read object '%s'."), arg); } @@ -274,17 +258,17 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset) free(buf); die(_("Cannot read note data from non-blob object '%s'."), arg); } - strbuf_add(&(msg->buf), buf, len); + strbuf_add(&d->buf, buf, len); free(buf); - msg->given = 1; + d->given = 1; return 0; } static int parse_reedit_arg(const struct option *opt, const char *arg, int unset) { - struct msg_arg *msg = opt->value; - msg->use_editor = 1; + struct note_data *d = opt->value; + d->use_editor = 1; return parse_reuse_arg(opt, arg, unset); } @@ -397,26 +381,27 @@ static int append_edit(int argc, const char **argv, const char *prefix); static int add(int argc, const char **argv, const char *prefix) { - int retval = 0, force = 0; + int force = 0, allow_empty = 0; const char *object_ref; struct notes_tree *t; unsigned char object[20], new_note[20]; - char logmsg[100]; const unsigned char *note; - struct msg_arg msg = { 0, 0, STRBUF_INIT }; + struct note_data d = { 0, 0, NULL, STRBUF_INIT }; struct option options[] = { - { OPTION_CALLBACK, 'm', "message", &msg, N_("message"), + { OPTION_CALLBACK, 'm', "message", &d, N_("message"), N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg}, - { OPTION_CALLBACK, 'F', "file", &msg, N_("file"), + { OPTION_CALLBACK, 'F', "file", &d, N_("file"), N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg}, - { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"), + { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"), N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg}, - { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"), + { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"), N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg}, + OPT_BOOL(0, "allow-empty", &allow_empty, + N_("allow storing empty note")), OPT__FORCE(&force, N_("replace existing notes")), OPT_END() }; @@ -439,41 +424,44 @@ static int add(int argc, const char **argv, const char *prefix) if (note) { if (!force) { - if (!msg.given) { - /* - * Redirect to "edit" subcommand. - * - * We only end up here if none of -m/-F/-c/-C - * or -f are given. The original args are - * therefore still in argv[0-1]. - */ - argv[0] = "edit"; - free_notes(t); - return append_edit(argc, argv, prefix); + free_notes(t); + if (d.given) { + free_note_data(&d); + return error(_("Cannot add notes. " + "Found existing notes for object %s. " + "Use '-f' to overwrite existing notes"), + sha1_to_hex(object)); } - retval = error(_("Cannot add notes. Found existing notes " - "for object %s. Use '-f' to overwrite " - "existing notes"), sha1_to_hex(object)); - goto out; + /* + * Redirect to "edit" subcommand. + * + * We only end up here if none of -m/-F/-c/-C or -f are + * given. The original args are therefore still in + * argv[0-1]. + */ + argv[0] = "edit"; + return append_edit(argc, argv, prefix); } fprintf(stderr, _("Overwriting existing notes for object %s\n"), sha1_to_hex(object)); } - create_note(object, &msg, 0, note, new_note); - - if (is_null_sha1(new_note)) + prepare_note_data(object, &d, note); + if (d.buf.len || allow_empty) { + write_note_data(&d, new_note); + 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); - else if (add_note(t, object, new_note, combine_notes_overwrite)) - die("BUG: combine_notes_overwrite failed"); + commit_notes(t, "Notes removed by 'git notes add'"); + } - snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'", - is_null_sha1(new_note) ? "removed" : "added", "add"); - commit_notes(t, logmsg); -out: + free_note_data(&d); free_notes(t); - strbuf_release(&(msg.buf)); - return retval; + return 0; } static int copy(int argc, const char **argv, const char *prefix) @@ -554,26 +542,29 @@ out: 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; char logmsg[100]; const char * const *usage; - struct msg_arg msg = { 0, 0, STRBUF_INIT }; + struct note_data d = { 0, 0, NULL, STRBUF_INIT }; struct option options[] = { - { OPTION_CALLBACK, 'm', "message", &msg, N_("message"), + { OPTION_CALLBACK, 'm', "message", &d, N_("message"), N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg}, - { OPTION_CALLBACK, 'F', "file", &msg, N_("file"), + { OPTION_CALLBACK, 'F', "file", &d, N_("file"), N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg}, - { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"), + { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"), N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg}, - { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"), + { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"), N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg}, + OPT_BOOL(0, "allow-empty", &allow_empty, + N_("allow storing empty note")), OPT_END() }; int edit = !strcmp(argv[0], "edit"); @@ -587,7 +578,7 @@ static int append_edit(int argc, const char **argv, const char *prefix) usage_with_options(usage, options); } - if (msg.given && edit) + if (d.given && edit) fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated " "for the 'edit' subcommand.\n" "Please use 'git notes add -f -m/-F/-c/-C' instead.\n")); @@ -600,18 +591,39 @@ static int append_edit(int argc, const char **argv, const char *prefix) t = init_notes_check(argv[0]); note = get_note(t, object); - create_note(object, &msg, !edit, note, new_note); + prepare_note_data(object, &d, edit ? note : NULL); - if (is_null_sha1(new_note)) - remove_note(t, object); - else if (add_note(t, object, new_note, combine_notes_overwrite)) - die("BUG: combine_notes_overwrite failed"); + 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); + + strbuf_grow(&d.buf, size + 1); + if (d.buf.len && prev_buf && size) + strbuf_insert(&d.buf, 0, "\n", 1); + if (prev_buf && size) + strbuf_insert(&d.buf, 0, prev_buf, size); + free(prev_buf); + } - snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'", - is_null_sha1(new_note) ? "removed" : "added", argv[0]); + if (d.buf.len || allow_empty) { + write_note_data(&d, new_note); + if (add_note(t, object, new_note, combine_notes_overwrite)) + die("BUG: combine_notes_overwrite failed"); + snprintf(logmsg, sizeof(logmsg), "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); + snprintf(logmsg, sizeof(logmsg), "Notes removed by 'git notes %s'", + argv[0]); + } commit_notes(t, logmsg); + + free_note_data(&d); free_notes(t); - strbuf_release(&(msg.buf)); return 0; } @@ -702,7 +714,7 @@ static int merge_commit(struct notes_merge_options *o) init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0); o->local_ref = local_ref_to_free = - resolve_refdup("NOTES_MERGE_REF", sha1, 0, NULL); + resolve_refdup("NOTES_MERGE_REF", 0, sha1, NULL); if (!o->local_ref) die("Failed to resolve NOTES_MERGE_REF"); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index d39193453a..d8165878e1 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -20,6 +20,9 @@ #include "streaming.h" #include "thread-utils.h" #include "pack-bitmap.h" +#include "reachable.h" +#include "sha1-array.h" +#include "argv-array.h" static const char *pack_usage[] = { N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"), @@ -811,6 +814,7 @@ static void write_pack_file(void) fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written, sha1, offset); close(fd); + write_bitmap_index = 0; } if (!pack_to_stdout) { @@ -1972,8 +1976,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, init_threaded_search(); - if (!delta_search_threads) /* --threads=0 means autodetect */ - delta_search_threads = online_cpus(); if (delta_search_threads <= 1) { find_deltas(list, &list_size, window, depth, processed); cleanup_threaded_search(); @@ -2407,6 +2409,27 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1) return 0; } +/* + * Store a list of sha1s that are should not be discarded + * because they are either written too recently, or are + * reachable from another object that was. + * + * This is filled by get_object_list. + */ +static struct sha1_array recent_objects; + +static int loosened_object_can_be_discarded(const unsigned char *sha1, + unsigned long mtime) +{ + if (!unpack_unreachable_expiration) + return 0; + if (mtime > unpack_unreachable_expiration) + return 0; + if (sha1_array_lookup(&recent_objects, sha1) >= 0) + return 0; + return 1; +} + static void loosen_unused_packed_objects(struct rev_info *revs) { struct packed_git *p; @@ -2417,17 +2440,14 @@ static void loosen_unused_packed_objects(struct rev_info *revs) if (!p->pack_local || p->pack_keep) continue; - if (unpack_unreachable_expiration && - p->mtime < unpack_unreachable_expiration) - continue; - if (open_pack_index(p)) die("cannot open pack index"); for (i = 0; i < p->num_objects; i++) { sha1 = nth_packed_object_sha1(p, i); if (!packlist_find(&to_pack, sha1, NULL) && - !has_sha1_pack_kept_or_nonlocal(sha1)) + !has_sha1_pack_kept_or_nonlocal(sha1) && + !loosened_object_can_be_discarded(sha1, p->mtime)) if (force_object_loose(sha1, p->mtime)) die("unable to force loose object"); } @@ -2463,6 +2483,19 @@ static int get_object_list_from_bitmap(struct rev_info *revs) return 0; } +static void record_recent_object(struct object *obj, + const struct name_path *path, + const char *last, + void *data) +{ + sha1_array_append(&recent_objects, obj->sha1); +} + +static void record_recent_commit(struct commit *commit, void *data) +{ + sha1_array_append(&recent_objects, commit->object.sha1); +} + static void get_object_list(int ac, const char **av) { struct rev_info revs; @@ -2510,10 +2543,23 @@ static void get_object_list(int ac, const char **av) mark_edges_uninteresting(&revs, show_edge); traverse_commit_list(&revs, show_commit, show_object, NULL); + if (unpack_unreachable_expiration) { + revs.ignore_missing_links = 1; + if (add_unseen_recent_objects_to_traversal(&revs, + unpack_unreachable_expiration)) + die("unable to add recent objects"); + if (prepare_revision_walk(&revs)) + die("revision walk setup failed"); + traverse_commit_list(&revs, record_recent_commit, + record_recent_object, NULL); + } + if (keep_unreachable) add_objects_in_unpacked_packs(&revs); if (unpack_unreachable) loosen_unused_packed_objects(&revs); + + sha1_array_clear(&recent_objects); } static int option_parse_index_version(const struct option *opt, @@ -2567,10 +2613,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) { int use_internal_rev_list = 0; int thin = 0; + int shallow = 0; int all_progress_implied = 0; - const char *rp_av[6]; - int rp_ac = 0; + struct argv_array rp = ARGV_ARRAY_INIT; int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0; + int rev_list_index = 0; struct option pack_objects_options[] = { OPT_SET_INT('q', "quiet", &progress, N_("do not show progress meter"), 0), @@ -2617,6 +2664,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) { OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL, N_("include objects referred by reflog entries"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, + { OPTION_SET_INT, 0, "indexed-objects", &rev_list_index, NULL, + N_("include objects referred to by the index"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, OPT_BOOL(0, "stdout", &pack_to_stdout, N_("output pack to stdout")), OPT_BOOL(0, "include-tag", &include_tag, @@ -2628,6 +2678,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) PARSE_OPT_OPTARG, option_parse_unpack_unreachable }, OPT_BOOL(0, "thin", &thin, N_("create thin packs")), + OPT_BOOL(0, "shallow", &shallow, + N_("create packs suitable for shallow fetches")), OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep, N_("ignore packs that have companion .keep file")), OPT_INTEGER(0, "compression", &pack_compression_level, @@ -2659,24 +2711,30 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (pack_to_stdout != !base_name || argc) usage_with_options(pack_usage, pack_objects_options); - rp_av[rp_ac++] = "pack-objects"; + argv_array_push(&rp, "pack-objects"); if (thin) { use_internal_rev_list = 1; - rp_av[rp_ac++] = "--objects-edge"; + argv_array_push(&rp, shallow + ? "--objects-edge-aggressive" + : "--objects-edge"); } else - rp_av[rp_ac++] = "--objects"; + argv_array_push(&rp, "--objects"); if (rev_list_all) { use_internal_rev_list = 1; - rp_av[rp_ac++] = "--all"; + argv_array_push(&rp, "--all"); } if (rev_list_reflog) { use_internal_rev_list = 1; - rp_av[rp_ac++] = "--reflog"; + argv_array_push(&rp, "--reflog"); + } + if (rev_list_index) { + use_internal_rev_list = 1; + argv_array_push(&rp, "--indexed-objects"); } if (rev_list_unpacked) { use_internal_rev_list = 1; - rp_av[rp_ac++] = "--unpacked"; + argv_array_push(&rp, "--unpacked"); } if (!reuse_object) @@ -2685,6 +2743,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) pack_compression_level = Z_DEFAULT_COMPRESSION; else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION) die("bad pack compression level %d", pack_compression_level); + + if (!delta_search_threads) /* --threads=0 means autodetect */ + delta_search_threads = online_cpus(); + #ifdef NO_PTHREADS if (delta_search_threads != 1) warning("no threads support, ignoring --threads"); @@ -2703,6 +2765,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (keep_unreachable && unpack_unreachable) die("--keep-unreachable and --unpack-unreachable are incompatible."); + if (!rev_list_all || !rev_list_reflog || !rev_list_index) + unpack_unreachable_expiration = 0; if (!use_internal_rev_list || !pack_to_stdout || is_repository_shallow()) use_bitmap_index = 0; @@ -2720,8 +2784,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (!use_internal_rev_list) read_object_list_from_stdin(); else { - rp_av[rp_ac] = NULL; - get_object_list(rp_ac, rp_av); + get_object_list(rp.argc, rp.argv); + argv_array_clear(&rp); } cleanup_preferred_base(); if (include_tag && nr_result) diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c index d430731d70..f24a2c2bdc 100644 --- a/builtin/prune-packed.c +++ b/builtin/prune-packed.c @@ -10,65 +10,42 @@ static const char * const prune_packed_usage[] = { static struct progress *progress; -static void prune_dir(int i, DIR *dir, struct strbuf *pathname, int opts) +static int prune_subdir(int nr, const char *path, void *data) { - struct dirent *de; - char hex[40]; - int top_len = pathname->len; + int *opts = data; + display_progress(progress, nr + 1); + if (!(*opts & PRUNE_PACKED_DRY_RUN)) + rmdir(path); + return 0; +} + +static int prune_object(const unsigned char *sha1, const char *path, + void *data) +{ + int *opts = data; - sprintf(hex, "%02x", i); - while ((de = readdir(dir)) != NULL) { - unsigned char sha1[20]; - if (strlen(de->d_name) != 38) - continue; - memcpy(hex + 2, de->d_name, 38); - if (get_sha1_hex(hex, sha1)) - continue; - if (!has_sha1_pack(sha1)) - continue; + if (!has_sha1_pack(sha1)) + return 0; - strbuf_add(pathname, de->d_name, 38); - if (opts & PRUNE_PACKED_DRY_RUN) - printf("rm -f %s\n", pathname->buf); - else - unlink_or_warn(pathname->buf); - display_progress(progress, i + 1); - strbuf_setlen(pathname, top_len); - } + if (*opts & PRUNE_PACKED_DRY_RUN) + printf("rm -f %s\n", path); + else + unlink_or_warn(path); + return 0; } void prune_packed_objects(int opts) { - int i; - const char *dir = get_object_directory(); - struct strbuf pathname = STRBUF_INIT; - int top_len; - - strbuf_addstr(&pathname, dir); if (opts & PRUNE_PACKED_VERBOSE) progress = start_progress_delay(_("Removing duplicate objects"), 256, 95, 2); - if (pathname.len && pathname.buf[pathname.len - 1] != '/') - strbuf_addch(&pathname, '/'); - - top_len = pathname.len; - for (i = 0; i < 256; i++) { - DIR *d; + for_each_loose_file_in_objdir(get_object_directory(), + prune_object, NULL, prune_subdir, &opts); - display_progress(progress, i + 1); - strbuf_setlen(&pathname, top_len); - strbuf_addf(&pathname, "%02x/", i); - d = opendir(pathname.buf); - if (!d) - continue; - prune_dir(i, d, &pathname, opts); - closedir(d); - strbuf_setlen(&pathname, top_len + 2); - rmdir(pathname.buf); - } + /* Ensure we show 100% before finishing progress */ + display_progress(progress, 256); stop_progress(&progress); - strbuf_release(&pathname); } int cmd_prune_packed(int argc, const char **argv, const char *prefix) diff --git a/builtin/prune.c b/builtin/prune.c index 144a3bdb33..04d3b12ae4 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -31,11 +31,23 @@ static int prune_tmp_file(const char *fullpath) return 0; } -static int prune_object(const char *fullpath, const unsigned char *sha1) +static int prune_object(const unsigned char *sha1, const char *fullpath, + void *data) { struct stat st; - if (lstat(fullpath, &st)) - return error("Could not stat '%s'", fullpath); + + /* + * Do we know about this object? + * It must have been reachable + */ + if (lookup_object(sha1)) + return 0; + + if (lstat(fullpath, &st)) { + /* report errors, but do not stop pruning */ + error("Could not stat '%s'", fullpath); + return 0; + } if (st.st_mtime > expire) return 0; if (show_only || verbose) { @@ -48,68 +60,20 @@ static int prune_object(const char *fullpath, const unsigned char *sha1) return 0; } -static int prune_dir(int i, struct strbuf *path) +static int prune_cruft(const char *basename, const char *path, void *data) { - size_t baselen = path->len; - DIR *dir = opendir(path->buf); - struct dirent *de; - - if (!dir) - return 0; - - while ((de = readdir(dir)) != NULL) { - char name[100]; - unsigned char sha1[20]; - - if (is_dot_or_dotdot(de->d_name)) - continue; - if (strlen(de->d_name) == 38) { - sprintf(name, "%02x", i); - memcpy(name+2, de->d_name, 39); - if (get_sha1_hex(name, sha1) < 0) - break; - - /* - * Do we know about this object? - * It must have been reachable - */ - if (lookup_object(sha1)) - continue; - - strbuf_addf(path, "/%s", de->d_name); - prune_object(path->buf, sha1); - strbuf_setlen(path, baselen); - continue; - } - if (starts_with(de->d_name, "tmp_obj_")) { - strbuf_addf(path, "/%s", de->d_name); - prune_tmp_file(path->buf); - strbuf_setlen(path, baselen); - continue; - } - fprintf(stderr, "bad sha1 file: %s/%s\n", path->buf, de->d_name); - } - closedir(dir); - if (!show_only) - rmdir(path->buf); + if (starts_with(basename, "tmp_obj_")) + prune_tmp_file(path); + else + fprintf(stderr, "bad sha1 file: %s\n", path); return 0; } -static void prune_object_dir(const char *path) +static int prune_subdir(int nr, const char *path, void *data) { - struct strbuf buf = STRBUF_INIT; - size_t baselen; - int i; - - strbuf_addstr(&buf, path); - strbuf_addch(&buf, '/'); - baselen = buf.len; - - for (i = 0; i < 256; i++) { - strbuf_addf(&buf, "%02x", i); - prune_dir(i, &buf); - strbuf_setlen(&buf, baselen); - } + if (!show_only) + rmdir(path); + return 0; } /* @@ -171,9 +135,10 @@ int cmd_prune(int argc, const char **argv, const char *prefix) if (show_progress) progress = start_progress_delay(_("Checking connectivity"), 0, 0, 2); - mark_reachable_objects(&revs, 1, progress); + mark_reachable_objects(&revs, 1, expire, progress); stop_progress(&progress); - prune_object_dir(get_object_directory()); + for_each_loose_file_in_objdir(get_object_directory(), prune_object, + prune_cruft, prune_subdir, NULL); prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0); remove_temporary_files(get_object_directory()); diff --git a/builtin/push.c b/builtin/push.c index ae56f73a66..12f5e69393 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -161,7 +161,7 @@ static const char message_detached_head_die[] = " git push %s HEAD:<name-of-remote-branch>\n"); static void setup_push_upstream(struct remote *remote, struct branch *branch, - int triangular) + int triangular, int simple) { struct strbuf refspec = STRBUF_INIT; @@ -184,7 +184,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch, "to update which remote branch."), remote->name, branch->name); - if (push_default == PUSH_DEFAULT_SIMPLE) { + if (simple) { /* Additional safety */ if (strcmp(branch->refname, branch->merge[0]->src)) die_push_simple(branch, remote); @@ -257,11 +257,11 @@ static void setup_default_push_refspecs(struct remote *remote) if (triangular) setup_push_current(remote, branch); else - setup_push_upstream(remote, branch, triangular); + setup_push_upstream(remote, branch, triangular, 1); break; case PUSH_DEFAULT_UPSTREAM: - setup_push_upstream(remote, branch, triangular); + setup_push_upstream(remote, branch, triangular, 0); break; case PUSH_DEFAULT_CURRENT: @@ -471,6 +471,17 @@ static int option_parse_recurse_submodules(const struct option *opt, return 0; } +static int git_push_config(const char *k, const char *v, void *cb) +{ + struct wt_status *s = cb; + int status; + + status = git_gpg_config(k, v, NULL); + if (status) + return status; + return git_default_config(k, v, s); +} + int cmd_push(int argc, const char **argv, const char *prefix) { int flags = 0; @@ -492,7 +503,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"), N_("require old value of ref to be at this value"), PARSE_OPT_OPTARG, parseopt_push_cas_option }, - { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"), + { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check|on-demand", N_("control recursive pushing of submodules"), PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOL( 0 , "thin", &thin, N_("use thin pack")), @@ -511,7 +522,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) }; packet_trace_identity("push"); - git_config(git_default_config, NULL); + git_config(git_push_config, NULL); argc = parse_options(argc, argv, prefix, options, push_usage, 0); if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR)))) diff --git a/builtin/read-tree.c b/builtin/read-tree.c index e7e1c33a7f..43b47f72f1 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -5,6 +5,7 @@ */ #include "cache.h" +#include "lockfile.h" #include "object.h" #include "tree.h" #include "tree-walk.h" diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index a01ac2096a..8266c1fccf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "lockfile.h" #include "pack.h" #include "refs.h" #include "pkt-line.h" @@ -25,7 +26,8 @@ enum deny_action { DENY_UNCONFIGURED, DENY_IGNORE, DENY_WARN, - DENY_REFUSE + DENY_REFUSE, + DENY_UPDATE_INSTEAD }; static int deny_deletes; @@ -75,6 +77,8 @@ static enum deny_action parse_deny_action(const char *var, const char *value) return DENY_WARN; if (!strcasecmp(value, "refuse")) return DENY_REFUSE; + if (!strcasecmp(value, "updateinstead")) + return DENY_UPDATE_INSTEAD; } if (git_config_bool(var, value)) return DENY_REFUSE; @@ -430,7 +434,7 @@ static const char *check_nonce(const char *buf, size_t len) nonce_stamp_slop = (long)ostamp - (long)stamp; if (nonce_stamp_slop_limit && - abs(nonce_stamp_slop) <= nonce_stamp_slop_limit) { + labs(nonce_stamp_slop) <= nonce_stamp_slop_limit) { /* * Pretend as if the received nonce (which passes the * HMAC check, so it is not a forged by third-party) @@ -452,7 +456,6 @@ leave: static void prepare_push_cert_sha1(struct child_process *proc) { static int already_done; - struct argv_array env = ARGV_ARRAY_INIT; if (!push_cert.len) return; @@ -486,20 +489,26 @@ static void prepare_push_cert_sha1(struct child_process *proc) nonce_status = check_nonce(push_cert.buf, bogs); } if (!is_null_sha1(push_cert_sha1)) { - argv_array_pushf(&env, "GIT_PUSH_CERT=%s", sha1_to_hex(push_cert_sha1)); - argv_array_pushf(&env, "GIT_PUSH_CERT_SIGNER=%s", + argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT=%s", + sha1_to_hex(push_cert_sha1)); + argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_SIGNER=%s", sigcheck.signer ? sigcheck.signer : ""); - argv_array_pushf(&env, "GIT_PUSH_CERT_KEY=%s", + argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_KEY=%s", sigcheck.key ? sigcheck.key : ""); - argv_array_pushf(&env, "GIT_PUSH_CERT_STATUS=%c", sigcheck.result); + argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_STATUS=%c", + sigcheck.result); if (push_cert_nonce) { - argv_array_pushf(&env, "GIT_PUSH_CERT_NONCE=%s", push_cert_nonce); - argv_array_pushf(&env, "GIT_PUSH_CERT_NONCE_STATUS=%s", nonce_status); + argv_array_pushf(&proc->env_array, + "GIT_PUSH_CERT_NONCE=%s", + push_cert_nonce); + argv_array_pushf(&proc->env_array, + "GIT_PUSH_CERT_NONCE_STATUS=%s", + nonce_status); if (nonce_status == NONCE_SLOP) - argv_array_pushf(&env, "GIT_PUSH_CERT_NONCE_SLOP=%ld", + argv_array_pushf(&proc->env_array, + "GIT_PUSH_CERT_NONCE_SLOP=%ld", nonce_stamp_slop); } - proc->env = env.argv; } } @@ -521,8 +530,6 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta proc.in = -1; proc.stdout_to_stderr = 1; - prepare_push_cert_sha1(&proc); - if (use_sideband) { memset(&muxer, 0, sizeof(muxer)); muxer.proc = copy_to_sideband; @@ -533,6 +540,8 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta proc.err = muxer.in; } + prepare_push_cert_sha1(&proc); + code = start_command(&proc); if (code) { if (use_sideband) @@ -724,11 +733,89 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) return 0; } +static const char *update_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "-q", "--ignore-submodules", "--refresh", NULL + }; + const char *diff_files[] = { + "diff-files", "--quiet", "--ignore-submodules", "--", NULL + }; + const char *diff_index[] = { + "diff-index", "--quiet", "--cached", "--ignore-submodules", + "HEAD", "--", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", NULL, NULL + }; + const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : ".."; + struct argv_array env = ARGV_ARRAY_INIT; + struct child_process child = CHILD_PROCESS_INIT; + + if (is_bare_repository()) + return "denyCurrentBranch = updateInstead needs a worktree"; + + argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir())); + + child.argv = update_refresh; + child.env = env.argv; + child.dir = work_tree; + child.no_stdin = 1; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) { + argv_array_clear(&env); + return "Up-to-date check failed"; + } + + /* run_command() does not clean up completely; reinitialize */ + child_process_init(&child); + child.argv = diff_files; + child.env = env.argv; + child.dir = work_tree; + child.no_stdin = 1; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) { + argv_array_clear(&env); + return "Working directory has unstaged changes"; + } + + child_process_init(&child); + child.argv = diff_index; + child.env = env.argv; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + child.git_cmd = 1; + if (run_command(&child)) { + argv_array_clear(&env); + return "Working directory has staged changes"; + } + + read_tree[3] = sha1_to_hex(sha1); + child_process_init(&child); + child.argv = read_tree; + child.env = env.argv; + child.dir = work_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + child.git_cmd = 1; + if (run_command(&child)) { + argv_array_clear(&env); + return "Could not update working tree to new HEAD"; + } + + argv_array_clear(&env); + return NULL; +} + static const char *update(struct command *cmd, struct shallow_info *si) { const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; - const char *namespaced_name; + const char *namespaced_name, *ret; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; @@ -754,6 +841,11 @@ static const char *update(struct command *cmd, struct shallow_info *si) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + ret = update_worktree(new_sha1); + if (ret) + return ret; + break; } } @@ -778,10 +870,13 @@ static const char *update(struct command *cmd, struct shallow_info *si) break; case DENY_REFUSE: case DENY_UNCONFIGURED: + case DENY_UPDATE_INSTEAD: if (deny_delete_current == DENY_UNCONFIGURED) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + return "Invalid denyDeleteCurrent setting"; } } } @@ -841,8 +936,9 @@ static const char *update(struct command *cmd, struct shallow_info *si) transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, namespaced_name, - new_sha1, old_sha1, 0, 1, &err) || - ref_transaction_commit(transaction, "push", &err)) { + new_sha1, old_sha1, 0, 1, "push", + &err) || + ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); rp_error("%s", err.buf); @@ -907,7 +1003,7 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) int flag; strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name); - dst_name = resolve_ref_unsafe(buf.buf, sha1, 0, &flag); + dst_name = resolve_ref_unsafe(buf.buf, 0, sha1, &flag); strbuf_release(&buf); if (!(flag & REF_ISSYMREF)) @@ -957,7 +1053,7 @@ static void check_aliased_updates(struct command *commands) string_list_append(&ref_list, cmd->ref_name); item->util = (void *)cmd; } - sort_string_list(&ref_list); + string_list_sort(&ref_list); for (cmd = commands; cmd; cmd = cmd->next) { if (!cmd->error_string) @@ -1068,7 +1164,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", sha1, 0, NULL); + head_name = head_name_to_free = resolve_refdup("HEAD", 0, sha1, NULL); checked_connectivity = 1; for (cmd = commands; cmd; cmd = cmd->next) { @@ -1229,7 +1325,6 @@ static const char *pack_lockfile; static const char *unpack(int err_fd, struct shallow_info *si) { struct pack_header hdr; - struct argv_array av = ARGV_ARRAY_INIT; const char *hdr_err; int status; char hdr_arg[38]; @@ -1252,16 +1347,16 @@ static const char *unpack(int err_fd, struct shallow_info *si) if (si->nr_ours || si->nr_theirs) { alt_shallow_file = setup_temporary_shallow(si->shallow); - argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL); + argv_array_push(&child.args, "--shallow-file"); + argv_array_push(&child.args, alt_shallow_file); } if (ntohl(hdr.hdr_entries) < unpack_limit) { - argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL); + argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL); if (quiet) - argv_array_push(&av, "-q"); + argv_array_push(&child.args, "-q"); if (fsck_objects) - argv_array_push(&av, "--strict"); - child.argv = av.argv; + argv_array_push(&child.args, "--strict"); child.no_stdout = 1; child.err = err_fd; child.git_cmd = 1; @@ -1276,13 +1371,12 @@ static const char *unpack(int err_fd, struct shallow_info *si) if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); - argv_array_pushl(&av, "index-pack", + argv_array_pushl(&child.args, "index-pack", "--stdin", hdr_arg, keep_arg, NULL); if (fsck_objects) - argv_array_push(&av, "--strict"); + argv_array_push(&child.args, "--strict"); if (fix_thin) - argv_array_push(&av, "--fix-thin"); - child.argv = av.argv; + argv_array_push(&child.args, "--fix-thin"); child.out = -1; child.err = err_fd; child.git_cmd = 1; diff --git a/builtin/reflog.c b/builtin/reflog.c index e8a8fb13b9..2d85d260ca 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -1,5 +1,5 @@ -#include "cache.h" #include "builtin.h" +#include "lockfile.h" #include "commit.h" #include "refs.h" #include "dir.h" @@ -431,7 +431,7 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, write_str_in_full(lock->lock_fd, "\n") != 1 || close_ref(lock) < 0)) { status |= error("Couldn't write %s", - lock->lk->filename); + lock->lk->filename.buf); unlink(newlog_path); } else if (rename(newlog_path, log_file)) { status |= error("cannot rename %s to %s", @@ -649,7 +649,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) init_revisions(&cb.revs, prefix); if (cb.verbose) printf("Marking reachable objects..."); - mark_reachable_objects(&cb.revs, 0, NULL); + mark_reachable_objects(&cb.revs, 0, 0, NULL); if (cb.verbose) putchar('\n'); } diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index d699d28e98..3b8c22cc75 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -30,16 +30,14 @@ static char *strip_escapes(const char *str, const char *service, size_t rpos = 0; int escape = 0; char special = 0; - size_t psoff = 0; + const char *service_noprefix = service; struct strbuf ret = STRBUF_INIT; - /* Calculate prefix length for \s and lengths for \s and \S */ - if (!strncmp(service, "git-", 4)) - psoff = 4; + skip_prefix(service_noprefix, "git-", &service_noprefix); /* Pass the service to command. */ setenv("GIT_EXT_SERVICE", service, 1); - setenv("GIT_EXT_SERVICE_NOPREFIX", service + psoff, 1); + setenv("GIT_EXT_SERVICE_NOPREFIX", service_noprefix, 1); /* Scan the length of argument. */ while (str[rpos] && (escape || str[rpos] != ' ')) { @@ -85,7 +83,7 @@ static char *strip_escapes(const char *str, const char *service, strbuf_addch(&ret, str[rpos]); break; case 's': - strbuf_addstr(&ret, service + psoff); + strbuf_addstr(&ret, service_noprefix); break; case 'S': strbuf_addstr(&ret, service); diff --git a/builtin/remote.c b/builtin/remote.c index 9a4640dbf0..b4ff468977 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -180,7 +180,9 @@ static int add(int argc, const char **argv) url = argv[1]; remote = remote_get(name); - if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) || + if (remote && (remote->url_nr > 1 || + (strcmp(name, remote->url[0]) && + strcmp(url, remote->url[0])) || remote->fetch_refspec_nr)) die(_("remote %s already exists."), name); @@ -352,9 +354,9 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat free_refs(stale_refs); free_refs(fetch_map); - sort_string_list(&states->new); - sort_string_list(&states->tracked); - sort_string_list(&states->stale); + string_list_sort(&states->new); + string_list_sort(&states->tracked); + string_list_sort(&states->stale); return 0; } @@ -567,7 +569,8 @@ static int read_remote_branches(const char *refname, strbuf_addf(&buf, "refs/remotes/%s/", rename->old); if (starts_with(refname, buf.buf)) { item = string_list_append(rename->remote_branches, xstrdup(refname)); - symref = resolve_ref_unsafe(refname, orig_sha1, 1, &flag); + symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING, + orig_sha1, &flag); if (flag & REF_ISSYMREF) item->util = xstrdup(symref); else @@ -703,7 +706,7 @@ static int mv(int argc, const char **argv) int flag = 0; unsigned char sha1[20]; - read_ref_full(item->string, sha1, 1, &flag); + read_ref_full(item->string, RESOLVE_REF_READING, sha1, &flag); if (!(flag & REF_ISSYMREF)) continue; if (delete_ref(item->string, NULL, REF_NODEREF)) @@ -748,14 +751,12 @@ static int mv(int argc, const char **argv) static int remove_branches(struct string_list *branches) { - const char **branch_names; + struct strbuf err = STRBUF_INIT; int i, result = 0; - branch_names = xmalloc(branches->nr * sizeof(*branch_names)); - for (i = 0; i < branches->nr; i++) - branch_names[i] = branches->items[i].string; - result |= repack_without_refs(branch_names, branches->nr, NULL); - free(branch_names); + if (repack_without_refs(branches, &err)) + result |= error("%s", err.buf); + strbuf_release(&err); for (i = 0; i < branches->nr; i++) { struct string_list_item *item = branches->items + i; @@ -910,7 +911,7 @@ static int get_remote_ref_states(const char *name, get_push_ref_states(remote_refs, states); } else { for_each_ref(append_ref_to_tracked_list, states); - sort_string_list(&states->tracked); + string_list_sort(&states->tracked); get_push_ref_states_noquery(states); } @@ -1129,7 +1130,7 @@ static int show_all(void) if (!result) { int i; - sort_string_list(&list); + string_list_sort(&list); for (i = 0; i < list.nr; i++) { struct string_list_item *item = list.items + i; if (verbose) @@ -1310,10 +1311,10 @@ static int set_head(int argc, const char **argv) static int prune_remote(const char *remote, int dry_run) { - int result = 0, i; + int result = 0; struct ref_states states; - struct string_list delete_refs_list = STRING_LIST_INIT_NODUP; - const char **delete_refs; + struct string_list refs_to_prune = STRING_LIST_INIT_NODUP; + struct string_list_item *item; const char *dangling_msg = dry_run ? _(" %s will become dangling!") : _(" %s has become dangling!"); @@ -1321,26 +1322,30 @@ static int prune_remote(const char *remote, int dry_run) memset(&states, 0, sizeof(states)); get_remote_ref_states(remote, &states, GET_REF_STATES); - if (states.stale.nr) { - printf_ln(_("Pruning %s"), remote); - printf_ln(_("URL: %s"), - states.remote->url_nr - ? states.remote->url[0] - : _("(no URL)")); - - delete_refs = xmalloc(states.stale.nr * sizeof(*delete_refs)); - for (i = 0; i < states.stale.nr; i++) - delete_refs[i] = states.stale.items[i].util; - if (!dry_run) - result |= repack_without_refs(delete_refs, - states.stale.nr, NULL); - free(delete_refs); + if (!states.stale.nr) { + free_remote_ref_states(&states); + return 0; } - for (i = 0; i < states.stale.nr; i++) { - const char *refname = states.stale.items[i].util; + printf_ln(_("Pruning %s"), remote); + printf_ln(_("URL: %s"), + states.remote->url_nr + ? states.remote->url[0] + : _("(no URL)")); + + for_each_string_list_item(item, &states.stale) + string_list_append(&refs_to_prune, item->util); + string_list_sort(&refs_to_prune); + + if (!dry_run) { + struct strbuf err = STRBUF_INIT; + if (repack_without_refs(&refs_to_prune, &err)) + result |= error("%s", err.buf); + strbuf_release(&err); + } - string_list_insert(&delete_refs_list, refname); + for_each_string_list_item(item, &states.stale) { + const char *refname = item->util; if (!dry_run) result |= delete_ref(refname, NULL, 0); @@ -1353,9 +1358,9 @@ static int prune_remote(const char *remote, int dry_run) abbrev_ref(refname, "refs/remotes/")); } - warn_dangling_symrefs(stdout, dangling_msg, &delete_refs_list); - string_list_clear(&delete_refs_list, 0); + warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune); + string_list_clear(&refs_to_prune, 0); free_remote_ref_states(&states); return result; } diff --git a/builtin/repack.c b/builtin/repack.c index 2aae05d364..3f852f35d1 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -135,7 +135,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix) }; struct child_process cmd = CHILD_PROCESS_INIT; struct string_list_item *item; - struct argv_array cmd_args = ARGV_ARRAY_INIT; struct string_list names = STRING_LIST_INIT_DUP; struct string_list rollback = STRING_LIST_INIT_NODUP; struct string_list existing_packs = STRING_LIST_INIT_DUP; @@ -202,55 +201,55 @@ int cmd_repack(int argc, const char **argv, const char *prefix) sigchain_push_common(remove_pack_on_signal); - argv_array_push(&cmd_args, "pack-objects"); - argv_array_push(&cmd_args, "--keep-true-parents"); + argv_array_push(&cmd.args, "pack-objects"); + argv_array_push(&cmd.args, "--keep-true-parents"); if (!pack_kept_objects) - argv_array_push(&cmd_args, "--honor-pack-keep"); - argv_array_push(&cmd_args, "--non-empty"); - argv_array_push(&cmd_args, "--all"); - argv_array_push(&cmd_args, "--reflog"); + argv_array_push(&cmd.args, "--honor-pack-keep"); + argv_array_push(&cmd.args, "--non-empty"); + argv_array_push(&cmd.args, "--all"); + argv_array_push(&cmd.args, "--reflog"); + argv_array_push(&cmd.args, "--indexed-objects"); if (window) - argv_array_pushf(&cmd_args, "--window=%s", window); + argv_array_pushf(&cmd.args, "--window=%s", window); if (window_memory) - argv_array_pushf(&cmd_args, "--window-memory=%s", window_memory); + argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory); if (depth) - argv_array_pushf(&cmd_args, "--depth=%s", depth); + argv_array_pushf(&cmd.args, "--depth=%s", depth); if (max_pack_size) - argv_array_pushf(&cmd_args, "--max-pack-size=%s", max_pack_size); + argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size); if (no_reuse_delta) - argv_array_pushf(&cmd_args, "--no-reuse-delta"); + argv_array_pushf(&cmd.args, "--no-reuse-delta"); if (no_reuse_object) - argv_array_pushf(&cmd_args, "--no-reuse-object"); + argv_array_pushf(&cmd.args, "--no-reuse-object"); if (write_bitmaps) - argv_array_push(&cmd_args, "--write-bitmap-index"); + argv_array_push(&cmd.args, "--write-bitmap-index"); if (pack_everything & ALL_INTO_ONE) { get_non_kept_pack_filenames(&existing_packs); if (existing_packs.nr && delete_redundant) { if (unpack_unreachable) - argv_array_pushf(&cmd_args, + argv_array_pushf(&cmd.args, "--unpack-unreachable=%s", unpack_unreachable); else if (pack_everything & LOOSEN_UNREACHABLE) - argv_array_push(&cmd_args, + argv_array_push(&cmd.args, "--unpack-unreachable"); } } else { - argv_array_push(&cmd_args, "--unpacked"); - argv_array_push(&cmd_args, "--incremental"); + argv_array_push(&cmd.args, "--unpacked"); + argv_array_push(&cmd.args, "--incremental"); } if (local) - argv_array_push(&cmd_args, "--local"); + argv_array_push(&cmd.args, "--local"); if (quiet) - argv_array_push(&cmd_args, "--quiet"); + argv_array_push(&cmd.args, "--quiet"); if (delta_base_offset) - argv_array_push(&cmd_args, "--delta-base-offset"); + argv_array_push(&cmd.args, "--delta-base-offset"); - argv_array_push(&cmd_args, packtmp); + argv_array_push(&cmd.args, packtmp); - cmd.argv = cmd_args.argv; cmd.git_cmd = 1; cmd.out = -1; cmd.no_stdin = 1; @@ -269,7 +268,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix) ret = finish_command(&cmd); if (ret) return ret; - argv_array_clear(&cmd_args); if (!names.nr && !quiet) printf("Nothing new to pack.\n"); @@ -378,7 +376,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (delete_redundant) { int opts = 0; - sort_string_list(&names); + string_list_sort(&names); for_each_string_list_item(item, &existing_packs) { char *sha1; size_t len = strlen(item->string); diff --git a/builtin/replace.c b/builtin/replace.c index 8020db8500..85d39b58d8 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -171,8 +171,9 @@ static int replace_object_sha1(const char *object_ref, transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, ref, repl, prev, 0, 1, &err) || - ref_transaction_commit(transaction, NULL, &err)) + ref_transaction_update(transaction, ref, repl, prev, + 0, 1, NULL, &err) || + ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); diff --git a/builtin/reset.c b/builtin/reset.c index 855d478e3b..4c08ddc1ca 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 "lockfile.h" #include "tag.h" #include "object.h" #include "commit.h" diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 35d3c43ed6..95328b80d9 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -279,7 +279,7 @@ static int try_difference(const char *arg) struct commit *a, *b; a = lookup_commit_reference(sha1); b = lookup_commit_reference(end); - exclude = get_merge_bases(a, b, 1); + exclude = get_merge_bases(a, b); while (exclude) { struct commit_list *n = exclude->next; show_rev(REVERSED, diff --git a/builtin/rm.c b/builtin/rm.c index 2b61d3bd41..d8a9c86dd1 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -3,8 +3,8 @@ * * Copyright (C) Linus Torvalds 2006 */ -#include "cache.h" #include "builtin.h" +#include "lockfile.h" #include "dir.h" #include "cache-tree.h" #include "tree-walk.h" diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 199b081e9b..365228aa8d 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -6,7 +6,10 @@ #include "parse-options.h" static const char* show_branch_usage[] = { - N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"), + N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order]\n" + " [--current] [--color[=<when>] | --no-color] [--sparse]\n" + " [--more=<n> | --list | --independent | --merge-base]\n" + " [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"), N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"), NULL }; @@ -728,7 +731,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (ac == 0) { static const char *fake_av[2]; - fake_av[0] = resolve_refdup("HEAD", sha1, 1, NULL); + fake_av[0] = resolve_refdup("HEAD", + RESOLVE_REF_READING, + sha1, NULL); fake_av[1] = NULL; av = fake_av; ac = 1; @@ -789,7 +794,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } } - head_p = resolve_ref_unsafe("HEAD", head_sha1, 1, NULL); + head_p = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, + head_sha1, NULL); if (head_p) { head_len = strlen(head_p); memcpy(head, head_p, head_len + 1); diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c index b6a711d319..29fb3f1c20 100644 --- a/builtin/symbolic-ref.c +++ b/builtin/symbolic-ref.c @@ -13,7 +13,7 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print) { unsigned char sha1[20]; int flag; - const char *refname = resolve_ref_unsafe(HEAD, sha1, 0, &flag); + const char *refname = resolve_ref_unsafe(HEAD, 0, sha1, &flag); if (!refname) die("No such ref: %s", HEAD); diff --git a/builtin/tag.c b/builtin/tag.c index a81b9e4174..e633f4efdb 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -733,8 +733,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, object, prev, - 0, 1, &err) || - ref_transaction_commit(transaction, NULL, &err)) + 0, 1, NULL, &err) || + ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); if (force && !is_null_sha1(prev) && hashcmp(prev, object)) diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 855d94b90b..ac6667242c 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -91,7 +91,7 @@ static void use(int bytes) static void *get_data(unsigned long size) { git_zstream stream; - void *buf = xmalloc(size); + void *buf = xmallocz(size); memset(&stream, 0, sizeof(stream)); diff --git a/builtin/update-index.c b/builtin/update-index.c index e8c7fd4d49..b0e3dc9105 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -4,6 +4,7 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "lockfile.h" #include "quote.h" #include "cache-tree.h" #include "tree-walk.h" @@ -942,7 +943,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (newfd < 0) { if (refresh_args.flags & REFRESH_QUIET) exit(128); - unable_to_lock_index_die(get_index_file(), lock_error); + unable_to_lock_die(get_index_file(), lock_error); } if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die("Unable to write new index file"); diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 54a48c0cfa..1993529521 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -14,6 +14,7 @@ static const char * const git_update_ref_usage[] = { static char line_termination = '\n'; static int update_flags; +static const char *msg; /* * Parse one whitespace- or NUL-terminated, possibly C-quoted argument @@ -198,7 +199,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, die("update %s: extra input: %s", refname, next); if (ref_transaction_update(transaction, refname, new_sha1, old_sha1, - update_flags, have_old, &err)) + update_flags, have_old, msg, &err)) die("%s", err.buf); update_flags = 0; @@ -229,7 +230,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, die("create %s: extra input: %s", refname, next); if (ref_transaction_create(transaction, refname, new_sha1, - update_flags, &err)) + update_flags, msg, &err)) die("%s", err.buf); update_flags = 0; @@ -264,7 +265,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, old_sha1, - update_flags, have_old, &err)) + update_flags, have_old, msg, &err)) die("%s", err.buf); update_flags = 0; @@ -281,26 +282,22 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, char *refname; unsigned char new_sha1[20]; unsigned char old_sha1[20]; - int have_old; 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(new_sha1); - have_old = 0; - } else { - hashcpy(new_sha1, old_sha1); - have_old = 1; - } + PARSE_SHA1_OLD)) + hashclr(old_sha1); + + hashcpy(new_sha1, old_sha1); if (*next != line_termination) die("verify %s: extra input: %s", refname, next); if (ref_transaction_update(transaction, refname, new_sha1, old_sha1, - update_flags, have_old, &err)) + update_flags, 1, msg, &err)) die("%s", err.buf); update_flags = 0; @@ -354,7 +351,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, *msg = NULL; + const char *refname, *oldval; unsigned char sha1[20], oldsha1[20]; int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0; struct option options[] = { @@ -385,7 +382,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) if (end_null) line_termination = '\0'; update_refs_stdin(transaction); - if (ref_transaction_commit(transaction, msg, &err)) + if (ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); strbuf_release(&err); |