diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/apply.c | 3 | ||||
-rw-r--r-- | builtin/archive.c | 2 | ||||
-rw-r--r-- | builtin/bisect--helper.c | 7 | ||||
-rw-r--r-- | builtin/branch.c | 18 | ||||
-rw-r--r-- | builtin/bundle.c | 2 | ||||
-rw-r--r-- | builtin/check-attr.c | 125 | ||||
-rw-r--r-- | builtin/check-ref-format.c | 6 | ||||
-rw-r--r-- | builtin/checkout-index.c | 32 | ||||
-rw-r--r-- | builtin/checkout.c | 25 | ||||
-rw-r--r-- | builtin/clean.c | 5 | ||||
-rw-r--r-- | builtin/clone.c | 138 | ||||
-rw-r--r-- | builtin/commit.c | 102 | ||||
-rw-r--r-- | builtin/config.c | 48 | ||||
-rw-r--r-- | builtin/describe.c | 17 | ||||
-rw-r--r-- | builtin/diff.c | 3 | ||||
-rw-r--r-- | builtin/fetch-pack.c | 32 | ||||
-rw-r--r-- | builtin/fetch.c | 15 | ||||
-rw-r--r-- | builtin/fsck.c | 9 | ||||
-rw-r--r-- | builtin/grep.c | 7 | ||||
-rw-r--r-- | builtin/init-db.c | 2 | ||||
-rw-r--r-- | builtin/log.c | 15 | ||||
-rw-r--r-- | builtin/ls-files.c | 10 | ||||
-rw-r--r-- | builtin/merge.c | 8 | ||||
-rw-r--r-- | builtin/pack-objects.c | 2 | ||||
-rw-r--r-- | builtin/patch-id.c | 10 | ||||
-rw-r--r-- | builtin/push.c | 19 | ||||
-rw-r--r-- | builtin/receive-pack.c | 45 | ||||
-rw-r--r-- | builtin/remote.c | 2 | ||||
-rw-r--r-- | builtin/revert.c | 7 | ||||
-rw-r--r-- | builtin/show-branch.c | 9 | ||||
-rw-r--r-- | builtin/update-ref.c | 2 |
31 files changed, 446 insertions, 281 deletions
diff --git a/builtin/apply.c b/builtin/apply.c index f2edc52818..aaa39fe17e 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -1407,6 +1407,9 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc "%d leading pathname components (line %d)" , p_value, linenr); patch->old_name = patch->new_name = patch->def_name; } + if (!patch->is_delete && !patch->new_name) + die("git diff header lacks filename information " + "(line %d)", linenr); patch->is_toplevel_relative = 1; *hdrsize = git_hdr_len; return offset; diff --git a/builtin/archive.c b/builtin/archive.c index 883c0092ad..931956def9 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -61,6 +61,8 @@ static int run_remote_archiver(int argc, const char **argv, if (strcmp(buf, "ACK")) { if (len > 5 && !prefixcmp(buf, "NACK ")) die(_("git archive: NACK %s"), buf + 5); + if (len > 4 && !prefixcmp(buf, "ERR ")) + die(_("remote error: %s"), buf + 4); die(_("git archive: protocol error")); } diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c index 5b226399e1..8d325a5179 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c @@ -4,16 +4,19 @@ #include "bisect.h" static const char * const git_bisect_helper_usage[] = { - "git bisect--helper --next-all", + "git bisect--helper --next-all [--no-checkout]", NULL }; int cmd_bisect__helper(int argc, const char **argv, const char *prefix) { int next_all = 0; + int no_checkout = 0; struct option options[] = { OPT_BOOLEAN(0, "next-all", &next_all, "perform 'git bisect next'"), + OPT_BOOLEAN(0, "no-checkout", &no_checkout, + "update BISECT_HEAD instead of checking out the current commit"), OPT_END() }; @@ -24,5 +27,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) usage_with_options(git_bisect_helper_usage, options); /* next-all */ - return bisect_next_all(prefix); + return bisect_next_all(prefix, no_checkout); } diff --git a/builtin/branch.c b/builtin/branch.c index 3142daa57a..f49596f826 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -71,7 +71,7 @@ static int parse_branch_color_slot(const char *var, int ofs) static int git_branch_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "color.branch")) { - branch_use_color = git_config_colorbool(var, value, -1); + branch_use_color = git_config_colorbool(var, value); return 0; } if (!prefixcmp(var, "color.branch.")) { @@ -88,7 +88,7 @@ static int git_branch_config(const char *var, const char *value, void *cb) static const char *branch_get_color(enum color_branch ix) { - if (branch_use_color > 0) + if (want_color(branch_use_color)) return branch_colors[ix]; return ""; } @@ -566,11 +566,7 @@ static void rename_branch(const char *oldname, const char *newname, int force) die(_("Invalid branch name: '%s'"), oldname); } - if (strbuf_check_branch_ref(&newref, newname)) - die(_("Invalid branch name: '%s'"), newname); - - if (resolve_ref(newref.buf, sha1, 1, NULL) && !force) - die(_("A branch named '%s' already exists."), newref.buf + 11); + validate_new_branchname(newname, &newref, force, 0); strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); @@ -613,7 +609,7 @@ static int opt_parse_merge_filter(const struct option *opt, const char *arg, int int cmd_branch(int argc, const char **argv, const char *prefix) { int delete = 0, rename = 0, force_create = 0; - int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0; + int verbose = 0, abbrev = -1, detached = 0; int reflog = 0; enum branch_track track; int kinds = REF_LOCAL_BRANCH; @@ -673,9 +669,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix) git_config(git_branch_config, NULL); - if (branch_use_color == -1) - branch_use_color = git_use_color_default; - track = git_branch_track; head = resolve_ref("HEAD", head_sha1, 0, NULL); @@ -696,6 +689,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (!!delete + !!rename + !!force_create > 1) usage_with_options(builtin_branch_usage, options); + if (abbrev == -1) + abbrev = DEFAULT_ABBREV; + if (delete) return delete_branches(argc, argv, delete > 1, kinds); else if (argc == 0) diff --git a/builtin/bundle.c b/builtin/bundle.c index 81046a9cb8..92a8a6026a 100644 --- a/builtin/bundle.c +++ b/builtin/bundle.c @@ -58,7 +58,7 @@ int cmd_bundle(int argc, const char **argv, const char *prefix) } else if (!strcmp(cmd, "unbundle")) { if (!startup_info->have_repository) die(_("Need a repository to unbundle.")); - return !!unbundle(&header, bundle_fd) || + return !!unbundle(&header, bundle_fd, 0) || list_bundle_refs(&header, argc, argv); } else usage(builtin_bundle_usage); diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 3016d29caa..708988a0e1 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -4,28 +4,28 @@ #include "quote.h" #include "parse-options.h" +static int all_attrs; static int stdin_paths; static const char * const check_attr_usage[] = { -"git check-attr attr... [--] pathname...", -"git check-attr --stdin attr... < <list-of-paths>", +"git check-attr [-a | --all | attr...] [--] pathname...", +"git check-attr --stdin [-a | --all | attr...] < <list-of-paths>", NULL }; static int null_term_line; static const struct option check_attr_options[] = { + OPT_BOOLEAN('a', "all", &all_attrs, "report all attributes set on file"), OPT_BOOLEAN(0 , "stdin", &stdin_paths, "read file names from stdin"), OPT_BOOLEAN('z', NULL, &null_term_line, "input paths are terminated by a null character"), OPT_END() }; -static void check_attr(int cnt, struct git_attr_check *check, - const char** name, const char *file) +static void output_attr(int cnt, struct git_attr_check *check, + const char *file) { int j; - if (git_checkattr(file, cnt, check)) - die("git_checkattr died"); for (j = 0; j < cnt; j++) { const char *value = check[j].value; @@ -37,12 +37,30 @@ static void check_attr(int cnt, struct git_attr_check *check, value = "unspecified"; quote_c_style(file, NULL, stdout, 0); - printf(": %s: %s\n", name[j], value); + printf(": %s: %s\n", git_attr_name(check[j].attr), value); } } -static void check_attr_stdin_paths(int cnt, struct git_attr_check *check, - const char** name) +static void check_attr(const char *prefix, int cnt, + struct git_attr_check *check, const char *file) +{ + char *full_path = + prefix_path(prefix, prefix ? strlen(prefix) : 0, file); + if (check != NULL) { + if (git_check_attr(full_path, cnt, check)) + die("git_check_attr died"); + output_attr(cnt, check, file); + } else { + if (git_all_attrs(full_path, &cnt, &check)) + die("git_all_attrs died"); + output_attr(cnt, check, file); + free(check); + } + free(full_path); +} + +static void check_attr_stdin_paths(const char *prefix, int cnt, + struct git_attr_check *check) { struct strbuf buf, nbuf; int line_termination = null_term_line ? 0 : '\n'; @@ -56,23 +74,26 @@ static void check_attr_stdin_paths(int cnt, struct git_attr_check *check, die("line is badly quoted"); strbuf_swap(&buf, &nbuf); } - check_attr(cnt, check, name, buf.buf); + check_attr(prefix, cnt, check, buf.buf); maybe_flush_or_die(stdout, "attribute to stdout"); } strbuf_release(&buf); strbuf_release(&nbuf); } +static NORETURN void error_with_usage(const char *msg) +{ + error("%s", msg); + usage_with_options(check_attr_usage, check_attr_options); +} + int cmd_check_attr(int argc, const char **argv, const char *prefix) { struct git_attr_check *check; - int cnt, i, doubledash; - const char *errstr = NULL; + int cnt, i, doubledash, filei; argc = parse_options(argc, argv, prefix, check_attr_options, check_attr_usage, PARSE_OPT_KEEP_DASHDASH); - if (!argc) - usage_with_options(check_attr_usage, check_attr_options); if (read_cache() < 0) { die("invalid cache"); @@ -84,39 +105,63 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix) doubledash = i; } - /* If there is no double dash, we handle only one attribute */ - if (doubledash < 0) { - cnt = 1; - doubledash = 0; - } else + /* Process --all and/or attribute arguments: */ + if (all_attrs) { + if (doubledash >= 1) + error_with_usage("Attributes and --all both specified"); + + cnt = 0; + filei = doubledash + 1; + } else if (doubledash == 0) { + error_with_usage("No attribute specified"); + } else if (doubledash < 0) { + if (!argc) + error_with_usage("No attribute specified"); + + if (stdin_paths) { + /* Treat all arguments as attribute names. */ + cnt = argc; + filei = argc; + } else { + /* Treat exactly one argument as an attribute name. */ + cnt = 1; + filei = 1; + } + } else { cnt = doubledash; - doubledash++; - - if (cnt <= 0) - errstr = "No attribute specified"; - else if (stdin_paths && doubledash < argc) - errstr = "Can't specify files with --stdin"; - if (errstr) { - error("%s", errstr); - usage_with_options(check_attr_usage, check_attr_options); + filei = doubledash + 1; } - check = xcalloc(cnt, sizeof(*check)); - for (i = 0; i < cnt; i++) { - const char *name; - struct git_attr *a; - name = argv[i]; - a = git_attr(name); - if (!a) - return error("%s: not a valid attribute name", name); - check[i].attr = a; + /* Check file argument(s): */ + if (stdin_paths) { + if (filei < argc) + error_with_usage("Can't specify files with --stdin"); + } else { + if (filei >= argc) + error_with_usage("No file specified"); + } + + if (all_attrs) { + check = NULL; + } else { + check = xcalloc(cnt, sizeof(*check)); + for (i = 0; i < cnt; i++) { + const char *name; + struct git_attr *a; + name = argv[i]; + a = git_attr(name); + if (!a) + return error("%s: not a valid attribute name", + name); + check[i].attr = a; + } } if (stdin_paths) - check_attr_stdin_paths(cnt, check, argv); + check_attr_stdin_paths(prefix, cnt, check); else { - for (i = doubledash; i < argc; i++) - check_attr(cnt, check, argv, argv[i]); + for (i = filei; i < argc; i++) + check_attr(prefix, cnt, check, argv[i]); maybe_flush_or_die(stdout, "attribute to stdout"); } return 0; diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c index ae3f28115a..0723cf245e 100644 --- a/builtin/check-ref-format.c +++ b/builtin/check-ref-format.c @@ -12,8 +12,8 @@ static const char builtin_check_ref_format_usage[] = " or: git check-ref-format --branch <branchname-shorthand>"; /* - * Replace each run of adjacent slashes in src with a single slash, - * and write the result to dst. + * Remove leading slashes and replace each run of adjacent slashes in + * src with a single slash, and write the result to dst. * * This function is similar to normalize_path_copy(), but stripped down * to meet check_ref_format's simpler needs. @@ -21,7 +21,7 @@ static const char builtin_check_ref_format_usage[] = static void collapse_slashes(char *dst, const char *src) { char ch; - char prev = '\0'; + char prev = '/'; while ((ch = *src++) != '\0') { if (prev == '/' && ch == prev) diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index f1fec24745..c16d82b7de 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -3,38 +3,6 @@ * * Copyright (C) 2005 Linus Torvalds * - * Careful: order of argument flags does matter. For example, - * - * git checkout-index -a -f file.c - * - * Will first check out all files listed in the cache (but not - * overwrite any old ones), and then force-checkout "file.c" a - * second time (ie that one _will_ overwrite any old contents - * with the same filename). - * - * Also, just doing "git checkout-index" does nothing. You probably - * meant "git checkout-index -a". And if you want to force it, you - * want "git checkout-index -f -a". - * - * Intuitiveness is not the goal here. Repeatability is. The - * reason for the "no arguments means no work" thing is that - * from scripts you are supposed to be able to do things like - * - * find . -name '*.h' -print0 | xargs -0 git checkout-index -f -- - * - * or: - * - * find . -name '*.h' -print0 | git checkout-index -f -z --stdin - * - * which will force all existing *.h files to be replaced with - * their cached copies. If an empty command line implied "all", - * then this would force-refresh everything in the cache, which - * was not the point. - * - * Oh, and the "--" is just a good idea when you know the rest - * will be filenames. Just so that you wouldn't have a filename - * of "-a" causing problems (not possible in the above example, - * but get used to it in scripting!). */ #include "builtin.h" #include "cache.h" diff --git a/builtin/checkout.c b/builtin/checkout.c index d647a31303..75dbe76136 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -71,7 +71,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen, hashcpy(ce->sha1, sha1); memcpy(ce->name, base, baselen); memcpy(ce->name + baselen, pathname, len - baselen); - ce->ce_flags = create_ce_flags(len, 0); + ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE; ce->ce_mode = create_ce_mode(mode); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); return 0; @@ -201,7 +201,7 @@ static int checkout_merged(int pos, struct checkout *state) } static int checkout_paths(struct tree *source_tree, const char **pathspec, - struct checkout_opts *opts) + const char *prefix, struct checkout_opts *opts) { int pos; struct checkout state; @@ -228,10 +228,12 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; + if (source_tree && !(ce->ce_flags & CE_UPDATE)) + continue; match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched); } - if (report_path_error(ps_matched, pathspec, 0)) + if (report_path_error(ps_matched, pathspec, prefix)) return 1; /* "checkout -m path" to recreate conflicted state */ @@ -266,6 +268,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, state.refresh_cache = 1; for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; + if (source_tree && !(ce->ce_flags & CE_UPDATE)) + continue; if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) { if (!ce_stage(ce)) { errs |= checkout_entry(ce, &state, NULL); @@ -1064,7 +1068,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge) die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.")); - return checkout_paths(source_tree, pathspec, &opts); + return checkout_paths(source_tree, pathspec, prefix, &opts); } if (patch_mode) @@ -1072,15 +1076,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (opts.new_branch) { struct strbuf buf = STRBUF_INIT; - if (strbuf_check_branch_ref(&buf, opts.new_branch)) - die(_("git checkout: we do not like '%s' as a branch name."), - opts.new_branch); - if (ref_exists(buf.buf)) { - opts.branch_exists = 1; - if (!opts.new_branch_force) - die(_("git checkout: branch %s already exists"), - opts.new_branch); - } + + opts.branch_exists = validate_new_branchname(opts.new_branch, &buf, + !!opts.new_branch_force, 0); + strbuf_release(&buf); } diff --git a/builtin/clean.c b/builtin/clean.c index 75697f7111..0c7b3d0f4c 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -54,7 +54,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) OPT_BOOLEAN('d', NULL, &remove_directories, "remove whole directories"), { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern", - "exclude <pattern>", PARSE_OPT_NONEG, exclude_cb }, + "add <pattern> to ignore rules", PARSE_OPT_NONEG, exclude_cb }, OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"), OPT_BOOLEAN('X', NULL, &ignored_only, "remove only ignored files"), @@ -98,7 +98,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix) setup_standard_excludes(&dir); for (i = 0; i < exclude_list.nr; i++) - add_exclude(exclude_list.items[i].string, "", 0, dir.exclude_list); + add_exclude(exclude_list.items[i].string, "", 0, + &dir.exclude_list[EXC_CMDL]); pathspec = get_pathspec(prefix, argv); diff --git a/builtin/clone.c b/builtin/clone.c index 7663bc22c9..488f48e9a5 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -39,7 +39,7 @@ static const char * const builtin_clone_usage[] = { static int option_no_checkout, option_bare, option_mirror; static int option_local, option_no_hardlinks, option_shared, option_recursive; -static char *option_template, *option_reference, *option_depth; +static char *option_template, *option_depth; static char *option_origin = NULL; static char *option_branch = NULL; static const char *real_git_dir; @@ -47,6 +47,16 @@ static char *option_upload_pack = "git-upload-pack"; static int option_verbosity; static int option_progress; static struct string_list option_config; +static struct string_list option_reference; + +static int opt_parse_reference(const struct option *opt, const char *arg, int unset) +{ + struct string_list *option_reference = opt->value; + if (!arg) + return -1; + string_list_append(option_reference, arg); + return 0; +} static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), @@ -72,8 +82,8 @@ static struct option builtin_clone_options[] = { "initialize submodules in the clone"), OPT_STRING(0, "template", &option_template, "template-directory", "directory from which templates will be used"), - OPT_STRING(0, "reference", &option_reference, "repo", - "reference repository"), + OPT_CALLBACK(0 , "reference", &option_reference, "repo", + "reference repository", &opt_parse_reference), OPT_STRING('o', "origin", &option_origin, "branch", "use <branch> instead of 'origin' to track upstream"), OPT_STRING('b', "branch", &option_branch, "branch", @@ -103,9 +113,26 @@ static char *get_repo_path(const char *repo, int *is_bundle) for (i = 0; i < ARRAY_SIZE(suffix); i++) { const char *path; path = mkpath("%s%s", repo, suffix[i]); - if (is_directory(path)) { + if (stat(path, &st)) + continue; + if (S_ISDIR(st.st_mode)) { *is_bundle = 0; return xstrdup(absolute_path(path)); + } else if (S_ISREG(st.st_mode) && st.st_size > 8) { + /* Is it a "gitfile"? */ + char signature[8]; + int len, fd = open(path, O_RDONLY); + if (fd < 0) + continue; + len = read_in_full(fd, signature, 8); + close(fd); + if (len != 8 || strncmp(signature, "gitdir: ", 8)) + continue; + path = read_gitfile(path); + if (path) { + *is_bundle = 0; + return xstrdup(absolute_path(path)); + } } } @@ -199,39 +226,80 @@ static void strip_trailing_slashes(char *dir) *end = '\0'; } -static void setup_reference(const char *repo) +static int add_one_reference(struct string_list_item *item, void *cb_data) { - const char *ref_git; - char *ref_git_copy; - + char *ref_git; + struct strbuf alternate = STRBUF_INIT; struct remote *remote; struct transport *transport; const struct ref *extra; - ref_git = real_path(option_reference); - - if (is_directory(mkpath("%s/.git/objects", ref_git))) - ref_git = mkpath("%s/.git", ref_git); - else if (!is_directory(mkpath("%s/objects", ref_git))) + /* Beware: real_path() and mkpath() return static buffer */ + ref_git = xstrdup(real_path(item->string)); + if (is_directory(mkpath("%s/.git/objects", ref_git))) { + char *ref_git_git = xstrdup(mkpath("%s/.git", ref_git)); + free(ref_git); + ref_git = ref_git_git; + } else if (!is_directory(mkpath("%s/objects", ref_git))) die(_("reference repository '%s' is not a local directory."), - option_reference); + item->string); - ref_git_copy = xstrdup(ref_git); + strbuf_addf(&alternate, "%s/objects", ref_git); + add_to_alternates_file(alternate.buf); + strbuf_release(&alternate); - add_to_alternates_file(ref_git_copy); - - remote = remote_get(ref_git_copy); - transport = transport_get(remote, ref_git_copy); + remote = remote_get(ref_git); + transport = transport_get(remote, ref_git); for (extra = transport_get_remote_refs(transport); extra; extra = extra->next) add_extra_ref(extra->name, extra->old_sha1, 0); transport_disconnect(transport); + free(ref_git); + return 0; +} - free(ref_git_copy); +static void setup_reference(void) +{ + for_each_string_list(&option_reference, add_one_reference, NULL); } -static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) +static void copy_alternates(struct strbuf *src, struct strbuf *dst, + const char *src_repo) +{ + /* + * Read from the source objects/info/alternates file + * and copy the entries to corresponding file in the + * destination repository with add_to_alternates_file(). + * Both src and dst have "$path/objects/info/alternates". + * + * Instead of copying bit-for-bit from the original, + * we need to append to existing one so that the already + * created entry via "clone -s" is not lost, and also + * to turn entries with paths relative to the original + * absolute, so that they can be used in the new repository. + */ + FILE *in = fopen(src->buf, "r"); + struct strbuf line = STRBUF_INIT; + + while (strbuf_getline(&line, in, '\n') != EOF) { + char *abs_path, abs_buf[PATH_MAX]; + if (!line.len || line.buf[0] == '#') + continue; + if (is_absolute_path(line.buf)) { + add_to_alternates_file(line.buf); + continue; + } + abs_path = mkpath("%s/objects/%s", src_repo, line.buf); + normalize_path_copy(abs_buf, abs_path); + add_to_alternates_file(abs_buf); + } + strbuf_release(&line); + fclose(in); +} + +static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, + const char *src_repo, int src_baselen) { struct dirent *de; struct stat buf; @@ -267,7 +335,14 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) } if (S_ISDIR(buf.st_mode)) { if (de->d_name[0] != '.') - copy_or_link_directory(src, dest); + copy_or_link_directory(src, dest, + src_repo, src_baselen); + continue; + } + + /* Files that cannot be copied bit-for-bit... */ + if (!strcmp(src->buf + src_baselen, "/info/alternates")) { + copy_alternates(src, dest, src_repo); continue; } @@ -290,17 +365,20 @@ static const struct ref *clone_local(const char *src_repo, const char *dest_repo) { const struct ref *ret; - struct strbuf src = STRBUF_INIT; - struct strbuf dest = STRBUF_INIT; struct remote *remote; struct transport *transport; - if (option_shared) - add_to_alternates_file(src_repo); - else { + if (option_shared) { + struct strbuf alt = STRBUF_INIT; + strbuf_addf(&alt, "%s/objects", src_repo); + add_to_alternates_file(alt.buf); + strbuf_release(&alt); + } else { + struct strbuf src = STRBUF_INIT; + struct strbuf dest = STRBUF_INIT; strbuf_addf(&src, "%s/objects", src_repo); strbuf_addf(&dest, "%s/objects", dest_repo); - copy_or_link_directory(&src, &dest); + copy_or_link_directory(&src, &dest, src_repo, src.len); strbuf_release(&src); strbuf_release(&dest); } @@ -544,8 +622,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) git_config_set(key.buf, repo); strbuf_reset(&key); - if (option_reference) - setup_reference(git_dir); + if (option_reference.nr) + setup_reference(); fetch_pattern = value.buf; refspec = parse_fetch_refspec(1, &fetch_pattern); diff --git a/builtin/commit.c b/builtin/commit.c index cb738574f7..cbc9613ec6 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -62,8 +62,6 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\ "\n" "Otherwise, please use 'git reset'\n"); -static unsigned char head_sha1[20]; - static const char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; static struct lock_file index_lock; /* real index */ @@ -102,7 +100,7 @@ static enum { static char *cleanup_arg; static enum commit_whence whence; -static int use_editor = 1, initial_commit, include_status = 1; +static int use_editor = 1, include_status = 1; static int show_ignored_in_status; static const char *only_include_assumed; static struct strbuf message; @@ -274,7 +272,7 @@ static int list_paths(struct string_list *list, const char *with_tree, item->util = item; /* better a valid pointer than a fake one */ } - return report_path_error(m, pattern, prefix ? strlen(prefix) : 0); + return report_path_error(m, pattern, prefix); } static void add_remove_files(struct string_list *list) @@ -296,13 +294,13 @@ static void add_remove_files(struct string_list *list) } } -static void create_base_index(void) +static void create_base_index(const struct commit *current_head) { struct tree *tree; struct unpack_trees_options opts; struct tree_desc t; - if (initial_commit) { + if (!current_head) { discard_cache(); return; } @@ -315,7 +313,7 @@ static void create_base_index(void) opts.dst_index = &the_index; opts.fn = oneway_merge; - tree = parse_tree_indirect(head_sha1); + tree = parse_tree_indirect(current_head->object.sha1); if (!tree) die(_("failed to unpack HEAD tree object")); parse_tree(tree); @@ -334,7 +332,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, int is_status) +static char *prepare_index(int argc, const char **argv, const char *prefix, + const struct commit *current_head, int is_status) { int fd; struct string_list partial; @@ -450,7 +449,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int memset(&partial, 0, sizeof(partial)); partial.strdup_strings = 1; - if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec)) + if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, pathspec)) exit(1); discard_cache(); @@ -469,7 +468,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int (uintmax_t) getpid()), LOCK_DIE_ON_ERROR); - create_base_index(); + create_base_index(current_head); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); @@ -518,12 +517,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int return s->commitable; } -static int is_a_merge(const unsigned char *sha1) +static int is_a_merge(const struct commit *current_head) { - struct commit *commit = lookup_commit(sha1); - if (!commit || parse_commit(commit)) - die(_("could not parse HEAD commit")); - return !!(commit->parents && commit->parents->next); + return !!(current_head->parents && current_head->parents->next); } static const char sign_off_header[] = "Signed-off-by: "; @@ -627,6 +623,7 @@ static char *cut_ident_timestamp_part(char *string) } static int prepare_to_commit(const char *index_file, const char *prefix, + struct commit *current_head, struct wt_status *s, struct strbuf *author_ident) { @@ -848,7 +845,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, * empty due to conflict resolution, which the user should okay. */ if (!commitable && whence != FROM_MERGE && !allow_empty && - !(amend && is_a_merge(head_sha1))) { + !(amend && is_a_merge(current_head))) { run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); @@ -1006,6 +1003,7 @@ static const char *read_commit_message(const char *name) static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], const char *prefix, + struct commit *current_head, struct wt_status *s) { int f = 0; @@ -1026,11 +1024,8 @@ static int parse_and_validate_options(int argc, const char *argv[], if (!use_editor) setenv("GIT_EDITOR", ":", 1); - if (get_sha1("HEAD", head_sha1)) - initial_commit = 1; - /* Sanity check options */ - if (amend && initial_commit) + if (amend && !current_head) die(_("You have nothing to amend.")); if (amend && whence != FROM_COMMIT) die(_("You are in the middle of a %s -- cannot amend."), whence_s()); @@ -1102,12 +1097,12 @@ static int parse_and_validate_options(int argc, const char *argv[], } static int dry_run_commit(int argc, const char **argv, const char *prefix, - struct wt_status *s) + const struct commit *current_head, struct wt_status *s) { int commitable; const char *index_file; - index_file = prepare_index(argc, argv, prefix, 1); + index_file = prepare_index(argc, argv, prefix, current_head, 1); commitable = run_status(stdout, index_file, prefix, 0, s); rollback_index_files(); @@ -1146,7 +1141,7 @@ static int git_status_config(const char *k, const char *v, void *cb) return 0; } if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { - s->use_color = git_config_colorbool(k, v, -1); + s->use_color = git_config_colorbool(k, v); return 0; } if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { @@ -1239,10 +1234,6 @@ int cmd_status(int argc, const char **argv, const char *prefix) if (s.relative_paths) s.prefix = prefix; - if (s.use_color == -1) - s.use_color = git_use_color_default; - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; switch (status_format) { case STATUS_FORMAT_SHORT: @@ -1260,7 +1251,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) return 0; } -static void print_summary(const char *prefix, const unsigned char *sha1) +static void print_summary(const char *prefix, const unsigned char *sha1, + int initial_commit) { struct rev_info rev; struct commit *commit; @@ -1382,12 +1374,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct strbuf author_ident = STRBUF_INIT; const char *index_file, *reflog_msg; char *nl, *p; - unsigned char commit_sha1[20]; + unsigned char sha1[20]; struct ref_lock *ref_lock; struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; int allow_fast_forward = 1; struct wt_status s; + struct commit *current_head = NULL; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_commit_usage, builtin_commit_options); @@ -1396,40 +1389,38 @@ int cmd_commit(int argc, const char **argv, const char *prefix) git_config(git_commit_config, &s); determine_whence(&s); - if (s.use_color == -1) - s.use_color = git_use_color_default; - argc = parse_and_validate_options(argc, argv, builtin_commit_usage, - prefix, &s); - if (dry_run) { - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - return dry_run_commit(argc, argv, prefix, &s); + if (get_sha1("HEAD", sha1)) + current_head = NULL; + else { + current_head = lookup_commit(sha1); + if (!current_head || parse_commit(current_head)) + die(_("could not parse HEAD commit")); } - index_file = prepare_index(argc, argv, prefix, 0); + argc = parse_and_validate_options(argc, argv, builtin_commit_usage, + prefix, current_head, &s); + if (dry_run) + return dry_run_commit(argc, argv, prefix, current_head, &s); + index_file = prepare_index(argc, argv, prefix, current_head, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ - if (!prepare_to_commit(index_file, prefix, &s, &author_ident)) { + if (!prepare_to_commit(index_file, prefix, + current_head, &s, &author_ident)) { rollback_index_files(); return 1; } /* Determine parents */ reflog_msg = getenv("GIT_REFLOG_ACTION"); - if (initial_commit) { + if (!current_head) { if (!reflog_msg) reflog_msg = "commit (initial)"; } else if (amend) { struct commit_list *c; - struct commit *commit; if (!reflog_msg) reflog_msg = "commit (amend)"; - commit = lookup_commit(head_sha1); - if (!commit || parse_commit(commit)) - die(_("could not parse HEAD commit")); - - for (c = commit->parents; c; c = c->next) + for (c = current_head->parents; c; c = c->next) pptr = &commit_list_insert(c->item, pptr)->next; } else if (whence == FROM_MERGE) { struct strbuf m = STRBUF_INIT; @@ -1437,7 +1428,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!reflog_msg) reflog_msg = "commit (merge)"; - pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; + pptr = &commit_list_insert(current_head, pptr)->next; fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) die_errno(_("could not open '%s' for reading"), @@ -1463,7 +1454,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) reflog_msg = (whence == FROM_CHERRY_PICK) ? "commit (cherry-pick)" : "commit"; - pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; + pptr = &commit_list_insert(current_head, pptr)->next; } /* Finally, get the commit message */ @@ -1489,7 +1480,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) exit(1); } - if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1, + if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1, author_ident.buf)) { rollback_index_files(); die(_("failed to write commit object")); @@ -1497,7 +1488,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) strbuf_release(&author_ident); ref_lock = lock_any_ref_for_update("HEAD", - initial_commit ? NULL : head_sha1, + !current_head + ? NULL + : current_head->object.sha1, 0); nl = strchr(sb.buf, '\n'); @@ -1512,7 +1505,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) rollback_index_files(); die(_("cannot lock HEAD ref")); } - if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) { + if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) { rollback_index_files(); die(_("cannot update HEAD ref")); } @@ -1534,13 +1527,14 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct notes_rewrite_cfg *cfg; cfg = init_copy_notes_for_rewrite("amend"); if (cfg) { - copy_note_for_rewrite(cfg, head_sha1, commit_sha1); + /* we are amending, so current_head is not NULL */ + copy_note_for_rewrite(cfg, current_head->object.sha1, sha1); finish_copy_notes_for_rewrite(cfg); } - run_rewrite_hook(head_sha1, commit_sha1); + run_rewrite_hook(current_head->object.sha1, sha1); } if (!quiet) - print_summary(prefix, commit_sha1); + print_summary(prefix, sha1, !current_head); return 0; } diff --git a/builtin/config.c b/builtin/config.c index 211e118d57..0315ad76f8 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -99,6 +99,7 @@ static int show_config(const char *key_, const char *value_, void *cb) const char *vptr = value; int must_free_vptr = 0; int dup_error = 0; + int must_print_delim = 0; if (!use_key_regexp && strcmp(key_, key)) return 0; @@ -109,10 +110,8 @@ static int show_config(const char *key_, const char *value_, void *cb) return 0; if (show_keys) { - if (value_) - printf("%s%c", key_, key_delim); - else - printf("%s", key_); + printf("%s", key_); + must_print_delim = 1; } if (seen && !do_all) dup_error = 1; @@ -130,16 +129,23 @@ static int show_config(const char *key_, const char *value_, void *cb) } else if (types == TYPE_PATH) { git_config_pathname(&vptr, key_, value_); must_free_vptr = 1; + } else if (value_) { + vptr = value_; + } else { + /* Just show the key name */ + vptr = ""; + must_print_delim = 0; } - else - vptr = value_?value_:""; seen++; if (dup_error) { error("More than one value for the key %s: %s", key_, vptr); } - else + else { + if (must_print_delim) + printf("%c", key_delim); printf("%s%c", vptr, term); + } if (must_free_vptr) /* If vptr must be freed, it's a pointer to a * dynamically allocated buffer, it's safe to cast to @@ -303,24 +309,18 @@ static void get_color(const char *def_color) fputs(parsed_color, stdout); } -static int stdout_is_tty; static int get_colorbool_found; static int get_diff_color_found; +static int get_color_ui_found; static int git_get_colorbool_config(const char *var, const char *value, void *cb) { - if (!strcmp(var, get_colorbool_slot)) { - get_colorbool_found = - git_config_colorbool(var, value, stdout_is_tty); - } - if (!strcmp(var, "diff.color")) { - get_diff_color_found = - git_config_colorbool(var, value, stdout_is_tty); - } - if (!strcmp(var, "color.ui")) { - git_use_color_default = git_config_colorbool(var, value, stdout_is_tty); - return 0; - } + if (!strcmp(var, get_colorbool_slot)) + get_colorbool_found = git_config_colorbool(var, value); + else if (!strcmp(var, "diff.color")) + get_diff_color_found = git_config_colorbool(var, value); + else if (!strcmp(var, "color.ui")) + get_color_ui_found = git_config_colorbool(var, value); return 0; } @@ -334,9 +334,11 @@ static int get_colorbool(int print) if (!strcmp(get_colorbool_slot, "color.diff")) get_colorbool_found = get_diff_color_found; if (get_colorbool_found < 0) - get_colorbool_found = git_use_color_default; + get_colorbool_found = get_color_ui_found; } + get_colorbool_found = want_color(get_colorbool_found); + if (print) { printf("%s\n", get_colorbool_found ? "true" : "false"); return 0; @@ -510,9 +512,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } else if (actions == ACTION_GET_COLORBOOL) { if (argc == 1) - stdout_is_tty = git_config_bool("command line", argv[0]); - else if (argc == 0) - stdout_is_tty = isatty(1); + color_stdout_is_tty = git_config_bool("command line", argv[0]); return get_colorbool(argc != 0); } diff --git a/builtin/describe.c b/builtin/describe.c index 66fc291c8a..9f63067f50 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -462,8 +462,21 @@ int cmd_describe(int argc, const char **argv, const char *prefix) die(_("No names found, cannot describe anything.")); if (argc == 0) { - if (dirty && !cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, diff_index_args, prefix)) - dirty = NULL; + if (dirty) { + static struct lock_file index_lock; + int fd; + + read_cache_preload(NULL); + refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, + NULL, NULL, NULL); + fd = hold_locked_index(&index_lock, 0); + if (0 <= fd) + update_index_if_able(&the_index, &index_lock); + + if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, + diff_index_args, prefix)) + dirty = NULL; + } describe("HEAD", 1); } else if (dirty) { die(_("--dirty is incompatible with committishes")); diff --git a/builtin/diff.c b/builtin/diff.c index 69cd5eed78..1118689fb2 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -277,9 +277,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix) gitmodules_config(); git_config(git_diff_ui_config, NULL); - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - init_revisions(&rev, prefix); /* If this is a no-index diff, just run it and exit there. */ diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 4367984102..412bd327b5 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -185,6 +185,36 @@ static void consume_shallow_list(int fd) } } +struct write_shallow_data { + struct strbuf *out; + int use_pack_protocol; + int count; +}; + +static int write_one_shallow(const struct commit_graft *graft, void *cb_data) +{ + struct write_shallow_data *data = cb_data; + const char *hex = sha1_to_hex(graft->sha1); + data->count++; + if (data->use_pack_protocol) + packet_buf_write(data->out, "shallow %s", hex); + else { + strbuf_addstr(data->out, hex); + strbuf_addch(data->out, '\n'); + } + return 0; +} + +static int write_shallow_commits(struct strbuf *out, int use_pack_protocol) +{ + struct write_shallow_data data; + data.out = out; + data.use_pack_protocol = use_pack_protocol; + data.count = 0; + for_each_commit_graft(write_one_shallow, &data); + return data.count; +} + static enum ack_type get_ack(int fd, unsigned char *result_sha1) { static char line[1000]; @@ -395,6 +425,8 @@ static int find_common(int fd[2], unsigned char *result_sha1, case ACK_continue: { struct commit *commit = lookup_commit(result_sha1); + if (!commit) + die("invalid commit %s", sha1_to_hex(result_sha1)); if (args.stateless_rpc && ack == ACK_common && !(commit->object.flags & COMMON)) { diff --git a/builtin/fetch.c b/builtin/fetch.c index 93c99385a9..e422ced929 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -941,6 +941,15 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_fetch_options, builtin_fetch_usage, 0); + if (recurse_submodules != RECURSE_SUBMODULES_OFF) { + if (recurse_submodules_default) { + int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default); + set_config_fetch_recurse_submodules(arg); + } + gitmodules_config(); + git_config(submodule_config, NULL); + } + if (all) { if (argc == 1) die(_("fetch --all does not take a repository argument")); @@ -976,12 +985,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) { const char *options[10]; int num_options = 0; - if (recurse_submodules_default) { - int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default); - set_config_fetch_recurse_submodules(arg); - } - gitmodules_config(); - git_config(submodule_config, NULL); add_options_to_argv(&num_options, options); result = fetch_populated_submodules(num_options, options, submodule_prefix, diff --git a/builtin/fsck.c b/builtin/fsck.c index 5ae0366bc8..df1a88b51a 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -231,12 +231,9 @@ static void check_unreachable_object(struct object *obj) unsigned long size; char *buf = read_sha1_file(obj->sha1, &type, &size); - if (buf) { - if (fwrite(buf, size, 1, f) != 1) - die_errno("Could not write '%s'", - filename); - free(buf); - } + if (buf && fwrite(buf, 1, size, f) != size) + die_errno("Could not write '%s'", filename); + free(buf); } else fprintf(f, "%s\n", sha1_to_hex(obj->sha1)); if (fclose(f)) diff --git a/builtin/grep.c b/builtin/grep.c index 1851797540..a286692e46 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -325,7 +325,7 @@ static int grep_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "color.grep")) - opt->color = git_config_colorbool(var, value, -1); + opt->color = git_config_colorbool(var, value); else if (!strcmp(var, "color.grep.context")) color = opt->color_context; else if (!strcmp(var, "color.grep.filename")) @@ -598,8 +598,11 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct strbuf base; int hit, len; + read_sha1_lock(); data = read_object_with_reference(obj->sha1, tree_type, &size, NULL); + read_sha1_unlock(); + if (!data) die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1)); @@ -898,8 +901,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) strcpy(opt.color_sep, GIT_COLOR_CYAN); opt.color = -1; git_config(grep_config, &opt); - if (opt.color == -1) - opt.color = git_use_color_default; /* * If there is no -- then the paths must exist in the working diff --git a/builtin/init-db.c b/builtin/init-db.c index 025aa47c80..d07554c884 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -347,7 +347,7 @@ static void separate_git_dir(const char *git_dir) const char *src; if (S_ISREG(st.st_mode)) - src = read_gitfile_gently(git_link); + src = read_gitfile(git_link); else if (S_ISDIR(st.st_mode)) src = git_link; else diff --git a/builtin/log.c b/builtin/log.c index 5c2af59004..f5d4930590 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -359,9 +359,6 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix) git_config(git_log_config, NULL); - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - init_revisions(&rev, prefix); rev.diff = 1; rev.simplify_history = 0; @@ -446,9 +443,6 @@ int cmd_show(int argc, const char **argv, const char *prefix) git_config(git_log_config, NULL); - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - init_pathspec(&match_all, NULL); init_revisions(&rev, prefix); rev.diff = 1; @@ -524,9 +518,6 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix) git_config(git_log_config, NULL); - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - init_revisions(&rev, prefix); init_reflog_walk(&rev.reflog_info); rev.verbose_header = 1; @@ -549,9 +540,6 @@ int cmd_log(int argc, const char **argv, const char *prefix) git_config(git_log_config, NULL); - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - init_revisions(&rev, prefix); rev.always_show_header = 1; memset(&opt, 0, sizeof(opt)); @@ -620,7 +608,8 @@ static int git_format_config(const char *var, const char *value, void *cb) string_list_append(&extra_cc, value); return 0; } - if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { + if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") || + !strcmp(var, "color.ui")) { return 0; } if (!strcmp(var, "format.numbered")) { diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 0e98bff0c4..e8a800d3ac 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -353,11 +353,13 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) } } -int report_path_error(const char *ps_matched, const char **pathspec, int prefix_len) +int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix) { /* * Make sure all pathspec matched; otherwise it is an error. */ + struct strbuf sb = STRBUF_INIT; + const char *name; int num, errors = 0; for (num = 0; pathspec[num]; num++) { int other, found_dup; @@ -382,10 +384,12 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_ if (found_dup) continue; + name = quote_path_relative(pathspec[num], -1, &sb, prefix); error("pathspec '%s' did not match any file(s) known to git.", - pathspec[num] + prefix_len); + name); errors++; } + strbuf_release(&sb); return errors; } @@ -577,7 +581,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) if (ps_matched) { int bad; - bad = report_path_error(ps_matched, pathspec, prefix_len); + bad = report_path_error(ps_matched, pathspec, prefix); if (bad) fprintf(stderr, "Did you forget to 'git add'?\n"); diff --git a/builtin/merge.c b/builtin/merge.c index 325891edb6..ab4077f272 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -390,8 +390,6 @@ static void finish(const unsigned char *new_head, const char *msg) opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; - if (diff_use_color_default > 0) - DIFF_OPT_SET(&opts, COLOR_DIFF); if (diff_setup_done(&opts) < 0) die(_("diff_setup_done failed")); diff_tree_sha1(head, new_head, "", &opts); @@ -903,7 +901,7 @@ static int finish_automerge(struct commit_list *common, strbuf_addch(&merge_msg, '\n'); run_prepare_commit_msg(); commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL); - strbuf_addf(&buf, "Merge made by %s.", wt_strategy); + strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(result_commit, buf.buf); strbuf_release(&buf); drop_save(); @@ -1033,10 +1031,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix) git_config(git_merge_config, NULL); - /* for color.ui */ - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - if (branch_mergeoptions) parse_branch_merge_options(branch_mergeoptions); argc = parse_options(argc, argv, prefix, builtin_merge_options, diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 27f24d3aaf..a9c67c18ba 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -770,7 +770,7 @@ static int no_try_delta(const char *path) struct git_attr_check check[1]; setup_delta_attr_check(check); - if (git_checkattr(path, ARRAY_SIZE(check), check)) + if (git_check_attr(path, ARRAY_SIZE(check), check)) return 0; if (ATTR_FALSE(check->value)) return 1; diff --git a/builtin/patch-id.c b/builtin/patch-id.c index f821eb3f0b..3cfe02d5a5 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -56,13 +56,13 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after) return 1; } -static int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx) +static int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx, struct strbuf *line_buf) { - static char line[1000]; int patchlen = 0, found_next = 0; int before = -1, after = -1; - while (fgets(line, sizeof(line), stdin) != NULL) { + while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) { + char *line = line_buf->buf; char *p = line; int len; @@ -133,14 +133,16 @@ static void generate_id_list(void) unsigned char sha1[20], n[20]; git_SHA_CTX ctx; int patchlen; + struct strbuf line_buf = STRBUF_INIT; git_SHA1_Init(&ctx); hashclr(sha1); while (!feof(stdin)) { - patchlen = get_one_patchid(n, &ctx); + patchlen = get_one_patchid(n, &ctx, &line_buf); flush_current_id(patchlen, sha1, &ctx); hashcpy(sha1, n); } + strbuf_release(&line_buf); } static const char patch_id_usage[] = "git patch-id < patch"; diff --git a/builtin/push.c b/builtin/push.c index 9cebf9ea23..35cce532f2 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -8,6 +8,7 @@ #include "remote.h" #include "transport.h" #include "parse-options.h" +#include "submodule.h" static const char * const push_usage[] = { "git push [<options>] [<repository> [<refspec>...]]", @@ -219,6 +220,21 @@ static int do_push(const char *repo, int flags) return !!errs; } +static int option_parse_recurse_submodules(const struct option *opt, + const char *arg, int unset) +{ + int *flags = opt->value; + if (arg) { + if (!strcmp(arg, "check")) + *flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK; + else + die("bad %s argument: %s", opt->long_name, arg); + } else + die("option %s needs an argument (check)", opt->long_name); + + return 0; +} + int cmd_push(int argc, const char **argv, const char *prefix) { int flags = 0; @@ -236,6 +252,9 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN), OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN), OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE), + { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check", + "controls recursive pushing of submodules", + PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"), OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"), OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"), diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e1a687ad07..ae164da4d5 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -120,9 +120,25 @@ static int show_ref(const char *path, const unsigned char *sha1, int flag, void return 0; } +static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *cb_data) +{ + path = strip_namespace(path); + /* + * Advertise refs outside our current namespace as ".have" + * refs, so that the client can use them to minimize data + * transfer but will otherwise ignore them. This happens to + * cover ".have" that are thrown in by add_one_alternate_ref() + * to mark histories that are complete in our alternates as + * well. + */ + if (!path) + path = ".have"; + return show_ref(path, sha1, flag, cb_data); +} + static void write_head_info(void) { - for_each_ref(show_ref, NULL); + for_each_ref(show_ref_cb, NULL); if (!sent_capabilities) show_ref("capabilities^{}", null_sha1, 0, NULL); @@ -333,6 +349,8 @@ static void refuse_unconfigured_deny_delete_current(void) static const char *update(struct command *cmd) { const char *name = cmd->ref_name; + struct strbuf namespaced_name_buf = STRBUF_INIT; + const char *namespaced_name; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; struct ref_lock *lock; @@ -343,7 +361,10 @@ static const char *update(struct command *cmd) return "funny refname"; } - if (is_ref_checked_out(name)) { + strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name); + namespaced_name = strbuf_detach(&namespaced_name_buf, NULL); + + if (is_ref_checked_out(namespaced_name)) { switch (deny_current_branch) { case DENY_IGNORE: break; @@ -371,7 +392,7 @@ static const char *update(struct command *cmd) return "deletion prohibited"; } - if (!strcmp(name, head_name)) { + if (!strcmp(namespaced_name, head_name)) { switch (deny_delete_current) { case DENY_IGNORE: break; @@ -427,14 +448,14 @@ static const char *update(struct command *cmd) rp_warning("Allowing deletion of corrupt ref."); old_sha1 = NULL; } - if (delete_ref(name, old_sha1, 0)) { + if (delete_ref(namespaced_name, old_sha1, 0)) { rp_error("failed to delete %s", name); return "failed to delete"; } return NULL; /* good */ } else { - lock = lock_any_ref_for_update(name, old_sha1, 0); + lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0); if (!lock) { rp_error("failed to lock %s", name); return "failed to lock"; @@ -491,17 +512,29 @@ static void run_update_post_hook(struct command *commands) static void check_aliased_update(struct command *cmd, struct string_list *list) { + struct strbuf buf = STRBUF_INIT; + const char *dst_name; struct string_list_item *item; struct command *dst_cmd; unsigned char sha1[20]; char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41]; int flag; - const char *dst_name = resolve_ref(cmd->ref_name, sha1, 0, &flag); + strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name); + dst_name = resolve_ref(buf.buf, sha1, 0, &flag); + strbuf_release(&buf); if (!(flag & REF_ISSYMREF)) return; + dst_name = strip_namespace(dst_name); + if (!dst_name) { + rp_error("refusing update to broken symref '%s'", cmd->ref_name); + cmd->skip_update = 1; + cmd->error_string = "broken symref"; + return; + } + if ((item = string_list_lookup(list, dst_name)) == NULL) return; diff --git a/builtin/remote.c b/builtin/remote.c index 05b1f5b76d..f2a9c26dc3 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1103,7 +1103,7 @@ static int show(int argc, const char **argv) url = states.remote->url; url_nr = states.remote->url_nr; } - for (i=0; i < url_nr; i++) + for (i = 0; i < url_nr; i++) printf(" Push URL: %s\n", url[i]); if (!i) printf(" Push URL: %s\n", "(no URL)"); diff --git a/builtin/revert.c b/builtin/revert.c index 1f27c63343..3117776c2c 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -258,12 +258,7 @@ static void write_message(struct strbuf *msgbuf, const char *filename) static struct tree *empty_tree(void) { - struct tree *tree = xcalloc(1, sizeof(struct tree)); - - tree->object.parsed = 1; - tree->object.type = OBJ_TREE; - pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); - return tree; + return lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN); } static NORETURN void die_dirty_index(const char *me) diff --git a/builtin/show-branch.c b/builtin/show-branch.c index facc63a79e..4b480d7c7c 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -26,14 +26,14 @@ static const char **default_arg; static const char *get_color_code(int idx) { - if (showbranch_use_color) + if (want_color(showbranch_use_color)) return column_colors_ansi[idx % column_colors_ansi_max]; return ""; } static const char *get_color_reset_code(void) { - if (showbranch_use_color) + if (want_color(showbranch_use_color)) return GIT_COLOR_RESET; return ""; } @@ -573,7 +573,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "color.showbranch")) { - showbranch_use_color = git_config_colorbool(var, value, -1); + showbranch_use_color = git_config_colorbool(var, value); return 0; } @@ -685,9 +685,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) git_config(git_show_branch_config, NULL); - if (showbranch_use_color == -1) - showbranch_use_color = git_use_color_default; - /* If nothing is specified, try the default first */ if (ac == 1 && default_num) { ac = default_num; diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 76ba1d5881..835c62ab15 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -11,7 +11,7 @@ static const char * const git_update_ref_usage[] = { int cmd_update_ref(int argc, const char **argv, const char *prefix) { - const char *refname, *oldval, *msg=NULL; + const char *refname, *oldval, *msg = NULL; unsigned char sha1[20], oldsha1[20]; int delete = 0, no_deref = 0, flags = 0; struct option options[] = { |