summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/apply.c255
-rw-r--r--builtin/blame.c22
-rw-r--r--builtin/bundle.c10
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/checkout.c83
-rw-r--r--builtin/clean.c25
-rw-r--r--builtin/clone.c7
-rw-r--r--builtin/commit-tree.c2
-rw-r--r--builtin/commit.c2
-rw-r--r--builtin/config.c12
-rw-r--r--builtin/diff-files.c2
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff-tree.c2
-rw-r--r--builtin/diff.c2
-rw-r--r--builtin/fast-export.c52
-rw-r--r--builtin/fetch.c59
-rw-r--r--builtin/fmt-merge-msg.c24
-rw-r--r--builtin/grep.c12
-rw-r--r--builtin/index-pack.c26
-rw-r--r--builtin/init-db.c32
-rw-r--r--builtin/ls-files.c54
-rw-r--r--builtin/ls-remote.c3
-rw-r--r--builtin/ls-tree.c4
-rw-r--r--builtin/mailsplit.c4
-rw-r--r--builtin/merge-base.c44
-rw-r--r--builtin/merge-file.c4
-rw-r--r--builtin/merge-recursive.c4
-rw-r--r--builtin/merge.c24
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/notes.c14
-rw-r--r--builtin/pack-objects.c14
-rw-r--r--builtin/push.c8
-rw-r--r--builtin/receive-pack.c2
-rw-r--r--builtin/remote.c14
-rw-r--r--builtin/rerere.c56
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/rev-list.c8
-rw-r--r--builtin/revert.c165
-rw-r--r--builtin/shortlog.c3
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/show-ref.c2
-rw-r--r--builtin/unpack-objects.c2
-rw-r--r--builtin/update-index.c2
-rw-r--r--builtin/var.c9
45 files changed, 711 insertions, 370 deletions
diff --git a/builtin/apply.c b/builtin/apply.c
index f38c1f7b88..23c18c573b 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -416,48 +416,190 @@ static char *squash_slash(char *name)
return name;
}
-static char *find_name(const char *line, char *def, int p_value, int terminate)
+static char *find_name_gnu(const char *line, char *def, int p_value)
{
- int len;
- const char *start = NULL;
+ struct strbuf name = STRBUF_INIT;
+ char *cp;
- if (p_value == 0)
- start = line;
+ /*
+ * Proposed "new-style" GNU patch/diff format; see
+ * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
+ */
+ if (unquote_c_style(&name, line, NULL)) {
+ strbuf_release(&name);
+ return NULL;
+ }
- if (*line == '"') {
- struct strbuf name = STRBUF_INIT;
+ for (cp = name.buf; p_value; p_value--) {
+ cp = strchr(cp, '/');
+ if (!cp) {
+ strbuf_release(&name);
+ return NULL;
+ }
+ cp++;
+ }
- /*
- * Proposed "new-style" GNU patch/diff format; see
- * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
- */
- if (!unquote_c_style(&name, line, NULL)) {
- char *cp;
+ /* name can later be freed, so we need
+ * to memmove, not just return cp
+ */
+ strbuf_remove(&name, 0, cp - name.buf);
+ free(def);
+ if (root)
+ strbuf_insert(&name, 0, root, root_len);
+ return squash_slash(strbuf_detach(&name, NULL));
+}
- for (cp = name.buf; p_value; p_value--) {
- cp = strchr(cp, '/');
- if (!cp)
- break;
- cp++;
- }
- if (cp) {
- /* name can later be freed, so we need
- * to memmove, not just return cp
- */
- strbuf_remove(&name, 0, cp - name.buf);
- free(def);
- if (root)
- strbuf_insert(&name, 0, root, root_len);
- return squash_slash(strbuf_detach(&name, NULL));
- }
- }
- strbuf_release(&name);
+static size_t tz_len(const char *line, size_t len)
+{
+ const char *tz, *p;
+
+ if (len < strlen(" +0500") || line[len-strlen(" +0500")] != ' ')
+ return 0;
+ tz = line + len - strlen(" +0500");
+
+ if (tz[1] != '+' && tz[1] != '-')
+ return 0;
+
+ for (p = tz + 2; p != line + len; p++)
+ if (!isdigit(*p))
+ return 0;
+
+ return line + len - tz;
+}
+
+static size_t date_len(const char *line, size_t len)
+{
+ const char *date, *p;
+
+ if (len < strlen("72-02-05") || line[len-strlen("-05")] != '-')
+ return 0;
+ p = date = line + len - strlen("72-02-05");
+
+ if (!isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+ !isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+ !isdigit(*p++) || !isdigit(*p++)) /* Not a date. */
+ return 0;
+
+ if (date - line >= strlen("19") &&
+ isdigit(date[-1]) && isdigit(date[-2])) /* 4-digit year */
+ date -= strlen("19");
+
+ return line + len - date;
+}
+
+static size_t short_time_len(const char *line, size_t len)
+{
+ const char *time, *p;
+
+ if (len < strlen(" 07:01:32") || line[len-strlen(":32")] != ':')
+ return 0;
+ p = time = line + len - strlen(" 07:01:32");
+
+ /* Permit 1-digit hours? */
+ if (*p++ != ' ' ||
+ !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+ !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+ !isdigit(*p++) || !isdigit(*p++)) /* Not a time. */
+ return 0;
+
+ return line + len - time;
+}
+
+static size_t fractional_time_len(const char *line, size_t len)
+{
+ const char *p;
+ size_t n;
+
+ /* Expected format: 19:41:17.620000023 */
+ if (!len || !isdigit(line[len - 1]))
+ return 0;
+ p = line + len - 1;
+
+ /* Fractional seconds. */
+ while (p > line && isdigit(*p))
+ p--;
+ if (*p != '.')
+ return 0;
+
+ /* Hours, minutes, and whole seconds. */
+ n = short_time_len(line, p - line);
+ if (!n)
+ return 0;
+
+ return line + len - p + n;
+}
+
+static size_t trailing_spaces_len(const char *line, size_t len)
+{
+ const char *p;
+
+ /* Expected format: ' ' x (1 or more) */
+ if (!len || line[len - 1] != ' ')
+ return 0;
+
+ p = line + len;
+ while (p != line) {
+ p--;
+ if (*p != ' ')
+ return line + len - (p + 1);
}
- for (;;) {
+ /* All spaces! */
+ return len;
+}
+
+static size_t diff_timestamp_len(const char *line, size_t len)
+{
+ const char *end = line + len;
+ size_t n;
+
+ /*
+ * Posix: 2010-07-05 19:41:17
+ * GNU: 2010-07-05 19:41:17.620000023 -0500
+ */
+
+ if (!isdigit(end[-1]))
+ return 0;
+
+ n = tz_len(line, end - line);
+ end -= n;
+
+ n = short_time_len(line, end - line);
+ if (!n)
+ n = fractional_time_len(line, end - line);
+ end -= n;
+
+ n = date_len(line, end - line);
+ if (!n) /* No date. Too bad. */
+ return 0;
+ end -= n;
+
+ if (end == line) /* No space before date. */
+ return 0;
+ if (end[-1] == '\t') { /* Success! */
+ end--;
+ return line + len - end;
+ }
+ if (end[-1] != ' ') /* No space before date. */
+ return 0;
+
+ /* Whitespace damage. */
+ end -= trailing_spaces_len(line, end - line);
+ return line + len - end;
+}
+
+static char *find_name_common(const char *line, char *def, int p_value,
+ const char *end, int terminate)
+{
+ int len;
+ const char *start = NULL;
+
+ if (p_value == 0)
+ start = line;
+ while (line != end) {
char c = *line;
- if (isspace(c)) {
+ if (!end && isspace(c)) {
if (c == '\n')
break;
if (name_terminate(start, line-start, c, terminate))
@@ -497,6 +639,37 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
return squash_slash(xmemdupz(start, len));
}
+static char *find_name(const char *line, char *def, int p_value, int terminate)
+{
+ if (*line == '"') {
+ char *name = find_name_gnu(line, def, p_value);
+ if (name)
+ return name;
+ }
+
+ return find_name_common(line, def, p_value, NULL, terminate);
+}
+
+static char *find_name_traditional(const char *line, char *def, int p_value)
+{
+ size_t len = strlen(line);
+ size_t date_len;
+
+ if (*line == '"') {
+ char *name = find_name_gnu(line, def, p_value);
+ if (name)
+ return name;
+ }
+
+ len = strchrnul(line, '\n') - line;
+ date_len = diff_timestamp_len(line, len);
+ if (!date_len)
+ return find_name_common(line, def, p_value, NULL, TERM_TAB);
+ len -= date_len;
+
+ return find_name_common(line, def, p_value, line + len, 0);
+}
+
static int count_slashes(const char *cp)
{
int cnt = 0;
@@ -519,7 +692,7 @@ static int guess_p_value(const char *nameline)
if (is_dev_null(nameline))
return -1;
- name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
+ name = find_name_traditional(nameline, NULL, 0);
if (!name)
return -1;
cp = strchr(name, '/');
@@ -638,16 +811,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
if (is_dev_null(first)) {
patch->is_new = 1;
patch->is_delete = 0;
- name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB);
+ name = find_name_traditional(second, NULL, p_value);
patch->new_name = name;
} else if (is_dev_null(second)) {
patch->is_new = 0;
patch->is_delete = 1;
- name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
+ name = find_name_traditional(first, NULL, p_value);
patch->old_name = name;
} else {
- name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
- name = find_name(second, name, p_value, TERM_SPACE | TERM_TAB);
+ name = find_name_traditional(first, NULL, p_value);
+ name = find_name_traditional(second, name, p_value);
if (has_epoch_timestamp(first)) {
patch->is_new = 1;
patch->is_delete = 0;
@@ -3606,11 +3779,11 @@ static int option_parse_directory(const struct option *opt,
return 0;
}
-int cmd_apply(int argc, const char **argv, const char *unused_prefix)
+int cmd_apply(int argc, const char **argv, const char *prefix_)
{
int i;
int errs = 0;
- int is_not_gitdir;
+ int is_not_gitdir = !startup_info->have_repository;
int binary;
int force_apply = 0;
@@ -3683,7 +3856,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
OPT_END()
};
- prefix = setup_git_directory_gently(&is_not_gitdir);
+ prefix = prefix_;
prefix_length = prefix ? strlen(prefix) : 0;
git_config(git_apply_config, NULL);
if (apply_default_whitespace)
diff --git a/builtin/blame.c b/builtin/blame.c
index 28e3be2ead..101535448f 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1407,7 +1407,8 @@ static void get_commit_info(struct commit *commit,
int detailed)
{
int len;
- char *tmp, *endp, *reencoded, *message;
+ const char *subject;
+ char *reencoded, *message;
static char author_name[1024];
static char author_mail[1024];
static char committer_name[1024];
@@ -1449,22 +1450,13 @@ static void get_commit_info(struct commit *commit,
&ret->committer_time, &ret->committer_tz);
ret->summary = summary_buf;
- tmp = strstr(message, "\n\n");
- if (!tmp) {
- error_out:
+ len = find_commit_subject(message, &subject);
+ if (len && len < sizeof(summary_buf)) {
+ memcpy(summary_buf, subject, len);
+ summary_buf[len] = 0;
+ } else {
sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1));
- free(reencoded);
- return;
}
- tmp += 2;
- endp = strchr(tmp, '\n');
- if (!endp)
- endp = tmp + strlen(tmp);
- len = endp - tmp;
- if (len >= sizeof(summary_buf) || len == 0)
- goto error_out;
- memcpy(summary_buf, tmp, len);
- summary_buf[len] = 0;
free(reencoded);
}
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 2006cc5cd5..9b87fb9ac2 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -12,13 +12,12 @@
static const char builtin_bundle_usage[] =
"git bundle create <file> <git-rev-list args>\n"
" or: git bundle verify <file>\n"
- " or: git bundle list-heads <file> [refname...]\n"
- " or: git bundle unbundle <file> [refname...]";
+ " or: git bundle list-heads <file> [<refname>...]\n"
+ " or: git bundle unbundle <file> [<refname>...]";
int cmd_bundle(int argc, const char **argv, const char *prefix)
{
struct bundle_header header;
- int nongit;
const char *cmd, *bundle_file;
int bundle_fd = -1;
char buffer[PATH_MAX];
@@ -31,7 +30,6 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
argc -= 2;
argv += 2;
- prefix = setup_git_directory_gently(&nongit);
if (prefix && bundle_file[0] != '/') {
snprintf(buffer, sizeof(buffer), "%s/%s", prefix, bundle_file);
bundle_file = buffer;
@@ -54,11 +52,11 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
return !!list_bundle_refs(&header, argc, argv);
}
if (!strcmp(cmd, "create")) {
- if (nongit)
+ if (!startup_info->have_repository)
die("Need a repository to create a bundle.");
return !!create_bundle(&header, bundle_file, argc, argv);
} else if (!strcmp(cmd, "unbundle")) {
- if (nongit)
+ if (!startup_info->have_repository)
die("Need a repository to unbundle.");
return !!unbundle(&header, bundle_fd) ||
list_bundle_refs(&header, argc, argv);
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index a7a5ee10f3..65cbee0552 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -155,7 +155,7 @@ static void checkout_all(const char *prefix, int prefix_length)
}
static const char * const builtin_checkout_index_usage[] = {
- "git checkout-index [options] [--] <file>...",
+ "git checkout-index [options] [--] [<file>...]",
NULL
};
diff --git a/builtin/checkout.c b/builtin/checkout.c
index eef2b48d98..a54583b3a4 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -18,6 +18,7 @@
#include "xdiff-interface.h"
#include "ll-merge.h"
#include "resolve-undo.h"
+#include "submodule.h"
static const char * const checkout_usage[] = {
"git checkout [options] <branch>",
@@ -32,10 +33,15 @@ struct checkout_opts {
int writeout_stage;
int writeout_error;
+ /* not set by parse_options */
+ int branch_exists;
+
const char *new_branch;
+ const char *new_branch_force;
const char *new_orphan_branch;
int new_branch_log;
enum branch_track track;
+ struct diff_options diff_options;
};
static int post_checkout_hook(struct commit *old, struct commit *new,
@@ -150,6 +156,10 @@ static int checkout_merged(int pos, struct checkout *state)
read_mmblob(&ours, active_cache[pos+1]->sha1);
read_mmblob(&theirs, active_cache[pos+2]->sha1);
+ /*
+ * NEEDSWORK: re-create conflicts from merges with
+ * merge.renormalize set, too
+ */
status = ll_merge(&result_buf, path, &ancestor, "base",
&ours, "ours", &theirs, "theirs", 0);
free(ancestor.ptr);
@@ -274,11 +284,12 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
return errs;
}
-static void show_local_changes(struct object *head)
+static void show_local_changes(struct object *head, struct diff_options *opts)
{
struct rev_info rev;
/* I think we want full paths, even if we're in a subdirectory. */
init_revisions(&rev, NULL);
+ rev.diffopt.flags = opts->flags;
rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
if (diff_setup_done(&rev.diffopt) < 0)
die("diff_setup_done failed");
@@ -372,7 +383,7 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.src_index = &the_index;
topts.dst_index = &the_index;
- topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
+ setup_unpack_trees_porcelain(&topts, "checkout");
refresh_cache(REFRESH_QUIET);
@@ -432,6 +443,13 @@ static int merge_working_tree(struct checkout_opts *opts,
*/
add_files_to_cache(NULL, NULL, 0);
+ /*
+ * NEEDSWORK: carrying over local changes
+ * when branches have different end-of-line
+ * normalization (or clean+smudge rules) is
+ * a pain; plumb in an option to set
+ * o.renormalize?
+ */
init_merge_options(&o);
o.verbosity = 0;
work = write_tree_from_memory(&o);
@@ -455,7 +473,7 @@ static int merge_working_tree(struct checkout_opts *opts,
die("unable to write new index file");
if (!opts->force && !opts->quiet)
- show_local_changes(&new->commit->object);
+ show_local_changes(&new->commit->object, &opts->diff_options);
return 0;
}
@@ -510,7 +528,8 @@ static void update_refs_for_switch(struct checkout_opts *opts,
}
}
else
- create_branch(old->name, opts->new_branch, new->name, 0,
+ create_branch(old->name, opts->new_branch, new->name,
+ opts->new_branch_force ? 1 : 0,
opts->new_branch_log, opts->track);
new->name = opts->new_branch;
setup_branch_path(new);
@@ -528,9 +547,12 @@ static void update_refs_for_switch(struct checkout_opts *opts,
if (old->path && !strcmp(new->path, old->path))
fprintf(stderr, "Already on '%s'\n",
new->name);
- else
+ else if (opts->new_branch)
fprintf(stderr, "Switched to%s branch '%s'\n",
- opts->new_branch ? " a new" : "",
+ opts->branch_exists ? " and reset" : " a new",
+ new->name);
+ else
+ fprintf(stderr, "Switched to branch '%s'\n",
new->name);
}
if (old->path && old->name) {
@@ -599,7 +621,16 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
static int git_checkout_config(const char *var, const char *value, void *cb)
{
- return git_xmerge_config(var, value, cb);
+ if (!strcmp(var, "diff.ignoresubmodules")) {
+ struct checkout_opts *opts = cb;
+ handle_ignore_submodules_arg(&opts->diff_options, value);
+ return 0;
+ }
+
+ if (!prefixcmp(var, "submodule."))
+ return parse_submodule_config_option(var, value);
+
+ return git_xmerge_config(var, value, NULL);
}
static int interactive_checkout(const char *revision, const char **pathspec,
@@ -656,17 +687,20 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
int dwim_new_local_branch = 1;
struct option options[] = {
OPT__QUIET(&opts.quiet),
- OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
- OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
- OPT_SET_INT('t', "track", &opts.track, "track",
+ OPT_STRING('b', NULL, &opts.new_branch, "branch",
+ "create and checkout a new branch"),
+ OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
+ "create/reset and checkout a branch"),
+ OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
+ OPT_SET_INT('t', "track", &opts.track, "set upstream info for new branch",
BRANCH_TRACK_EXPLICIT),
OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
- OPT_SET_INT('2', "ours", &opts.writeout_stage, "stage",
+ OPT_SET_INT('2', "ours", &opts.writeout_stage, "checkout our version for unmerged files",
2),
- OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
+ OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
3),
- OPT_BOOLEAN('f', "force", &opts.force, "force"),
- OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
+ OPT_BOOLEAN('f', "force", &opts.force, "force checkout (throw away local modifications)"),
+ OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"),
OPT_STRING(0, "conflict", &conflict_style, "style",
"conflict style (merge or diff3)"),
OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
@@ -680,13 +714,22 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
memset(&new, 0, sizeof(new));
- git_config(git_checkout_config, NULL);
+ gitmodules_config();
+ git_config(git_checkout_config, &opts);
opts.track = BRANCH_TRACK_UNSPECIFIED;
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
+ /* we can assume from now on new_branch = !new_branch_force */
+ if (opts.new_branch && opts.new_branch_force)
+ die("-B cannot be used with -b");
+
+ /* copy -B over to -b, so that we can just check the latter */
+ if (opts.new_branch_force)
+ opts.new_branch = opts.new_branch_force;
+
if (patch_mode && (opts.track > 0 || opts.new_branch
|| opts.new_branch_log || opts.merge || opts.force))
die ("--patch is incompatible with all other options");
@@ -708,7 +751,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (opts.new_orphan_branch) {
if (opts.new_branch)
- die("--orphan and -b are mutually exclusive");
+ die("--orphan and -b|-B are mutually exclusive");
if (opts.track > 0)
die("--orphan cannot be used with -t");
opts.new_branch = opts.new_orphan_branch;
@@ -857,8 +900,12 @@ no_reference:
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 (!get_sha1(buf.buf, rev))
- die("git checkout: branch %s already exists", opts.new_branch);
+ if (!get_sha1(buf.buf, rev)) {
+ opts.branch_exists = 1;
+ if (!opts.new_branch_force)
+ die("git checkout: branch %s already exists",
+ opts.new_branch);
+ }
strbuf_release(&buf);
}
diff --git a/builtin/clean.c b/builtin/clean.c
index fac64e6cd3..fb24030751 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -10,12 +10,13 @@
#include "cache.h"
#include "dir.h"
#include "parse-options.h"
+#include "string-list.h"
#include "quote.h"
static int force = -1; /* unset */
static const char *const builtin_clean_usage[] = {
- "git clean [-d] [-f] [-n] [-q] [-x | -X] [--] <paths>...",
+ "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>...",
NULL
};
@@ -26,16 +27,24 @@ static int git_clean_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
+static int exclude_cb(const struct option *opt, const char *arg, int unset)
+{
+ struct string_list *exclude_list = opt->value;
+ string_list_append(exclude_list, arg);
+ return 0;
+}
+
int cmd_clean(int argc, const char **argv, const char *prefix)
{
int i;
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
- int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
+ int ignored_only = 0, config_set = 0, errors = 0;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
static const char **pathspec;
struct strbuf buf = STRBUF_INIT;
+ struct string_list exclude_list = STRING_LIST_INIT_NODUP;
const char *qname;
char *seen = NULL;
struct option options[] = {
@@ -44,6 +53,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN('f', "force", &force, "force"),
OPT_BOOLEAN('d', NULL, &remove_directories,
"remove whole directories"),
+ { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern",
+ "exclude <pattern>", PARSE_OPT_NONEG, exclude_cb },
OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
OPT_BOOLEAN('X', NULL, &ignored_only,
"remove only ignored files"),
@@ -81,6 +92,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (!ignored)
setup_standard_excludes(&dir);
+ for (i = 0; i < exclude_list.nr; i++)
+ add_exclude(exclude_list.items[i].string, "", 0, dir.exclude_list);
+
pathspec = get_pathspec(prefix, argv);
fill_directory(&dir, pathspec);
@@ -124,7 +138,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (pathspec) {
memset(seen, 0, argc > 0 ? argc : 1);
matches = match_pathspec(pathspec, ent->name, len,
- baselen, seen);
+ 0, seen);
}
if (S_ISDIR(st.st_mode)) {
@@ -139,7 +153,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
printf("Removing %s\n", qname);
if (remove_dir_recursively(&directory,
rm_flags) != 0) {
- warning("failed to remove '%s'", qname);
+ warning("failed to remove %s", qname);
errors++;
}
} else if (show_only) {
@@ -159,7 +173,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
printf("Removing %s\n", qname);
}
if (unlink(ent->name) != 0) {
- warning("failed to remove '%s'", qname);
+ warning("failed to remove %s", qname);
errors++;
}
}
@@ -167,5 +181,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
free(seen);
strbuf_release(&directory);
+ string_list_clear(&exclude_list, 0);
return (errors != 0);
}
diff --git a/builtin/clone.c b/builtin/clone.c
index efb1e6faa5..19ed64041d 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -361,7 +361,7 @@ static void write_remote_refs(const struct ref *local_refs)
int cmd_clone(int argc, const char **argv, const char *prefix)
{
- int is_bundle = 0;
+ int is_bundle = 0, is_local;
struct stat buf;
const char *repo_name, *repo, *work_tree, *git_dir;
char *path, *dir;
@@ -414,6 +414,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
repo = xstrdup(make_absolute_path(repo_name));
else
repo = repo_name;
+ is_local = path && !is_bundle;
+ if (is_local && option_depth)
+ warning("--depth is ignored in local clones; use file:// instead.");
if (argc == 2)
dir = xstrdup(argv[1]);
@@ -514,7 +517,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_reset(&value);
- if (path && !is_bundle) {
+ if (is_local) {
refs = clone_local(path, git_dir);
mapped_refs = wanted_peer_refs(refs, refspec);
} else {
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 87f0591c2f..e06573920f 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -9,7 +9,7 @@
#include "builtin.h"
#include "utf8.h"
-static const char commit_tree_usage[] = "git commit-tree <sha1> [-p <sha1>]* < changelog";
+static const char commit_tree_usage[] = "git commit-tree <sha1> [(-p <sha1>)...] < changelog";
static void new_parent(struct commit *parent, struct commit_list **parents_p)
{
diff --git a/builtin/commit.c b/builtin/commit.c
index c4a577d5c5..66fdd22024 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -25,6 +25,7 @@
#include "rerere.h"
#include "unpack-trees.h"
#include "quote.h"
+#include "submodule.h"
static const char * const builtin_commit_usage[] = {
"git commit [options] [--] <filepattern>...",
@@ -1073,6 +1074,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
status_format = STATUS_FORMAT_PORCELAIN;
wt_status_prepare(&s);
+ gitmodules_config();
git_config(git_status_config, &s);
in_merge = file_exists(git_path("MERGE_HEAD"));
argc = parse_options(argc, argv, prefix,
diff --git a/builtin/config.c b/builtin/config.c
index f3d1660d02..ca4a0db4a7 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -20,7 +20,7 @@ static char delim = '=';
static char key_delim = ' ';
static char term = '\n';
-static int use_global_config, use_system_config;
+static int use_global_config, use_system_config, use_local_config;
static const char *given_config_file;
static int actions, types;
static const char *get_color_slot, *get_colorbool_slot;
@@ -51,6 +51,7 @@ static struct option builtin_config_options[] = {
OPT_GROUP("Config file location"),
OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
+ OPT_BOOLEAN(0, "local", &use_local_config, "use repository config file"),
OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"),
OPT_GROUP("Action"),
OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
@@ -330,11 +331,10 @@ static int get_colorbool(int print)
return get_colorbool_found ? 0 : 1;
}
-int cmd_config(int argc, const char **argv, const char *unused_prefix)
+int cmd_config(int argc, const char **argv, const char *prefix)
{
- int nongit;
+ int nongit = !startup_info->have_repository;
char *value;
- const char *prefix = setup_git_directory_gently(&nongit);
config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
@@ -342,7 +342,7 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix)
builtin_config_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- if (use_global_config + use_system_config + !!given_config_file > 1) {
+ if (use_global_config + use_system_config + use_local_config + !!given_config_file > 1) {
error("only one config file at a time.");
usage_with_options(builtin_config_usage, builtin_config_options);
}
@@ -358,6 +358,8 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix)
}
else if (use_system_config)
config_exclusive_filename = git_etc_gitconfig();
+ else if (use_local_config)
+ config_exclusive_filename = git_pathdup("config");
else if (given_config_file) {
if (!is_absolute_path(given_config_file) && prefix)
config_exclusive_filename = prefix_filename(prefix,
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 5b64011de8..951c7c8994 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -8,6 +8,7 @@
#include "commit.h"
#include "revision.h"
#include "builtin.h"
+#include "submodule.h"
static const char diff_files_usage[] =
"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
@@ -20,6 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
unsigned options = 0;
init_revisions(&rev, prefix);
+ gitmodules_config();
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
rev.abbrev = 0;
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 04837494fe..2eb32bd9da 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -3,6 +3,7 @@
#include "commit.h"
#include "revision.h"
#include "builtin.h"
+#include "submodule.h"
static const char diff_cache_usage[] =
"git diff-index [-m] [--cached] "
@@ -17,6 +18,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
int result;
init_revisions(&rev, prefix);
+ gitmodules_config();
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
rev.abbrev = 0;
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 3c78bda566..0d2a3e9fa2 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -3,6 +3,7 @@
#include "commit.h"
#include "log-tree.h"
#include "builtin.h"
+#include "submodule.h"
static struct rev_info log_tree_opt;
@@ -112,6 +113,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int read_stdin = 0;
init_revisions(opt, prefix);
+ gitmodules_config();
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
opt->abbrev = 0;
opt->diff = 1;
diff --git a/builtin/diff.c b/builtin/diff.c
index 89ae89cde1..a43d326363 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -13,6 +13,7 @@
#include "revision.h"
#include "log-tree.h"
#include "builtin.h"
+#include "submodule.h"
struct blobinfo {
unsigned char sha1[20];
@@ -279,6 +280,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
*/
prefix = setup_git_directory_gently(&nongit);
+ gitmodules_config();
git_config(git_diff_ui_config, NULL);
if (diff_use_color_default == -1)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 9fe25ff0b3..c8fd46b872 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -27,6 +27,7 @@ static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
static int fake_missing_tagger;
static int no_data;
+static int full_tree;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
@@ -147,10 +148,47 @@ static void handle_object(const unsigned char *sha1)
free(buf);
}
+static int depth_first(const void *a_, const void *b_)
+{
+ const struct diff_filepair *a = *((const struct diff_filepair **)a_);
+ const struct diff_filepair *b = *((const struct diff_filepair **)b_);
+ const char *name_a, *name_b;
+ int len_a, len_b, len;
+ int cmp;
+
+ name_a = a->one ? a->one->path : a->two->path;
+ name_b = b->one ? b->one->path : b->two->path;
+
+ len_a = strlen(name_a);
+ len_b = strlen(name_b);
+ len = (len_a < len_b) ? len_a : len_b;
+
+ /* strcmp will sort 'd' before 'd/e', we want 'd/e' before 'd' */
+ cmp = memcmp(name_a, name_b, len);
+ if (cmp)
+ return cmp;
+ cmp = len_b - len_a;
+ if (cmp)
+ return cmp;
+ /*
+ * Move 'R'ename entries last so that all references of the file
+ * appear in the output before it is renamed (e.g., when a file
+ * was copied and renamed in the same commit).
+ */
+ return (a->status == 'R') - (b->status == 'R');
+}
+
static void show_filemodify(struct diff_queue_struct *q,
struct diff_options *options, void *data)
{
int i;
+
+ /*
+ * Handle files below a directory first, in case they are all deleted
+ * and the directory changes to a file or symlink.
+ */
+ qsort(q->queue, q->nr, sizeof(q->queue[0]), depth_first);
+
for (i = 0; i < q->nr; i++) {
struct diff_filespec *ospec = q->queue[i]->one;
struct diff_filespec *spec = q->queue[i]->two;
@@ -241,7 +279,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
message += 2;
if (commit->parents &&
- get_object_mark(&commit->parents->item->object) != 0) {
+ get_object_mark(&commit->parents->item->object) != 0 &&
+ !full_tree) {
parse_commit(commit->parents->item);
diff_tree_sha1(commit->parents->item->tree->object.sha1,
commit->tree->object.sha1, "", &rev->diffopt);
@@ -281,6 +320,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
i++;
}
+ if (full_tree)
+ printf("deleteall\n");
log_tree_diff_flush(rev);
rev->diffopt.output_format = saved_output_format;
@@ -565,8 +606,8 @@ static void import_marks(char *input_file)
int cmd_fast_export(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
- struct object_array commits = { 0, 0, NULL };
- struct string_list extra_refs = { NULL, 0, 0, 0 };
+ struct object_array commits = OBJECT_ARRAY_INIT;
+ struct string_list extra_refs = STRING_LIST_INIT_NODUP;
struct commit *commit;
char *export_filename = NULL, *import_filename = NULL;
struct option options[] = {
@@ -584,6 +625,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Import marks from this file"),
OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger,
"Fake a tagger when tags lack one"),
+ OPT_BOOLEAN(0, "full-tree", &full_tree,
+ "Output full tree for each commit"),
{ OPTION_NEGBIT, 0, "data", &no_data, NULL,
"Skip output of blob data",
PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
@@ -608,6 +651,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (import_filename)
import_marks(import_filename);
+ if (import_filename && revs.prune_data)
+ full_tree = 1;
+
get_tags_and_duplicates(&revs.pending, &extra_refs);
if (prepare_revision_walk(&revs))
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7a53144153..d35f000c03 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -16,7 +16,7 @@
static const char * const builtin_fetch_usage[] = {
"git fetch [<options>] [<repository> [<refspec>...]]",
"git fetch [<options>] <group>",
- "git fetch --multiple [<options>] [<repository> | <group>]...",
+ "git fetch --multiple [<options>] [(<repository> | <group>)...]",
"git fetch --all [<options>]",
NULL
};
@@ -146,7 +146,10 @@ static struct ref *get_ref_map(struct transport *transport,
struct remote *remote = transport->remote;
struct branch *branch = branch_get(NULL);
int has_merge = branch_has_merge_config(branch);
- if (remote && (remote->fetch_refspec_nr || has_merge)) {
+ if (remote &&
+ (remote->fetch_refspec_nr ||
+ /* Note: has_merge implies non-NULL branch->remote_name */
+ (has_merge && !strcmp(branch->remote_name, remote->name)))) {
for (i = 0; i < remote->fetch_refspec_nr; i++) {
get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0);
if (remote->fetch[i].dst &&
@@ -160,6 +163,8 @@ static struct ref *get_ref_map(struct transport *transport,
* if the remote we're fetching from is the same
* as given in branch.<name>.remote, we add the
* ref given in branch.<name>.merge, too.
+ *
+ * Note: has_merge implies non-NULL branch->remote_name
*/
if (has_merge &&
!strcmp(branch->remote_name, remote->name))
@@ -544,40 +549,14 @@ static int will_fetch(struct ref **head, const unsigned char *sha1)
return 0;
}
-struct tag_data {
- struct ref **head;
- struct ref ***tail;
-};
-
-static int add_to_tail(struct string_list_item *item, void *cb_data)
-{
- struct tag_data *data = (struct tag_data *)cb_data;
- struct ref *rm = NULL;
-
- /* We have already decided to ignore this item */
- if (!item->util)
- return 0;
-
- rm = alloc_ref(item->string);
- rm->peer_ref = alloc_ref(item->string);
- hashcpy(rm->old_sha1, item->util);
-
- **data->tail = rm;
- *data->tail = &rm->next;
-
- return 0;
-}
-
static void find_non_local_tags(struct transport *transport,
struct ref **head,
struct ref ***tail)
{
- struct string_list existing_refs = { NULL, 0, 0, 0 };
- struct string_list remote_refs = { NULL, 0, 0, 0 };
- struct tag_data data;
+ struct string_list existing_refs = STRING_LIST_INIT_NODUP;
+ struct string_list remote_refs = STRING_LIST_INIT_NODUP;
const struct ref *ref;
struct string_list_item *item = NULL;
- data.head = head; data.tail = tail;
for_each_ref(add_existing, &existing_refs);
for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
@@ -631,10 +610,20 @@ static void find_non_local_tags(struct transport *transport,
item->util = NULL;
/*
- * For all the tags in the remote_refs string list, call
- * add_to_tail to add them to the list of refs to be fetched
+ * For all the tags in the remote_refs string list,
+ * add them to the list of refs to be fetched
*/
- for_each_string_list(&remote_refs, add_to_tail, &data);
+ for_each_string_list_item(item, &remote_refs) {
+ /* Unless we have already decided to ignore this item... */
+ if (item->util)
+ {
+ struct ref *rm = alloc_ref(item->string);
+ rm->peer_ref = alloc_ref(item->string);
+ hashcpy(rm->old_sha1, item->util);
+ **tail = rm;
+ *tail = &rm->next;
+ }
+ }
string_list_clear(&remote_refs, 0);
}
@@ -667,7 +656,7 @@ static int truncate_fetch_head(void)
static int do_fetch(struct transport *transport,
struct refspec *refs, int ref_count)
{
- struct string_list existing_refs = { NULL, 0, 0, 0 };
+ struct string_list existing_refs = STRING_LIST_INIT_NODUP;
struct string_list_item *peer_item = NULL;
struct ref *ref_map;
struct ref *rm;
@@ -893,7 +882,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
int i;
- struct string_list list = { NULL, 0, 0, 0 };
+ struct string_list list = STRING_LIST_INIT_NODUP;
struct remote *remote;
int result = 0;
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index bc3c5e6d3e..e7e12eea25 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -7,7 +7,7 @@
#include "string-list.h"
static const char * const fmt_merge_msg_usage[] = {
- "git fmt-merge-msg [--log|--no-log] [--file <file>]",
+ "git fmt-merge-msg [-m <message>] [--log|--no-log] [--file <file>]",
NULL
};
@@ -38,8 +38,8 @@ void init_src_data(struct src_data *data)
data->generic.strdup_strings = 1;
}
-static struct string_list srcs = { NULL, 0, 0, 1 };
-static struct string_list origins = { NULL, 0, 0, 1 };
+static struct string_list srcs = STRING_LIST_INIT_DUP;
+static struct string_list origins = STRING_LIST_INIT_DUP;
static int handle_line(char *line)
{
@@ -146,7 +146,7 @@ static void shortlog(const char *name, unsigned char *sha1,
int i, count = 0;
struct commit *commit;
struct object *branch;
- struct string_list subjects = { NULL, 0, 0, 1 };
+ struct string_list subjects = STRING_LIST_INIT_DUP;
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
struct strbuf sb = STRBUF_INIT;
@@ -319,11 +319,14 @@ int fmt_merge_msg_shortlog(struct strbuf *in, struct strbuf *out) {
int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
{
const char *inpath = NULL;
+ const char *message = NULL;
struct option options[] = {
OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"),
{ OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL,
"alias for --log (deprecated)",
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ OPT_STRING('m', "message", &message, "text",
+ "use <text> as start of message"),
OPT_FILENAME('F', "file", &inpath, "file to read from"),
OPT_END()
};
@@ -337,6 +340,12 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
0);
if (argc > 0)
usage_with_options(fmt_merge_msg_usage, options);
+ if (message && !merge_summary) {
+ char nl = '\n';
+ write_in_full(STDOUT_FILENO, message, strlen(message));
+ write_in_full(STDOUT_FILENO, &nl, 1);
+ return 0;
+ }
if (inpath && strcmp(inpath, "-")) {
in = fopen(inpath, "r");
@@ -346,7 +355,12 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
if (strbuf_read(&input, fileno(in), 0) < 0)
die_errno("could not read input file");
- ret = fmt_merge_msg(merge_summary, &input, &output);
+ if (message) {
+ strbuf_addstr(&output, message);
+ ret = fmt_merge_msg_shortlog(&input, &output);
+ } else {
+ ret = fmt_merge_msg(merge_summary, &input, &output);
+ }
if (ret)
return ret;
write_in_full(STDOUT_FILENO, output.buf, output.len);
diff --git a/builtin/grep.c b/builtin/grep.c
index 597f76bc42..3d5f6ace97 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -24,7 +24,7 @@
#endif
static char const * const grep_usage[] = {
- "git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
+ "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
NULL
};
@@ -834,12 +834,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
int external_grep_allowed__ignored;
const char *show_in_pager = NULL, *default_pager = "dummy";
struct grep_opt opt;
- struct object_array list = { 0, 0, NULL };
+ struct object_array list = OBJECT_ARRAY_INIT;
const char **paths = NULL;
- struct string_list path_list = { NULL, 0, 0, 0 };
+ struct string_list path_list = STRING_LIST_INIT_NODUP;
int i;
int dummy;
- int nongit = 0, use_index = 1;
+ int use_index = 1;
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
"search in index instead of in the work tree"),
@@ -930,8 +930,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_END()
};
- prefix = setup_git_directory_gently(&nongit);
-
/*
* 'git grep -h', unlike 'git grep -h <pattern>', is a request
* to show usage information and exit.
@@ -976,7 +974,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
- if (use_index && nongit)
+ if (use_index && !startup_info->have_repository)
/* die the same way as if we did it at the beginning */
setup_git_directory();
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index fad76bf7a8..8dc5c0b541 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -11,7 +11,7 @@
#include "exec_cmd.h"
static const char index_pack_usage[] =
-"git index-pack [-v] [-o <index-file>] [{ --keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
+"git index-pack [-v] [-o <index-file>] [ --keep | --keep=<msg> ] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
struct object_entry
{
@@ -161,7 +161,7 @@ static void use(int bytes)
input_offset += bytes;
/* make sure off_t is sufficiently large not to wrap */
- if (consumed_bytes > consumed_bytes + bytes)
+ if (signed_add_overflows(consumed_bytes, bytes))
die("pack too large for current definition of off_t");
consumed_bytes += bytes;
}
@@ -886,25 +886,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
read_replace_refs = 0;
- /*
- * We wish to read the repository's config file if any, and
- * for that it is necessary to call setup_git_directory_gently().
- * However if the cwd was inside .git/objects/pack/ then we need
- * to go back there or all the pack name arguments will be wrong.
- * And in that case we cannot rely on any prefix returned by
- * setup_git_directory_gently() either.
- */
- {
- char cwd[PATH_MAX+1];
- int nongit;
-
- if (!getcwd(cwd, sizeof(cwd)-1))
- die("Unable to get current working directory");
- setup_git_directory_gently(&nongit);
- git_config(git_index_pack_config, NULL);
- if (chdir(cwd))
- die("Cannot come back to cwd");
- }
+ git_config(git_index_pack_config, NULL);
+ if (prefix && chdir(prefix))
+ die("Cannot come back to cwd");
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0271285fad..9d4886c716 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -294,11 +294,26 @@ static int create_default_files(const char *template_path)
return reinit;
}
+static void create_object_directory(void)
+{
+ const char *object_directory = get_object_directory();
+ int len = strlen(object_directory);
+ char *path = xmalloc(len + 40);
+
+ memcpy(path, object_directory, len);
+
+ safe_create_dir(object_directory, 1);
+ strcpy(path+len, "/pack");
+ safe_create_dir(path, 1);
+ strcpy(path+len, "/info");
+ safe_create_dir(path, 1);
+
+ free(path);
+}
+
int init_db(const char *template_dir, unsigned int flags)
{
- const char *sha1_dir;
- char *path;
- int len, reinit;
+ int reinit;
safe_create_dir(get_git_dir(), 0);
@@ -313,16 +328,7 @@ int init_db(const char *template_dir, unsigned int flags)
reinit = create_default_files(template_dir);
- sha1_dir = get_object_directory();
- len = strlen(sha1_dir);
- path = xmalloc(len + 40);
- memcpy(path, sha1_dir, len);
-
- safe_create_dir(sha1_dir, 1);
- strcpy(path+len, "/pack");
- safe_create_dir(path, 1);
- strcpy(path+len, "/info");
- safe_create_dir(path, 1);
+ create_object_directory();
if (shared_repository) {
char buf[10];
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 1b9b8a8b4a..6a307ab784 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -25,6 +25,7 @@ static int show_modified;
static int show_killed;
static int show_valid_bit;
static int line_terminator = '\n';
+static int debug_mode;
static const char *prefix;
static int max_prefix_len;
@@ -162,35 +163,41 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
ce_stage(ce));
}
write_name(ce->name, ce_namelen(ce));
-}
-
-static int show_one_ru(struct string_list_item *item, void *cbdata)
-{
- const char *path = item->string;
- struct resolve_undo_info *ui = item->util;
- int i, len;
-
- len = strlen(path);
- if (len < max_prefix_len)
- return 0; /* outside of the prefix */
- if (!match_pathspec(pathspec, path, len, max_prefix_len, ps_matched))
- return 0; /* uninterested */
- for (i = 0; i < 3; i++) {
- if (!ui->mode[i])
- continue;
- printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
- find_unique_abbrev(ui->sha1[i], abbrev),
- i + 1);
- write_name(path, len);
+ if (debug_mode) {
+ printf(" ctime: %d:%d\n", ce->ce_ctime.sec, ce->ce_ctime.nsec);
+ printf(" mtime: %d:%d\n", ce->ce_mtime.sec, ce->ce_mtime.nsec);
+ printf(" dev: %d\tino: %d\n", ce->ce_dev, ce->ce_ino);
+ printf(" uid: %d\tgid: %d\n", ce->ce_uid, ce->ce_gid);
+ printf(" size: %d\tflags: %x\n", ce->ce_size, ce->ce_flags);
}
- return 0;
}
static void show_ru_info(void)
{
+ struct string_list_item *item;
+
if (!the_index.resolve_undo)
return;
- for_each_string_list(the_index.resolve_undo, show_one_ru, NULL);
+
+ for_each_string_list_item(item, the_index.resolve_undo) {
+ const char *path = item->string;
+ struct resolve_undo_info *ui = item->util;
+ int i, len;
+
+ len = strlen(path);
+ if (len < max_prefix_len)
+ continue; /* outside of the prefix */
+ if (!match_pathspec(pathspec, path, len, max_prefix_len, ps_matched))
+ continue; /* uninterested */
+ for (i = 0; i < 3; i++) {
+ if (!ui->mode[i])
+ continue;
+ printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
+ find_unique_abbrev(ui->sha1[i], abbrev),
+ i + 1);
+ write_name(path, len);
+ }
+ }
}
static void show_files(struct dir_struct *dir)
@@ -417,7 +424,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
}
static const char * const ls_files_usage[] = {
- "git ls-files [options] [<file>]*",
+ "git ls-files [options] [<file>...]",
NULL
};
@@ -519,6 +526,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
"pretend that paths removed since <tree-ish> are still present"),
OPT__ABBREV(&abbrev),
+ OPT_BOOLEAN(0, "debug", &debug_mode, "show debugging data"),
OPT_END()
};
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 34480cfad6..97eed4012b 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -32,7 +32,6 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
{
int i;
const char *dest = NULL;
- int nongit;
unsigned flags = 0;
int quiet = 0;
const char *uploadpack = NULL;
@@ -42,8 +41,6 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
struct transport *transport;
const struct ref *ref;
- setup_git_directory_gently(&nongit);
-
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index dc86b0d9a9..f73e6bd962 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -24,7 +24,7 @@ static int chomp_prefix;
static const char *ls_tree_prefix;
static const char * const ls_tree_usage[] = {
- "git ls-tree [<options>] <tree-ish> [path...]",
+ "git ls-tree [<options>] <tree-ish> [<path>...]",
NULL
};
@@ -52,6 +52,8 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
speclen = strlen(spec);
if (speclen <= len)
continue;
+ if (spec[len] && spec[len] != '/')
+ continue;
if (memcmp(pathname, spec, len))
continue;
return 1;
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index e4560da191..2d4327801e 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -10,7 +10,7 @@
#include "strbuf.h"
static const char git_mailsplit_usage[] =
-"git mailsplit [-d<prec>] [-f<n>] [-b] [--keep-cr] -o<directory> [<mbox>|<Maildir>...]";
+"git mailsplit [-d<prec>] [-f<n>] [-b] [--keep-cr] -o<directory> [(<mbox>|<Maildir>)...]";
static int is_from_line(const char *line, int len)
{
@@ -137,7 +137,7 @@ static int split_maildir(const char *maildir, const char *dir,
char name[PATH_MAX];
int ret = -1;
int i;
- struct string_list list = {NULL, 0, 0, 1};
+ struct string_list list = STRING_LIST_INIT_DUP;
if (populate_maildir_list(&list, maildir) < 0)
goto out;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 54e7ec2237..96dd160731 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -23,7 +23,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
}
static const char * const merge_base_usage[] = {
- "git merge-base [-a|--all] <commit> <commit>...",
+ "git merge-base [-a|--all] [--octopus] <commit> <commit>...",
+ "git merge-base --independent <commit>...",
NULL
};
@@ -41,21 +42,58 @@ static struct commit *get_commit_reference(const char *arg)
return r;
}
+static int handle_octopus(int count, const char **args, int reduce, int show_all)
+{
+ struct commit_list *revs = NULL;
+ struct commit_list *result;
+ int i;
+
+ if (reduce)
+ show_all = 1;
+
+ for (i = count - 1; i >= 0; i--)
+ commit_list_insert(get_commit_reference(args[i]), &revs);
+
+ result = reduce ? reduce_heads(revs) : get_octopus_merge_bases(revs);
+
+ if (!result)
+ return 1;
+
+ while (result) {
+ printf("%s\n", sha1_to_hex(result->item->object.sha1));
+ if (!show_all)
+ return 0;
+ result = result->next;
+ }
+
+ return 0;
+}
+
int cmd_merge_base(int argc, const char **argv, const char *prefix)
{
struct commit **rev;
int rev_nr = 0;
int show_all = 0;
+ int octopus = 0;
+ int reduce = 0;
struct option options[] = {
- OPT_BOOLEAN('a', "all", &show_all, "outputs all common ancestors"),
+ OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"),
+ OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"),
+ OPT_BOOLEAN(0, "independent", &reduce, "list revs not reachable from others"),
OPT_END()
};
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
- if (argc < 2)
+ if (!octopus && !reduce && argc < 2)
usage_with_options(merge_base_usage, options);
+ if (reduce && (show_all || octopus))
+ die("--independent cannot be used with other options");
+
+ if (octopus || reduce)
+ return handle_octopus(argc, argv, reduce, show_all);
+
rev = xmalloc(argc * sizeof(*rev));
while (argc-- > 0)
rev[rev_nr++] = get_commit_reference(*argv++);
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index b8e9e5ba01..b6664d49be 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -28,7 +28,6 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
xmparam_t xmp = {{0}};
int ret = 0, i = 0, to_stdout = 0;
int quiet = 0;
- int nongit;
struct option options[] = {
OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
@@ -50,8 +49,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
xmp.style = 0;
xmp.favor = 0;
- prefix = setup_git_directory_gently(&nongit);
- if (!nongit) {
+ if (startup_info->have_repository) {
/* Read the configuration file */
git_config(git_xmerge_config, NULL);
if (0 <= git_xmerge_style)
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 3d00adbfc7..78b9db76a0 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -48,6 +48,10 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
o.subtree_shift = "";
else if (!prefixcmp(arg+2, "subtree="))
o.subtree_shift = arg + 10;
+ else if (!strcmp(arg+2, "renormalize"))
+ o.renormalize = 1;
+ else if (!strcmp(arg+2, "no-renormalize"))
+ o.renormalize = 0;
else
die("Unknown option %s", arg);
continue;
diff --git a/builtin/merge.c b/builtin/merge.c
index 37ce4f589f..5f65c0c8a6 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -54,6 +54,7 @@ static size_t use_strategies_nr, use_strategies_alloc;
static const char **xopts;
static size_t xopts_nr, xopts_alloc;
static const char *branch;
+static int option_renormalize;
static int verbosity;
static int allow_rerere_auto;
@@ -131,6 +132,7 @@ static struct strategy *get_strategy(const char *name)
ret = xcalloc(1, sizeof(struct strategy));
ret->name = xstrdup(name);
+ ret->attr = NO_TRIVIAL;
return ret;
}
@@ -437,7 +439,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_addstr(&truname, "refs/heads/");
strbuf_addstr(&truname, remote);
strbuf_setlen(&truname, truname.len - len);
- if (resolve_ref(truname.buf, buf_sha, 0, NULL)) {
+ if (resolve_ref(truname.buf, buf_sha, 1, NULL)) {
strbuf_addf(msg,
"%s\t\tbranch '%s'%s of .\n",
sha1_to_hex(remote_head->sha1),
@@ -486,7 +488,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
buf = xstrdup(v);
argc = split_cmdline(buf, &argv);
if (argc < 0)
- die("Bad branch.%s.mergeoptions string", branch);
+ die("Bad branch.%s.mergeoptions string: %s", branch,
+ split_cmdline_strerror(argc));
argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
argc++;
@@ -503,6 +506,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
return git_config_string(&pull_octopus, k, v);
else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary"))
option_log = git_config_bool(k, v);
+ else if (!strcmp(k, "merge.renormalize"))
+ option_renormalize = git_config_bool(k, v);
return git_diff_ui_config(k, v, cb);
}
@@ -624,6 +629,11 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
if (!strcmp(strategy, "subtree"))
o.subtree_shift = "";
+ o.renormalize = option_renormalize;
+
+ /*
+ * NEEDSWORK: merge with table in builtin/merge-recursive
+ */
for (x = 0; x < xopts_nr; x++) {
if (!strcmp(xopts[x], "ours"))
o.recursive_variant = MERGE_RECURSIVE_OURS;
@@ -633,6 +643,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
o.subtree_shift = "";
else if (!prefixcmp(xopts[x], "subtree="))
o.subtree_shift = xopts[x]+8;
+ else if (!strcmp(xopts[x], "renormalize"))
+ o.renormalize = 1;
+ else if (!strcmp(xopts[x], "no-renormalize"))
+ o.renormalize = 0;
else
die("Unknown option for merge-recursive: -X%s", xopts[x]);
}
@@ -704,7 +718,7 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
opts.verbose_update = 1;
opts.merge = 1;
opts.fn = twoway_merge;
- opts.msgs = get_porcelain_error_msgs();
+ setup_unpack_trees_porcelain(&opts, "merge");
trees[nr_trees] = parse_tree_indirect(head);
if (!trees[nr_trees++])
@@ -816,7 +830,7 @@ static int finish_automerge(struct commit_list *common,
return 0;
}
-static int suggest_conflicts(void)
+static int suggest_conflicts(int renormalizing)
{
FILE *fp;
int pos;
@@ -1301,5 +1315,5 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
"stopped before committing as requested\n");
return 0;
} else
- return suggest_conflicts();
+ return suggest_conflicts(option_renormalize);
}
diff --git a/builtin/mv.c b/builtin/mv.c
index 38574b89f7..cdbb09473c 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -63,7 +63,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
const char **source, **destination, **dest_path;
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
struct stat st;
- struct string_list src_for_dst = {NULL, 0, 0, 0};
+ struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
git_config(git_default_config, NULL);
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 06a38ac8c1..31f5c1c971 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -220,7 +220,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
int cmd_name_rev(int argc, const char **argv, const char *prefix)
{
- struct object_array revs = { 0, 0, NULL };
+ struct object_array revs = OBJECT_ARRAY_INIT;
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0;
struct name_ref_data data = { 0, 0, NULL };
struct option opts[] = {
diff --git a/builtin/notes.c b/builtin/notes.c
index fbc347c9f0..6d07aac80c 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -769,6 +769,7 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
const char *object_ref;
struct notes_tree *t;
unsigned char object[20];
+ int retval;
argc = parse_options(argc, argv, prefix, options,
git_notes_remove_usage, 0);
@@ -785,12 +786,17 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
t = init_notes_check("remove");
- fprintf(stderr, "Removing note for object %s\n", sha1_to_hex(object));
- remove_note(t, object);
+ retval = remove_note(t, object);
+ if (retval)
+ fprintf(stderr, "Object %s has no note\n", sha1_to_hex(object));
+ else {
+ fprintf(stderr, "Removing note for object %s\n",
+ sha1_to_hex(object));
- commit_notes(t, "Notes removed by 'git notes remove'");
+ commit_notes(t, "Notes removed by 'git notes remove'");
+ }
free_notes(t);
- return 0;
+ return retval;
}
static int prune(int argc, const char **argv, const char *prefix)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 0e81673118..f8eba53c82 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -23,15 +23,15 @@
#endif
static const char pack_usage[] =
- "git pack-objects [{ -q | --progress | --all-progress }]\n"
+ "git pack-objects [ -q | --progress | --all-progress ]\n"
" [--all-progress-implied]\n"
- " [--max-pack-size=N] [--local] [--incremental]\n"
- " [--window=N] [--window-memory=N] [--depth=N]\n"
+ " [--max-pack-size=<n>] [--local] [--incremental]\n"
+ " [--window=<n>] [--window-memory=<n>] [--depth=<n>]\n"
" [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n"
- " [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n"
+ " [--threads=<n>] [--non-empty] [--revs [--unpacked | --all]]\n"
" [--reflog] [--stdout | base-name] [--include-tag]\n"
- " [--keep-unreachable | --unpack-unreachable \n"
- " [<ref-list | <object-list]";
+ " [--keep-unreachable | --unpack-unreachable]\n"
+ " [< ref-list | < object-list]";
struct object_entry {
struct pack_idx_entry idx;
@@ -431,7 +431,7 @@ static int write_one(struct sha1file *f,
written_list[nr_written++] = &e->idx;
/* make sure off_t is sufficiently large not to wrap */
- if (*offset > *offset + size)
+ if (signed_add_overflows(*offset, size))
die("pack too large for current definition of off_t");
*offset += size;
return 1;
diff --git a/builtin/push.c b/builtin/push.c
index 69bc2f27ac..e655eb7695 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -22,13 +22,13 @@ static int progress;
static const char **refspec;
static int refspec_nr;
+static int refspec_alloc;
static void add_refspec(const char *ref)
{
- int nr = refspec_nr + 1;
- refspec = xrealloc(refspec, nr * sizeof(char *));
- refspec[nr-1] = ref;
- refspec_nr = nr;
+ refspec_nr++;
+ ALLOC_GROW(refspec, refspec_nr, refspec_alloc);
+ refspec[refspec_nr-1] = ref;
}
static void set_refspecs(const char **refs, int nr)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d634b5a3d5..760817dbd7 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -530,7 +530,7 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
static void check_aliased_updates(struct command *commands)
{
struct command *cmd;
- struct string_list ref_list = { NULL, 0, 0, 0 };
+ struct string_list ref_list = STRING_LIST_INIT_NODUP;
for (cmd = commands; cmd; cmd = cmd->next) {
struct string_list_item *item =
diff --git a/builtin/remote.c b/builtin/remote.c
index 6699bc5712..e9a6e09257 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -15,7 +15,7 @@ static const char * const builtin_remote_usage[] = {
"git remote set-head <name> (-a | -d | <branch>)",
"git remote [-v | --verbose] show [-n] <name>",
"git remote prune [-n | --dry-run] <name>",
- "git remote [-v | --verbose] update [-p | --prune] [group | remote]",
+ "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]",
"git remote set-branches <name> [--add] <branch>...",
"git remote set-url <name> <newurl> [<oldurl>]",
"git remote set-url --add <name> <newurl>",
@@ -134,7 +134,7 @@ static int add_branch(const char *key, const char *branchname,
static int add(int argc, const char **argv)
{
int fetch = 0, mirror = 0, fetch_tags = TAGS_DEFAULT;
- struct string_list track = { NULL, 0, 0 };
+ struct string_list track = STRING_LIST_INIT_NODUP;
const char *master = NULL;
struct remote *remote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
@@ -596,7 +596,7 @@ static int mv(int argc, const char **argv)
};
struct remote *oldremote, *newremote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT;
- struct string_list remote_branches = { NULL, 0, 0, 0 };
+ struct string_list remote_branches = STRING_LIST_INIT_NODUP;
struct rename_info rename;
int i;
@@ -734,8 +734,8 @@ static int rm(int argc, const char **argv)
struct remote *remote;
struct strbuf buf = STRBUF_INIT;
struct known_remotes known_remotes = { NULL, NULL };
- struct string_list branches = { NULL, 0, 0, 1 };
- struct string_list skipped = { NULL, 0, 0, 1 };
+ struct string_list branches = STRING_LIST_INIT_DUP;
+ struct string_list skipped = STRING_LIST_INIT_DUP;
struct branches_for_remote cb_data;
int i, result;
@@ -1044,7 +1044,7 @@ static int show(int argc, const char **argv)
OPT_END()
};
struct ref_states states;
- struct string_list info_list = { NULL, 0, 0, 0 };
+ struct string_list info_list = STRING_LIST_INIT_NODUP;
struct show_info info;
argc = parse_options(argc, argv, NULL, options, builtin_remote_show_usage,
@@ -1483,7 +1483,7 @@ static int get_one_entry(struct remote *remote, void *priv)
static int show_all(void)
{
- struct string_list list = { NULL, 0, 0 };
+ struct string_list list = STRING_LIST_INIT_NODUP;
int result;
list.strdup_strings = 1;
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 0c7202eb9e..642bf35587 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -1,13 +1,16 @@
#include "builtin.h"
#include "cache.h"
#include "dir.h"
+#include "parse-options.h"
#include "string-list.h"
#include "rerere.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
-static const char git_rerere_usage[] =
-"git rerere [clear | status | diff | gc]";
+static const char * const rerere_usage[] = {
+ "git rerere [clear | status | diff | gc]",
+ NULL,
+};
/* these values are days */
static int cutoff_noresolve = 15;
@@ -46,7 +49,7 @@ static int git_rerere_gc_config(const char *var, const char *value, void *cb)
static void garbage_collect(struct string_list *rr)
{
- struct string_list to_remove = { NULL, 0, 0, 1 };
+ struct string_list to_remove = STRING_LIST_INIT_DUP;
DIR *dir;
struct dirent *e;
int i, cutoff;
@@ -113,26 +116,27 @@ static int diff_two(const char *file1, const char *label1,
int cmd_rerere(int argc, const char **argv, const char *prefix)
{
- struct string_list merge_rr = { NULL, 0, 0, 1 };
- int i, fd, flags = 0;
-
- if (2 < argc) {
- if (!strcmp(argv[1], "-h"))
- usage(git_rerere_usage);
- if (!strcmp(argv[1], "--rerere-autoupdate"))
- flags = RERERE_AUTOUPDATE;
- else if (!strcmp(argv[1], "--no-rerere-autoupdate"))
- flags = RERERE_NOAUTOUPDATE;
- if (flags) {
- argc--;
- argv++;
- }
- }
- if (argc < 2)
+ struct string_list merge_rr = STRING_LIST_INIT_DUP;
+ int i, fd, autoupdate = -1, flags = 0;
+
+ struct option options[] = {
+ OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
+ "register clean resolutions in index", 1),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);
+
+ if (autoupdate == 1)
+ flags = RERERE_AUTOUPDATE;
+ if (autoupdate == 0)
+ flags = RERERE_NOAUTOUPDATE;
+
+ if (argc < 1)
return rerere(flags);
- if (!strcmp(argv[1], "forget")) {
- const char **pathspec = get_pathspec(prefix, argv + 2);
+ if (!strcmp(argv[0], "forget")) {
+ const char **pathspec = get_pathspec(prefix, argv + 1);
return rerere_forget(pathspec);
}
@@ -140,26 +144,26 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (fd < 0)
return 0;
- if (!strcmp(argv[1], "clear")) {
+ if (!strcmp(argv[0], "clear")) {
for (i = 0; i < merge_rr.nr; i++) {
const char *name = (const char *)merge_rr.items[i].util;
if (!has_rerere_resolution(name))
unlink_rr_item(name);
}
unlink_or_warn(git_path("MERGE_RR"));
- } else if (!strcmp(argv[1], "gc"))
+ } else if (!strcmp(argv[0], "gc"))
garbage_collect(&merge_rr);
- else if (!strcmp(argv[1], "status"))
+ else if (!strcmp(argv[0], "status"))
for (i = 0; i < merge_rr.nr; i++)
printf("%s\n", merge_rr.items[i].string);
- else if (!strcmp(argv[1], "diff"))
+ else if (!strcmp(argv[0], "diff"))
for (i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
const char *name = (const char *)merge_rr.items[i].util;
diff_two(rerere_path(name, "preimage"), path, path, path);
}
else
- usage(git_rerere_usage);
+ usage_with_options(rerere_usage, options);
string_list_clear(&merge_rr, 1);
return 0;
diff --git a/builtin/reset.c b/builtin/reset.c
index 1283068fd2..0037be4693 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -318,7 +318,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
* affecting the working tree nor HEAD. */
if (i < argc) {
if (reset_type == MIXED)
- warning("--mixed option is deprecated with paths.");
+ warning("--mixed with paths is deprecated; use 'git reset -- <paths>' instead.");
else if (reset_type != NONE)
die("Cannot do %s reset with paths.",
reset_type_names[reset_type]);
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index efe9360e2f..158ce1111a 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -11,9 +11,9 @@
static const char rev_list_usage[] =
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
" limiting output:\n"
-" --max-count=nr\n"
-" --max-age=epoch\n"
-" --min-age=epoch\n"
+" --max-count=<n>\n"
+" --max-age=<epoch>\n"
+" --min-age=<epoch>\n"
" --sparse\n"
" --no-merges\n"
" --remove-empty\n"
@@ -33,7 +33,7 @@ static const char rev_list_usage[] =
" --objects | --objects-edge\n"
" --unpacked\n"
" --header | --pretty\n"
-" --abbrev=nr | --no-abbrev\n"
+" --abbrev=<n> | --no-abbrev\n"
" --abbrev-commit\n"
" --left-right\n"
" special purpose:\n"
diff --git a/builtin/revert.c b/builtin/revert.c
index 54d13cf5ef..4b47ace36b 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,9 +102,9 @@ struct commit_message {
static int get_message(const char *raw_message, struct commit_message *out)
{
const char *encoding;
- const char *p, *abbrev, *eol;
+ const char *abbrev, *subject;
+ int abbrev_len, subject_len;
char *q;
- int abbrev_len, oneline_len;
if (!raw_message)
return -1;
@@ -125,27 +125,17 @@ static int get_message(const char *raw_message, struct commit_message *out)
abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
abbrev_len = strlen(abbrev);
- /* Find beginning and end of commit subject. */
- p = out->message;
- while (*p && (*p != '\n' || p[1] != '\n'))
- p++;
- if (*p) {
- p += 2;
- for (eol = p + 1; *eol && *eol != '\n'; eol++)
- ; /* do nothing */
- } else
- eol = p;
- oneline_len = eol - p;
+ subject_len = find_commit_subject(out->message, &subject);
out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
- strlen("... ") + oneline_len + 1);
+ strlen("... ") + subject_len + 1);
q = out->parent_label;
q = mempcpy(q, "parent of ", strlen("parent of "));
out->label = q;
q = mempcpy(q, abbrev, abbrev_len);
q = mempcpy(q, "... ", strlen("... "));
out->subject = q;
- q = mempcpy(q, p, oneline_len);
+ q = mempcpy(q, subject, subject_len);
*q = '\0';
return 0;
}
@@ -241,27 +231,30 @@ static void set_author_ident_env(const char *message)
sha1_to_hex(commit->object.sha1));
}
-static char *help_msg(void)
+static void advise(const char *advice, ...)
{
- struct strbuf helpbuf = STRBUF_INIT;
- char *msg = getenv("GIT_CHERRY_PICK_HELP");
+ va_list params;
- if (msg)
- return msg;
+ va_start(params, advice);
+ vreportf("hint: ", advice, params);
+ va_end(params);
+}
- strbuf_addstr(&helpbuf, " After resolving the conflicts,\n"
- "mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
- "and commit the result");
+static void print_advice(void)
+{
+ char *msg = getenv("GIT_CHERRY_PICK_HELP");
- if (action == CHERRY_PICK) {
- strbuf_addf(&helpbuf, " with: \n"
- "\n"
- " git commit -c %s\n",
- sha1_to_hex(commit->object.sha1));
+ if (msg) {
+ fprintf(stderr, "%s\n", msg);
+ return;
}
- else
- strbuf_addch(&helpbuf, '.');
- return strbuf_detach(&helpbuf, NULL);
+
+ advise("after resolving the conflicts, mark the corrected paths");
+ advise("with 'git add <paths>' or 'git rm <paths>'");
+
+ if (action == CHERRY_PICK)
+ advise("and commit the result with 'git commit -c %s'",
+ find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
}
static void write_message(struct strbuf *msgbuf, const char *filename)
@@ -311,10 +304,9 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from)
return write_ref_sha1(ref_lock, to, "cherry-pick");
}
-static void do_recursive_merge(struct commit *base, struct commit *next,
- const char *base_label, const char *next_label,
- unsigned char *head, struct strbuf *msgbuf,
- char *defmsg)
+static int do_recursive_merge(struct commit *base, struct commit *next,
+ const char *base_label, const char *next_label,
+ unsigned char *head, struct strbuf *msgbuf)
{
struct merge_options o;
struct tree *result, *next_tree, *base_tree, *head_tree;
@@ -324,6 +316,13 @@ static void do_recursive_merge(struct commit *base, struct commit *next,
index_fd = hold_locked_index(&index_lock, 1);
read_cache();
+
+ /*
+ * NEEDSWORK: cherry-picking between branches with
+ * different end-of-line normalization is a pain;
+ * plumb in an option to set o.renormalize?
+ * (or better: arbitrary -X options)
+ */
init_merge_options(&o);
o.ancestor = base ? base_label : "(empty tree)";
o.branch1 = "HEAD";
@@ -357,14 +356,35 @@ static void do_recursive_merge(struct commit *base, struct commit *next,
i++;
}
}
- write_message(msgbuf, defmsg);
- fprintf(stderr, "Automatic %s failed.%s\n",
- me, help_msg());
- rerere(allow_rerere_auto);
- exit(1);
}
- write_message(msgbuf, defmsg);
- fprintf(stderr, "Finished one %s.\n", me);
+
+ return !clean;
+}
+
+/*
+ * If we are cherry-pick, and if the merge did not result in
+ * hand-editing, we will hit this commit and inherit the original
+ * author date and name.
+ * If we are revert, or if our cherry-pick results in a hand merge,
+ * we had better say that the current user is responsible for that.
+ */
+static int run_git_commit(const char *defmsg)
+{
+ /* 6 is max possible length of our args array including NULL */
+ const char *args[6];
+ int i = 0;
+
+ args[i++] = "commit";
+ args[i++] = "-n";
+ if (signoff)
+ args[i++] = "-s";
+ if (!edit) {
+ args[i++] = "-F";
+ args[i++] = defmsg;
+ }
+ args[i] = NULL;
+
+ return run_command_v_opt(args, RUN_GIT_CMD);
}
static int do_pick_commit(void)
@@ -375,6 +395,7 @@ static int do_pick_commit(void)
struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
char *defmsg = NULL;
struct strbuf msgbuf = STRBUF_INIT;
+ int res;
if (no_commit) {
/*
@@ -470,62 +491,40 @@ static int do_pick_commit(void)
}
}
- if (!strategy || !strcmp(strategy, "recursive") || action == REVERT)
- do_recursive_merge(base, next, base_label, next_label,
- head, &msgbuf, defmsg);
- else {
- int res;
+ if (!strategy || !strcmp(strategy, "recursive") || action == REVERT) {
+ res = do_recursive_merge(base, next, base_label, next_label,
+ head, &msgbuf);
+ write_message(&msgbuf, defmsg);
+ } else {
struct commit_list *common = NULL;
struct commit_list *remotes = NULL;
+
write_message(&msgbuf, defmsg);
+
commit_list_insert(base, &common);
commit_list_insert(next, &remotes);
res = try_merge_command(strategy, common,
sha1_to_hex(head), remotes);
free_commit_list(common);
free_commit_list(remotes);
- if (res) {
- fprintf(stderr, "Automatic %s with strategy %s failed.%s\n",
- me, strategy, help_msg());
- rerere(allow_rerere_auto);
- exit(1);
- }
}
- free_message(&msg);
-
- /*
- * If we are cherry-pick, and if the merge did not result in
- * hand-editing, we will hit this commit and inherit the original
- * author date and name.
- * If we are revert, or if our cherry-pick results in a hand merge,
- * we had better say that the current user is responsible for that.
- */
-
- if (!no_commit) {
- /* 6 is max possible length of our args array including NULL */
- const char *args[6];
- int res;
- int i = 0;
-
- args[i++] = "commit";
- args[i++] = "-n";
- if (signoff)
- args[i++] = "-s";
- if (!edit) {
- args[i++] = "-F";
- args[i++] = defmsg;
- }
- args[i] = NULL;
- res = run_command_v_opt(args, RUN_GIT_CMD);
- free(defmsg);
-
- return res;
+ if (res) {
+ error("could not %s %s... %s",
+ action == REVERT ? "revert" : "apply",
+ find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
+ msg.subject);
+ print_advice();
+ rerere(allow_rerere_auto);
+ } else {
+ if (!no_commit)
+ res = run_git_commit(defmsg);
}
+ free_message(&msg);
free(defmsg);
- return 0;
+ return res;
}
static void prepare_revs(struct rev_info *revs)
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 0a9681ba7e..2135b0dde1 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -249,7 +249,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
{
static struct shortlog log;
static struct rev_info rev;
- int nongit;
+ int nongit = !startup_info->have_repository;
static const struct option options[] = {
OPT_BOOLEAN('n', "numbered", &log.sort_by_number,
@@ -265,7 +265,6 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
struct parse_opt_ctx_t ctx;
- prefix = setup_git_directory_gently(&nongit);
git_config(git_default_config, NULL);
shortlog_init(&log);
init_revisions(&rev, prefix);
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index e8719aa9e9..8663ccaa99 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -6,7 +6,7 @@
#include "parse-options.h"
static const char* show_branch_usage[] = {
- "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>]...",
+ "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>)...]",
"git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]",
NULL
};
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 0b2a9ad1a9..be9b512eeb 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -120,7 +120,7 @@ static int add_existing(const char *refname, const unsigned char *sha1, int flag
*/
static int exclude_existing(const char *match)
{
- static struct string_list existing_refs = { NULL, 0, 0, 0 };
+ static struct string_list existing_refs = STRING_LIST_INIT_NODUP;
char buf[1024];
int matchlen = match ? strlen(match) : 0;
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 685566e0b5..f63973c914 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -83,7 +83,7 @@ static void use(int bytes)
offset += bytes;
/* make sure off_t is sufficiently large not to wrap */
- if (consumed_bytes > consumed_bytes + bytes)
+ if (signed_add_overflows(consumed_bytes, bytes))
die("pack too large for current definition of off_t");
consumed_bytes += bytes;
}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 3ab214d24e..62d9f3f0fa 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -398,7 +398,7 @@ static void read_index_info(int line_termination)
}
static const char update_index_usage[] =
-"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] [<file>...]";
static unsigned char head_sha1[20];
static unsigned char merge_head_sha1[20];
diff --git a/builtin/var.c b/builtin/var.c
index 70fdb4dec7..0744bb8318 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -74,14 +74,9 @@ static int show_config(const char *var, const char *value, void *cb)
int cmd_var(int argc, const char **argv, const char *prefix)
{
- const char *val;
- int nongit;
- if (argc != 2) {
+ const char *val = NULL;
+ if (argc != 2)
usage(var_usage);
- }
-
- setup_git_directory_gently(&nongit);
- val = NULL;
if (strcmp(argv[1], "-l") == 0) {
git_config(show_config, NULL);