summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c97
-rw-r--r--builtin/am.c52
-rw-r--r--builtin/archive.c4
-rw-r--r--builtin/bisect--helper.c3
-rw-r--r--builtin/branch.c12
-rw-r--r--builtin/bugreport.c13
-rw-r--r--builtin/bundle.c74
-rw-r--r--builtin/cat-file.c10
-rw-r--r--builtin/check-ignore.c7
-rw-r--r--builtin/checkout--worker.c145
-rw-r--r--builtin/checkout-index.c26
-rw-r--r--builtin/checkout.c34
-rw-r--r--builtin/clean.c14
-rw-r--r--builtin/clone.c13
-rw-r--r--builtin/column.c2
-rw-r--r--builtin/commit-graph.c90
-rw-r--r--builtin/commit-tree.c4
-rw-r--r--builtin/commit.c44
-rw-r--r--builtin/config.c6
-rw-r--r--builtin/credential-cache.c2
-rw-r--r--builtin/credential-store.c2
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff-index.c9
-rw-r--r--builtin/diff.c6
-rw-r--r--builtin/difftool.c10
-rw-r--r--builtin/fast-export.c10
-rw-r--r--builtin/fast-import.c8
-rw-r--r--builtin/fetch.c112
-rw-r--r--builtin/for-each-ref.c18
-rw-r--r--builtin/for-each-repo.c14
-rw-r--r--builtin/fsck.c7
-rw-r--r--builtin/gc.c142
-rw-r--r--builtin/grep.c7
-rw-r--r--builtin/hash-object.c4
-rw-r--r--builtin/help.c17
-rw-r--r--builtin/index-pack.c18
-rw-r--r--builtin/init-db.c3
-rw-r--r--builtin/log.c10
-rw-r--r--builtin/ls-files.c25
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/mailinfo.c115
-rw-r--r--builtin/mailsplit.c4
-rw-r--r--builtin/merge-index.c5
-rw-r--r--builtin/merge-ours.c4
-rw-r--r--builtin/merge-tree.c5
-rw-r--r--builtin/merge.c51
-rw-r--r--builtin/mktree.c2
-rw-r--r--builtin/multi-pack-index.c11
-rw-r--r--builtin/mv.c5
-rw-r--r--builtin/notes.c4
-rw-r--r--builtin/pack-objects.c319
-rw-r--r--builtin/pack-redundant.c28
-rw-r--r--builtin/pull.c81
-rw-r--r--builtin/push.c79
-rw-r--r--builtin/rebase.c14
-rw-r--r--builtin/receive-pack.c7
-rw-r--r--builtin/repack.c9
-rw-r--r--builtin/rerere.c4
-rw-r--r--builtin/rev-list.c69
-rw-r--r--builtin/rev-parse.c30
-rw-r--r--builtin/revert.c3
-rw-r--r--builtin/rm.c39
-rw-r--r--builtin/send-pack.c1
-rw-r--r--builtin/show-branch.c9
-rw-r--r--builtin/show-index.c4
-rw-r--r--builtin/sparse-checkout.c54
-rw-r--r--builtin/stash.c24
-rw-r--r--builtin/submodule--helper.c455
-rw-r--r--builtin/tag.c21
-rw-r--r--builtin/unpack-objects.c7
-rw-r--r--builtin/update-index.c6
-rw-r--r--builtin/worktree.c29
72 files changed, 1784 insertions, 792 deletions
diff --git a/builtin/add.c b/builtin/add.c
index ea762a41e3..8ec5ad9f26 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -46,6 +46,9 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
struct cache_entry *ce = active_cache[i];
int err;
+ if (ce_skip_worktree(ce))
+ continue;
+
if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
continue;
@@ -144,6 +147,8 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
+ if (ce_skip_worktree(ce))
+ continue;
if (ce_stage(ce))
continue; /* do not touch unmerged paths */
if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
@@ -172,24 +177,52 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
*dst++ = entry;
}
dir->nr = dst - dir->entries;
- add_pathspec_matches_against_index(pathspec, &the_index, seen);
+ add_pathspec_matches_against_index(pathspec, &the_index, seen,
+ PS_IGNORE_SKIP_WORKTREE);
return seen;
}
-static void refresh(int verbose, const struct pathspec *pathspec)
+static int refresh(int verbose, const struct pathspec *pathspec)
{
char *seen;
- int i;
+ int i, ret = 0;
+ char *skip_worktree_seen = NULL;
+ struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
+ int flags = REFRESH_IGNORE_SKIP_WORKTREE |
+ (verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
+ struct pattern_list pl = { 0 };
+ int sparse_checkout_enabled = !get_sparse_checkout_patterns(&pl);
seen = xcalloc(pathspec->nr, 1);
- refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
- pathspec, seen, _("Unstaged changes after refreshing the index:"));
+ refresh_index(&the_index, flags, pathspec, seen,
+ _("Unstaged changes after refreshing the index:"));
for (i = 0; i < pathspec->nr; i++) {
- if (!seen[i])
- die(_("pathspec '%s' did not match any files"),
- pathspec->items[i].match);
+ if (!seen[i]) {
+ const char *path = pathspec->items[i].original;
+ int dtype = DT_REG;
+
+ if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
+ (sparse_checkout_enabled &&
+ !path_matches_pattern_list(path, strlen(path), NULL,
+ &dtype, &pl, &the_index))) {
+ string_list_append(&only_match_skip_worktree,
+ pathspec->items[i].original);
+ } else {
+ die(_("pathspec '%s' did not match any files"),
+ pathspec->items[i].original);
+ }
+ }
}
+
+ if (only_match_skip_worktree.nr) {
+ advise_on_updating_sparse_paths(&only_match_skip_worktree);
+ ret = 1;
+ }
+
free(seen);
+ free(skip_worktree_seen);
+ string_list_clear(&only_match_skip_worktree, 0);
+ return ret;
}
int run_add_interactive(const char *revision, const char *patch_mode,
@@ -286,9 +319,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
rev.diffopt.use_color = 0;
rev.diffopt.flags.ignore_dirty_submodules = 1;
- out = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
- if (out < 0)
- die(_("Could not open '%s' for writing."), file);
+ out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
rev.diffopt.file = xfdopen(out, "w");
rev.diffopt.close_file = 1;
if (run_diff_files(&rev, 0))
@@ -443,7 +474,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
{
int exit_status = 0;
struct pathspec pathspec;
- struct dir_struct dir;
+ struct dir_struct dir = DIR_INIT;
int flags;
int add_new_files;
int require_pathspec;
@@ -457,6 +488,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (patch_interactive)
add_interactive = 1;
if (add_interactive) {
+ if (show_only)
+ die(_("--dry-run is incompatible with --interactive/--patch"));
if (pathspec_from_file)
die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
exit(interactive_add(argv + 1, prefix, patch_interactive));
@@ -499,6 +532,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
/*
@@ -548,7 +584,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die_in_unpopulated_submodule(&the_index, prefix);
die_path_inside_submodule(&the_index, &pathspec);
- dir_init(&dir);
if (add_new_files) {
int baselen;
@@ -565,15 +600,18 @@ int cmd_add(int argc, const char **argv, const char *prefix)
}
if (refresh_only) {
- refresh(verbose, &pathspec);
+ exit_status |= refresh(verbose, &pathspec);
goto finish;
}
if (pathspec.nr) {
int i;
+ char *skip_worktree_seen = NULL;
+ struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
if (!seen)
- seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
+ seen = find_pathspecs_matching_against_index(&pathspec,
+ &the_index, PS_IGNORE_SKIP_WORKTREE);
/*
* file_exists() assumes exact match
@@ -587,12 +625,24 @@ int cmd_add(int argc, const char **argv, const char *prefix)
for (i = 0; i < pathspec.nr; i++) {
const char *path = pathspec.items[i].match;
+
if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
continue;
- if (!seen[i] && path[0] &&
- ((pathspec.items[i].magic &
- (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
- !file_exists(path))) {
+ if (seen[i])
+ continue;
+
+ if (matches_skip_worktree(&pathspec, i, &skip_worktree_seen)) {
+ string_list_append(&only_match_skip_worktree,
+ pathspec.items[i].original);
+ continue;
+ }
+
+ /* Don't complain at 'git add .' on empty repo */
+ if (!path[0])
+ continue;
+
+ if ((pathspec.items[i].magic & (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
+ !file_exists(path)) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
if (is_excluded(&dir, &the_index, path, &dtype))
@@ -603,7 +653,16 @@ int cmd_add(int argc, const char **argv, const char *prefix)
pathspec.items[i].original);
}
}
+
+
+ if (only_match_skip_worktree.nr) {
+ advise_on_updating_sparse_paths(&only_match_skip_worktree);
+ exit_status = 1;
+ }
+
free(seen);
+ free(skip_worktree_seen);
+ string_list_clear(&only_match_skip_worktree, 0);
}
plug_bulk_checkin();
diff --git a/builtin/am.c b/builtin/am.c
index 8355e3566f..0c2ad96b70 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -116,6 +116,7 @@ struct am_state {
int keep; /* enum keep_type */
int message_id;
int scissors; /* enum scissors_type */
+ int quoted_cr; /* enum quoted_cr_action */
struct strvec git_apply_opts;
const char *resolvemsg;
int committer_date_is_author_date;
@@ -145,6 +146,7 @@ static void am_state_init(struct am_state *state)
git_config_get_bool("am.messageid", &state->message_id);
state->scissors = SCISSORS_UNSET;
+ state->quoted_cr = quoted_cr_unset;
strvec_init(&state->git_apply_opts);
@@ -165,6 +167,16 @@ static void am_state_release(struct am_state *state)
strvec_clear(&state->git_apply_opts);
}
+static int am_option_parse_quoted_cr(const struct option *opt,
+ const char *arg, int unset)
+{
+ BUG_ON_OPT_NEG(unset);
+
+ if (mailinfo_parse_quoted_cr_action(arg, opt->value) != 0)
+ return error(_("bad action '%s' for '%s'"), arg, "--quoted-cr");
+ return 0;
+}
+
/**
* Returns path relative to the am_state directory.
*/
@@ -198,6 +210,7 @@ static void write_state_bool(const struct am_state *state,
* If state->quiet is false, calls fprintf(fp, fmt, ...), and appends a newline
* at the end.
*/
+__attribute__((format (printf, 3, 4)))
static void say(const struct am_state *state, FILE *fp, const char *fmt, ...)
{
va_list ap;
@@ -397,6 +410,12 @@ static void am_load(struct am_state *state)
else
state->scissors = SCISSORS_UNSET;
+ read_state_file(&sb, state, "quoted-cr", 1);
+ if (!*sb.buf)
+ state->quoted_cr = quoted_cr_unset;
+ else if (mailinfo_parse_quoted_cr_action(sb.buf, &state->quoted_cr) != 0)
+ die(_("could not parse %s"), am_path(state, "quoted-cr"));
+
read_state_file(&sb, state, "apply-opt", 1);
strvec_clear(&state->git_apply_opts);
if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0)
@@ -1002,6 +1021,24 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
}
write_state_text(state, "scissors", str);
+ switch (state->quoted_cr) {
+ case quoted_cr_unset:
+ str = "";
+ break;
+ case quoted_cr_nowarn:
+ str = "nowarn";
+ break;
+ case quoted_cr_warn:
+ str = "warn";
+ break;
+ case quoted_cr_strip:
+ str = "strip";
+ break;
+ default:
+ BUG("invalid value for state->quoted_cr");
+ }
+ write_state_text(state, "quoted-cr", str);
+
sq_quote_argv(&sb, state->git_apply_opts.v);
write_state_text(state, "apply-opt", sb.buf);
@@ -1162,6 +1199,18 @@ static int parse_mail(struct am_state *state, const char *mail)
BUG("invalid value for state->scissors");
}
+ switch (state->quoted_cr) {
+ case quoted_cr_unset:
+ break;
+ case quoted_cr_nowarn:
+ case quoted_cr_warn:
+ case quoted_cr_strip:
+ mi.quoted_cr = state->quoted_cr;
+ break;
+ default:
+ BUG("invalid value for state->quoted_cr");
+ }
+
mi.input = xfopen(mail, "r");
mi.output = xfopen(am_path(state, "info"), "w");
if (mailinfo(&mi, am_path(state, "msg"), am_path(state, "patch")))
@@ -2242,6 +2291,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
0, PARSE_OPT_NONEG),
OPT_BOOL('c', "scissors", &state.scissors,
N_("strip everything before a scissors line")),
+ OPT_CALLBACK_F(0, "quoted-cr", &state.quoted_cr, N_("action"),
+ N_("pass it through git-mailinfo"),
+ PARSE_OPT_NONEG, am_option_parse_quoted_cr),
OPT_PASSTHRU_ARGV(0, "whitespace", &state.git_apply_opts, N_("action"),
N_("pass it through git-apply"),
0),
diff --git a/builtin/archive.c b/builtin/archive.c
index 45d11669aa..7176b041b6 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -12,9 +12,7 @@
static void create_output_file(const char *output_file)
{
- int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
- if (output_fd < 0)
- die_errno(_("could not create archive file '%s'"), output_file);
+ int output_fd = xopen(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
if (output_fd != 1) {
if (dup2(output_fd, 1) < 0)
die_errno(_("could not redirect output"));
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1fdb7d9d10..f184eaeac6 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -117,6 +117,7 @@ static int write_in_file(const char *path, const char *mode, const char *format,
return fclose(fp);
}
+__attribute__((format (printf, 2, 3)))
static int write_to_file(const char *path, const char *format, ...)
{
int res;
@@ -129,6 +130,7 @@ static int write_to_file(const char *path, const char *format, ...)
return res;
}
+__attribute__((format (printf, 2, 3)))
static int append_to_file(const char *path, const char *format, ...)
{
int res;
@@ -1126,6 +1128,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
break;
case BISECT_SKIP:
set_terms(&terms, "bad", "good");
+ get_terms(&terms);
res = bisect_skip(&terms, argv, argc);
break;
default:
diff --git a/builtin/branch.c b/builtin/branch.c
index bcc00bcf18..03c7b7253a 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -168,7 +168,7 @@ static int check_branch_commit(const char *branchname, const char *refname,
int kinds, int force)
{
struct commit *rev = lookup_commit_reference(the_repository, oid);
- if (!rev) {
+ if (!force && !rev) {
error(_("Couldn't look up commit object for '%s'"), refname);
return -1;
}
@@ -411,6 +411,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
{
int i;
struct ref_array array;
+ struct strbuf out = STRBUF_INIT;
+ struct strbuf err = STRBUF_INIT;
int maxwidth = 0;
const char *remote_prefix = "";
char *to_free = NULL;
@@ -440,8 +442,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
ref_array_sort(sorting, &array);
for (i = 0; i < array.nr; i++) {
- struct strbuf out = STRBUF_INIT;
- struct strbuf err = STRBUF_INIT;
+ strbuf_reset(&err);
+ strbuf_reset(&out);
if (format_ref_array_item(array.items[i], format, &out, &err))
die("%s", err.buf);
if (column_active(colopts)) {
@@ -452,10 +454,10 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
fwrite(out.buf, 1, out.len, stdout);
putchar('\n');
}
- strbuf_release(&err);
- strbuf_release(&out);
}
+ strbuf_release(&err);
+ strbuf_release(&out);
ref_array_clear(&array);
free(to_free);
}
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index ad3cc9c02f..06ed10dc92 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -129,6 +129,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
char *option_output = NULL;
char *option_suffix = "%Y-%m-%d-%H%M";
const char *user_relative_path = NULL;
+ char *prefixed_filename;
const struct option bugreport_options[] = {
OPT_STRING('o', "output-directory", &option_output, N_("path"),
@@ -142,9 +143,9 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
bugreport_usage, 0);
/* Prepare the path to put the result */
- strbuf_addstr(&report_path,
- prefix_filename(prefix,
- option_output ? option_output : ""));
+ prefixed_filename = prefix_filename(prefix,
+ option_output ? option_output : "");
+ strbuf_addstr(&report_path, prefixed_filename);
strbuf_complete(&report_path, '/');
strbuf_addstr(&report_path, "git-bugreport-");
@@ -170,10 +171,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
get_populated_hooks(&buffer, !startup_info->have_repository);
/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
- report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
-
- if (report < 0)
- die(_("couldn't create a new file at '%s'"), report_path.buf);
+ report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (write_in_full(report, buffer.buf, buffer.len) < 0)
die_errno(_("unable to write to %s"), report_path.buf);
@@ -189,6 +187,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
fprintf(stderr, _("Created new report at '%s'.\n"),
user_relative_path);
+ free(prefixed_filename);
UNLEAK(buffer);
UNLEAK(report_path);
return !!launch_editor(report_path.buf, NULL, NULL);
diff --git a/builtin/bundle.c b/builtin/bundle.c
index ea6948110b..053a51bea1 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -46,7 +46,7 @@ static int parse_options_cmd_bundle(int argc,
const char* prefix,
const char * const usagestr[],
const struct option options[],
- const char **bundle_file) {
+ char **bundle_file) {
int newargc;
newargc = parse_options(argc, argv, NULL, options, usagestr,
PARSE_OPT_STOP_AT_NON_OPTION);
@@ -61,7 +61,7 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
int progress = isatty(STDERR_FILENO);
struct strvec pack_opts;
int version = -1;
-
+ int ret;
struct option options[] = {
OPT_SET_INT('q', "quiet", &progress,
N_("do not show progress meter"), 0),
@@ -76,7 +76,7 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
N_("specify bundle format version")),
OPT_END()
};
- const char* bundle_file;
+ char *bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_create_usage, options, &bundle_file);
@@ -94,75 +94,95 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
- return !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
+ ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
+ free(bundle_file);
+ return ret;
}
static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
- struct bundle_header header;
+ struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
int quiet = 0;
-
+ int ret;
struct option options[] = {
OPT_BOOL('q', "quiet", &quiet,
N_("do not show bundle details")),
OPT_END()
};
- const char* bundle_file;
+ char *bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_verify_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- memset(&header, 0, sizeof(header));
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
- return 1;
+ if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ ret = 1;
+ goto cleanup;
+ }
close(bundle_fd);
- if (verify_bundle(the_repository, &header, !quiet))
- return 1;
+ if (verify_bundle(the_repository, &header, !quiet)) {
+ ret = 1;
+ goto cleanup;
+ }
+
fprintf(stderr, _("%s is okay\n"), bundle_file);
- return 0;
+ ret = 0;
+cleanup:
+ free(bundle_file);
+ bundle_header_release(&header);
+ return ret;
}
static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix) {
- struct bundle_header header;
+ struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
-
+ int ret;
struct option options[] = {
OPT_END()
};
- const char* bundle_file;
+ char *bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_list_heads_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- memset(&header, 0, sizeof(header));
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
- return 1;
+ if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ ret = 1;
+ goto cleanup;
+ }
close(bundle_fd);
- return !!list_bundle_refs(&header, argc, argv);
+ ret = !!list_bundle_refs(&header, argc, argv);
+cleanup:
+ free(bundle_file);
+ bundle_header_release(&header);
+ return ret;
}
static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) {
- struct bundle_header header;
+ struct bundle_header header = BUNDLE_HEADER_INIT;
int bundle_fd = -1;
-
+ int ret;
struct option options[] = {
OPT_END()
};
- const char* bundle_file;
+ char *bundle_file;
argc = parse_options_cmd_bundle(argc, argv, prefix,
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
- memset(&header, 0, sizeof(header));
- if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0)
- return 1;
+ if ((bundle_fd = read_bundle_header(bundle_file, &header)) < 0) {
+ ret = 1;
+ goto cleanup;
+ }
if (!startup_info->have_repository)
die(_("Need a repository to unbundle."));
- return !!unbundle(the_repository, &header, bundle_fd, 0) ||
+ ret = !!unbundle(the_repository, &header, bundle_fd, 0) ||
list_bundle_refs(&header, argc, argv);
+ bundle_header_release(&header);
+cleanup:
+ free(bundle_file);
+ return ret;
}
int cmd_bundle(int argc, const char **argv, const char *prefix)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 5ebf13359e..243fe6844b 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -512,12 +512,6 @@ static int batch_objects(struct batch_options *opt)
if (opt->cmdmode)
data.split_on_whitespace = 1;
- if (opt->all_objects) {
- struct object_info empty = OBJECT_INFO_INIT;
- if (!memcmp(&data.info, &empty, sizeof(empty)))
- data.skip_object_info = 1;
- }
-
/*
* If we are printing out the object, then always fill in the type,
* since we will want to decide whether or not to stream.
@@ -527,6 +521,10 @@ static int batch_objects(struct batch_options *opt)
if (opt->all_objects) {
struct object_cb_data cb;
+ struct object_info empty = OBJECT_INFO_INIT;
+
+ if (!memcmp(&data.info, &empty, sizeof(empty)))
+ data.skip_object_info = 1;
if (has_promisor_remote())
warning("This repository uses promisor remotes. Some objects may not be loaded.");
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 3c652748d5..2191256965 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -100,7 +100,8 @@ static int check_ignore(struct dir_struct *dir,
* should not be ignored, in order to be consistent with
* 'git status', 'git add' etc.
*/
- seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
+ seen = find_pathspecs_matching_against_index(&pathspec, &the_index,
+ PS_HEED_SKIP_WORKTREE);
for (i = 0; i < pathspec.nr; i++) {
full_path = pathspec.items[i].match;
pattern = NULL;
@@ -118,6 +119,7 @@ static int check_ignore(struct dir_struct *dir,
num_ignored++;
}
free(seen);
+ clear_pathspec(&pathspec);
return num_ignored;
}
@@ -151,7 +153,7 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
int cmd_check_ignore(int argc, const char **argv, const char *prefix)
{
int num_ignored;
- struct dir_struct dir;
+ struct dir_struct dir = DIR_INIT;
git_config(git_default_config, NULL);
@@ -180,7 +182,6 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
if (!no_index && read_cache() < 0)
die(_("index file corrupt"));
- dir_init(&dir);
setup_standard_excludes(&dir);
if (stdin_paths) {
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
new file mode 100644
index 0000000000..fb9fd13b73
--- /dev/null
+++ b/builtin/checkout--worker.c
@@ -0,0 +1,145 @@
+#include "builtin.h"
+#include "config.h"
+#include "entry.h"
+#include "parallel-checkout.h"
+#include "parse-options.h"
+#include "pkt-line.h"
+
+static void packet_to_pc_item(const char *buffer, int len,
+ struct parallel_checkout_item *pc_item)
+{
+ const struct pc_item_fixed_portion *fixed_portion;
+ const char *variant;
+ char *encoding;
+
+ if (len < sizeof(struct pc_item_fixed_portion))
+ BUG("checkout worker received too short item (got %dB, exp %dB)",
+ len, (int)sizeof(struct pc_item_fixed_portion));
+
+ fixed_portion = (struct pc_item_fixed_portion *)buffer;
+
+ if (len - sizeof(struct pc_item_fixed_portion) !=
+ fixed_portion->name_len + fixed_portion->working_tree_encoding_len)
+ BUG("checkout worker received corrupted item");
+
+ variant = buffer + sizeof(struct pc_item_fixed_portion);
+
+ /*
+ * Note: the main process uses zero length to communicate that the
+ * encoding is NULL. There is no use case that requires sending an
+ * actual empty string, since convert_attrs() never sets
+ * ca.working_tree_enconding to "".
+ */
+ if (fixed_portion->working_tree_encoding_len) {
+ encoding = xmemdupz(variant,
+ fixed_portion->working_tree_encoding_len);
+ variant += fixed_portion->working_tree_encoding_len;
+ } else {
+ encoding = NULL;
+ }
+
+ memset(pc_item, 0, sizeof(*pc_item));
+ pc_item->ce = make_empty_transient_cache_entry(fixed_portion->name_len, NULL);
+ pc_item->ce->ce_namelen = fixed_portion->name_len;
+ pc_item->ce->ce_mode = fixed_portion->ce_mode;
+ memcpy(pc_item->ce->name, variant, pc_item->ce->ce_namelen);
+ oidcpy(&pc_item->ce->oid, &fixed_portion->oid);
+
+ pc_item->id = fixed_portion->id;
+ pc_item->ca.crlf_action = fixed_portion->crlf_action;
+ pc_item->ca.ident = fixed_portion->ident;
+ pc_item->ca.working_tree_encoding = encoding;
+}
+
+static void report_result(struct parallel_checkout_item *pc_item)
+{
+ struct pc_item_result res = { 0 };
+ size_t size;
+
+ res.id = pc_item->id;
+ res.status = pc_item->status;
+
+ if (pc_item->status == PC_ITEM_WRITTEN) {
+ res.st = pc_item->st;
+ size = sizeof(res);
+ } else {
+ size = PC_ITEM_RESULT_BASE_SIZE;
+ }
+
+ packet_write(1, (const char *)&res, size);
+}
+
+/* Free the worker-side malloced data, but not pc_item itself. */
+static void release_pc_item_data(struct parallel_checkout_item *pc_item)
+{
+ free((char *)pc_item->ca.working_tree_encoding);
+ discard_cache_entry(pc_item->ce);
+}
+
+static void worker_loop(struct checkout *state)
+{
+ struct parallel_checkout_item *items = NULL;
+ size_t i, nr = 0, alloc = 0;
+
+ while (1) {
+ int len = packet_read(0, NULL, NULL, packet_buffer,
+ sizeof(packet_buffer), 0);
+
+ if (len < 0)
+ BUG("packet_read() returned negative value");
+ else if (!len)
+ break;
+
+ ALLOC_GROW(items, nr + 1, alloc);
+ packet_to_pc_item(packet_buffer, len, &items[nr++]);
+ }
+
+ for (i = 0; i < nr; i++) {
+ struct parallel_checkout_item *pc_item = &items[i];
+ write_pc_item(pc_item, state);
+ report_result(pc_item);
+ release_pc_item_data(pc_item);
+ }
+
+ packet_flush(1);
+
+ free(items);
+}
+
+static const char * const checkout_worker_usage[] = {
+ N_("git checkout--worker [<options>]"),
+ NULL
+};
+
+int cmd_checkout__worker(int argc, const char **argv, const char *prefix)
+{
+ struct checkout state = CHECKOUT_INIT;
+ struct option checkout_worker_options[] = {
+ OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
+ N_("when creating files, prepend <string>")),
+ OPT_END()
+ };
+
+ if (argc == 2 && !strcmp(argv[1], "-h"))
+ usage_with_options(checkout_worker_usage,
+ checkout_worker_options);
+
+ git_config(git_default_config, NULL);
+ argc = parse_options(argc, argv, prefix, checkout_worker_options,
+ checkout_worker_usage, 0);
+ if (argc > 0)
+ usage_with_options(checkout_worker_usage, checkout_worker_options);
+
+ if (state.base_dir)
+ state.base_dir_len = strlen(state.base_dir);
+
+ /*
+ * Setting this on a worker won't actually update the index. We just
+ * need to tell the checkout machinery to lstat() the written entries,
+ * so that we can send this data back to the main process.
+ */
+ state.refresh_cache = 1;
+
+ worker_loop(&state);
+ return 0;
+}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index c0bf4ac1b2..e21620d964 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -12,6 +12,7 @@
#include "cache-tree.h"
#include "parse-options.h"
#include "entry.h"
+#include "parallel-checkout.h"
#define CHECKOUT_ALL 4
static int nul_term_line;
@@ -115,11 +116,13 @@ static int checkout_file(const char *name, const char *prefix)
return -1;
}
-static void checkout_all(const char *prefix, int prefix_length)
+static int checkout_all(const char *prefix, int prefix_length)
{
int i, errs = 0;
struct cache_entry *last_ce = NULL;
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (i = 0; i < active_nr ; i++) {
struct cache_entry *ce = active_cache[i];
if (ce_stage(ce) != checkout_stage
@@ -142,11 +145,7 @@ static void checkout_all(const char *prefix, int prefix_length)
}
if (last_ce && to_tempfile)
write_tempfile_record(last_ce->name, prefix);
- if (errs)
- /* we have already done our error reporting.
- * exit with the same code as die().
- */
- exit(128);
+ return !!errs;
}
static const char * const builtin_checkout_index_usage[] = {
@@ -182,6 +181,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
int force = 0, quiet = 0, not_new = 0;
int index_opt = 0;
int err = 0;
+ int pc_workers, pc_threshold;
struct option builtin_checkout_index_options[] = {
OPT_BOOL('a', "all", &all,
N_("check out all files in the index")),
@@ -236,6 +236,10 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
}
+ get_parallel_checkout_configs(&pc_workers, &pc_threshold);
+ if (pc_workers > 1)
+ init_parallel_checkout();
+
/* Check out named files first */
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
@@ -275,12 +279,16 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
strbuf_release(&buf);
}
+ if (all)
+ err |= checkout_all(prefix, prefix_length);
+
+ if (pc_workers > 1)
+ err |= run_parallel_checkout(&state, pc_workers, pc_threshold,
+ NULL, NULL);
+
if (err)
return 1;
- if (all)
- checkout_all(prefix, prefix_length);
-
if (is_lock_file_locked(&lock_file) &&
write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 4c696ef480..b23bc149d1 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -27,6 +27,7 @@
#include "wt-status.h"
#include "xdiff-interface.h"
#include "entry.h"
+#include "parallel-checkout.h"
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
@@ -106,8 +107,8 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
int changed)
{
return run_hook_le(NULL, "post-checkout",
- oid_to_hex(old_commit ? &old_commit->object.oid : &null_oid),
- oid_to_hex(new_commit ? &new_commit->object.oid : &null_oid),
+ oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
+ oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
changed ? "1" : "0", NULL);
/* "new_commit" can be NULL when checking out from the index before
a commit exists. */
@@ -230,7 +231,8 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
return error(_("path '%s' does not have their version"), ce->name);
}
-static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts)
+static int checkout_merged(int pos, const struct checkout *state,
+ int *nr_checkouts, struct mem_pool *ce_mem_pool)
{
struct cache_entry *ce = active_cache[pos];
const char *path = ce->name;
@@ -291,11 +293,10 @@ static int checkout_merged(int pos, const struct checkout *state, int *nr_checko
if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
- ce = make_transient_cache_entry(mode, &oid, path, 2);
+ ce = make_transient_cache_entry(mode, &oid, path, 2, ce_mem_pool);
if (!ce)
die(_("make_cache_entry failed for path '%s'"), path);
status = checkout_entry(ce, state, NULL, nr_checkouts);
- discard_cache_entry(ce);
return status;
}
@@ -359,16 +360,24 @@ static int checkout_worktree(const struct checkout_opts *opts,
int nr_checkouts = 0, nr_unmerged = 0;
int errs = 0;
int pos;
+ int pc_workers, pc_threshold;
+ struct mem_pool ce_mem_pool;
state.force = 1;
state.refresh_cache = 1;
state.istate = &the_index;
+ mem_pool_init(&ce_mem_pool, 0);
+ get_parallel_checkout_configs(&pc_workers, &pc_threshold);
init_checkout_metadata(&state.meta, info->refname,
info->commit ? &info->commit->object.oid : &info->oid,
NULL);
enable_delayed_checkout(&state);
+
+ if (pc_workers > 1)
+ init_parallel_checkout();
+
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
if (ce->ce_flags & CE_MATCHED) {
@@ -384,13 +393,18 @@ static int checkout_worktree(const struct checkout_opts *opts,
&nr_checkouts, opts->overlay_mode);
else if (opts->merge)
errs |= checkout_merged(pos, &state,
- &nr_unmerged);
+ &nr_unmerged,
+ &ce_mem_pool);
pos = skip_same_name(ce, pos) - 1;
}
}
+ if (pc_workers > 1)
+ errs |= run_parallel_checkout(&state, pc_workers, pc_threshold,
+ NULL, NULL);
+ mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
remove_marked_cache_entries(&the_index, 1);
remove_scheduled_dirs();
- errs |= finish_delayed_checkout(&state, &nr_checkouts);
+ errs |= finish_delayed_checkout(&state, &nr_checkouts, opts->show_progress);
if (opts->count_checkout_paths) {
if (nr_unmerged)
@@ -602,6 +616,7 @@ static void show_local_changes(struct object *head,
diff_setup_done(&rev.diffopt);
add_pending_object(&rev, head, NULL);
run_diff_index(&rev, 0);
+ object_array_clear(&rev.pending);
}
static void describe_detached_head(const char *msg, struct commit *commit)
@@ -638,7 +653,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
opts.src_index = &the_index;
opts.dst_index = &the_index;
init_checkout_metadata(&opts.meta, info->refname,
- info->commit ? &info->commit->object.oid : &null_oid,
+ info->commit ? &info->commit->object.oid : null_oid(),
NULL);
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
@@ -1573,6 +1588,9 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
git_config(git_checkout_config, opts);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
opts->track = BRANCH_TRACK_UNSPECIFIED;
if (!opts->accept_pathspec && !opts->accept_ref)
diff --git a/builtin/clean.c b/builtin/clean.c
index 995053b791..98a2860409 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -189,10 +189,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
strbuf_complete(path, '/');
len = path->len;
- while ((e = readdir(dir)) != NULL) {
+ while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) {
struct stat st;
- if (is_dot_or_dotdot(e->d_name))
- continue;
strbuf_setlen(path, len);
strbuf_addstr(path, e->d_name);
@@ -643,7 +641,7 @@ static int clean_cmd(void)
static int filter_by_patterns_cmd(void)
{
- struct dir_struct dir;
+ struct dir_struct dir = DIR_INIT;
struct strbuf confirm = STRBUF_INIT;
struct strbuf **ignore_list;
struct string_list_item *item;
@@ -667,7 +665,6 @@ static int filter_by_patterns_cmd(void)
if (!confirm.len)
break;
- dir_init(&dir);
pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
ignore_list = strbuf_split_max(&confirm, ' ', 0);
@@ -892,7 +889,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf abs_path = STRBUF_INIT;
- struct dir_struct dir;
+ struct dir_struct dir = DIR_INIT;
struct pathspec pathspec;
struct strbuf buf = STRBUF_INIT;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
@@ -923,7 +920,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
0);
- dir_init(&dir);
if (!interactive && !dry_run && !force) {
if (config_set)
die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
@@ -1003,7 +999,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
- int matches = 0;
struct stat st;
const char *rel;
@@ -1013,8 +1008,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (lstat(ent->name, &st))
die_errno("Cannot lstat '%s'", ent->name);
- if (S_ISDIR(st.st_mode) && !remove_directories &&
- matches != MATCHED_EXACTLY)
+ if (S_ISDIR(st.st_mode) && !remove_directories)
continue;
rel = relative_path(ent->name, prefix, &buf);
diff --git a/builtin/clone.c b/builtin/clone.c
index f6b0c48bed..66fe66679c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -820,7 +820,7 @@ static int checkout(int submodule_progress)
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- err |= run_hook_le(NULL, "post-checkout", oid_to_hex(&null_oid),
+ err |= run_hook_le(NULL, "post-checkout", oid_to_hex(null_oid()),
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
@@ -1320,9 +1320,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (!is_local && !complete_refs_before_fetch) {
- err = transport_fetch_refs(transport, mapped_refs);
- if (err)
- goto cleanup;
+ if (transport_fetch_refs(transport, mapped_refs))
+ die(_("remote transport reported error"));
}
remote_head = find_ref_by_name(refs, "HEAD");
@@ -1380,9 +1379,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (is_local)
clone_local(path, git_dir);
else if (refs && complete_refs_before_fetch) {
- err = transport_fetch_refs(transport, mapped_refs);
- if (err)
- goto cleanup;
+ if (transport_fetch_refs(transport, mapped_refs))
+ die(_("remote transport reported error"));
}
update_remote_refs(refs, mapped_refs, remote_head_points_at,
@@ -1410,7 +1408,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
junk_mode = JUNK_LEAVE_REPO;
err = checkout(submodule_progress);
-cleanup:
free(remote_name);
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
diff --git a/builtin/column.c b/builtin/column.c
index 40d4b3bee2..158fdf53d9 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -29,7 +29,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)
OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")),
OPT_INTEGER(0, "width", &copts.width, N_("maximum width")),
OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("padding space on left border")),
- OPT_INTEGER(0, "nl", &copts.nl, N_("padding space on right border")),
+ OPT_STRING(0, "nl", &copts.nl, N_("string"), N_("padding space on right border")),
OPT_INTEGER(0, "padding", &copts.padding, N_("padding space between columns")),
OPT_END()
};
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index cd86315221..21fc6e934b 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -9,26 +9,29 @@
#include "progress.h"
#include "tag.h"
-static char const * const builtin_commit_graph_usage[] = {
- N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
- N_("git commit-graph write [--object-dir <objdir>] [--append] "
- "[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
- "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
- "<split options>"),
+#define BUILTIN_COMMIT_GRAPH_VERIFY_USAGE \
+ N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]")
+
+#define BUILTIN_COMMIT_GRAPH_WRITE_USAGE \
+ N_("git commit-graph write [--object-dir <objdir>] [--append] " \
+ "[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] " \
+ "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] " \
+ "<split options>")
+
+static const char * builtin_commit_graph_verify_usage[] = {
+ BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
NULL
};
-static const char * const builtin_commit_graph_verify_usage[] = {
- N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
+static const char * builtin_commit_graph_write_usage[] = {
+ BUILTIN_COMMIT_GRAPH_WRITE_USAGE,
NULL
};
-static const char * const builtin_commit_graph_write_usage[] = {
- N_("git commit-graph write [--object-dir <objdir>] [--append] "
- "[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
- "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
- "<split options>"),
- NULL
+static char const * const builtin_commit_graph_usage[] = {
+ BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
+ BUILTIN_COMMIT_GRAPH_WRITE_USAGE,
+ NULL,
};
static struct opts_commit_graph {
@@ -43,6 +46,20 @@ static struct opts_commit_graph {
int enable_changed_paths;
} opts;
+static struct option common_opts[] = {
+ OPT_STRING(0, "object-dir", &opts.obj_dir,
+ N_("dir"),
+ N_("the object directory to store the graph")),
+ OPT_BOOL(0, "progress", &opts.progress,
+ N_("force progress reporting")),
+ OPT_END()
+};
+
+static struct option *add_common_options(struct option *to)
+{
+ return parse_options_concat(common_opts, to);
+}
+
static struct object_directory *find_odb(struct repository *r,
const char *obj_dir)
{
@@ -76,21 +93,20 @@ static int graph_verify(int argc, const char **argv)
int flags = 0;
static struct option builtin_commit_graph_verify_options[] = {
- OPT_STRING(0, "object-dir", &opts.obj_dir,
- N_("dir"),
- N_("the object directory to store the graph")),
OPT_BOOL(0, "shallow", &opts.shallow,
N_("if the commit-graph is split, only verify the tip file")),
- OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
OPT_END(),
};
+ struct option *options = add_common_options(builtin_commit_graph_verify_options);
trace2_cmd_mode("verify");
opts.progress = isatty(2);
argc = parse_options(argc, argv, NULL,
- builtin_commit_graph_verify_options,
+ options,
builtin_commit_graph_verify_usage, 0);
+ if (argc)
+ usage_with_options(builtin_commit_graph_verify_usage, options);
if (!opts.obj_dir)
opts.obj_dir = get_object_directory();
@@ -106,6 +122,7 @@ static int graph_verify(int argc, const char **argv)
die_errno(_("Could not open commit-graph '%s'"), graph_name);
FREE_AND_NULL(graph_name);
+ FREE_AND_NULL(options);
if (open_ok)
graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
@@ -206,9 +223,6 @@ static int graph_write(int argc, const char **argv)
struct progress *progress = NULL;
static struct option builtin_commit_graph_write_options[] = {
- OPT_STRING(0, "object-dir", &opts.obj_dir,
- N_("dir"),
- N_("the object directory to store the graph")),
OPT_BOOL(0, "reachable", &opts.reachable,
N_("start walk at all refs")),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
@@ -219,7 +233,6 @@ static int graph_write(int argc, const char **argv)
N_("include all commits already in the commit-graph file")),
OPT_BOOL(0, "changed-paths", &opts.enable_changed_paths,
N_("enable computation for changed paths")),
- OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
OPT_CALLBACK_F(0, "split", &write_opts.split_flags, NULL,
N_("allow writing an incremental commit-graph file"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
@@ -235,6 +248,7 @@ static int graph_write(int argc, const char **argv)
0, write_option_max_new_filters),
OPT_END(),
};
+ struct option *options = add_common_options(builtin_commit_graph_write_options);
opts.progress = isatty(2);
opts.enable_changed_paths = -1;
@@ -248,8 +262,10 @@ static int graph_write(int argc, const char **argv)
git_config(git_commit_graph_write_config, &opts);
argc = parse_options(argc, argv, NULL,
- builtin_commit_graph_write_options,
+ options,
builtin_commit_graph_write_usage, 0);
+ if (argc)
+ usage_with_options(builtin_commit_graph_write_usage, options);
if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
@@ -304,6 +320,7 @@ static int graph_write(int argc, const char **argv)
result = 1;
cleanup:
+ FREE_AND_NULL(options);
string_list_clear(&pack_indexes, 0);
strbuf_release(&buf);
return result;
@@ -311,32 +328,25 @@ cleanup:
int cmd_commit_graph(int argc, const char **argv, const char *prefix)
{
- static struct option builtin_commit_graph_options[] = {
- OPT_STRING(0, "object-dir", &opts.obj_dir,
- N_("dir"),
- N_("the object directory to store the graph")),
- OPT_END(),
- };
-
- if (argc == 2 && !strcmp(argv[1], "-h"))
- usage_with_options(builtin_commit_graph_usage,
- builtin_commit_graph_options);
+ struct option *builtin_commit_graph_options = common_opts;
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix,
builtin_commit_graph_options,
builtin_commit_graph_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
+ if (!argc)
+ goto usage;
save_commit_buffer = 0;
- if (argc > 0) {
- if (!strcmp(argv[0], "verify"))
- return graph_verify(argc, argv);
- if (!strcmp(argv[0], "write"))
- return graph_write(argc, argv);
- }
+ if (!strcmp(argv[0], "verify"))
+ return graph_verify(argc, argv);
+ else if (argc && !strcmp(argv[0], "write"))
+ return graph_write(argc, argv);
+ error(_("unrecognized subcommand: %s"), argv[0]);
+usage:
usage_with_options(builtin_commit_graph_usage,
builtin_commit_graph_options);
}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 1031b9a491..63ea322933 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -88,9 +88,7 @@ static int parse_file_arg_callback(const struct option *opt,
if (!strcmp(arg, "-"))
fd = 0;
else {
- fd = open(arg, O_RDONLY);
- if (fd < 0)
- die_errno(_("git commit-tree: failed to open '%s'"), arg);
+ fd = xopen(arg, O_RDONLY);
}
if (strbuf_read(buf, fd, 0) < 0)
die_errno(_("git commit-tree: failed to read '%s'"), arg);
diff --git a/builtin/commit.c b/builtin/commit.c
index 55d50a8891..7c9b1e7be3 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -261,6 +261,8 @@ static int list_paths(struct string_list *list, const char *with_tree,
free(max_prefix);
}
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
struct string_list_item *item;
@@ -887,7 +889,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
int ident_shown = 0;
int saved_color_setting;
struct ident_split ci, ai;
-
+ const char *hint_cleanup_all = allow_empty_message ?
+ _("Please enter the commit message for your changes."
+ " Lines starting\nwith '%c' will be ignored.\n") :
+ _("Please enter the commit message for your changes."
+ " Lines starting\nwith '%c' will be ignored, and an empty"
+ " message aborts the commit.\n");
+ const char *hint_cleanup_space = allow_empty_message ?
+ _("Please enter the commit message for your changes."
+ " Lines starting\n"
+ "with '%c' will be kept; you may remove them"
+ " yourself if you want to.\n") :
+ _("Please enter the commit message for your changes."
+ " Lines starting\n"
+ "with '%c' will be kept; you may remove them"
+ " yourself if you want to.\n"
+ "An empty message aborts the commit.\n");
if (whence != FROM_COMMIT) {
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
!merge_contains_scissors)
@@ -909,20 +926,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
fprintf(s->fp, "\n");
if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
- status_printf(s, GIT_COLOR_NORMAL,
- _("Please enter the commit message for your changes."
- " Lines starting\nwith '%c' will be ignored, and an empty"
- " message aborts the commit.\n"), comment_line_char);
+ status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_all, comment_line_char);
else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
if (whence == FROM_COMMIT && !merge_contains_scissors)
wt_status_add_cut_line(s->fp);
} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
- status_printf(s, GIT_COLOR_NORMAL,
- _("Please enter the commit message for your changes."
- " Lines starting\n"
- "with '%c' will be kept; you may remove them"
- " yourself if you want to.\n"
- "An empty message aborts the commit.\n"), comment_line_char);
+ status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_space, comment_line_char);
/*
* These should never fail because they come from our own
@@ -976,6 +985,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (get_oid(parent, &oid)) {
int i, ita_nr = 0;
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++)
if (ce_intent_to_add(active_cache[i]))
ita_nr++;
@@ -1242,8 +1253,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (logfile || have_option_m || use_message)
use_editor = 0;
- if (0 <= edit_flag)
- use_editor = edit_flag;
/* Sanity check options */
if (amend && !current_head)
@@ -1333,6 +1342,9 @@ static int parse_and_validate_options(int argc, const char *argv[],
}
}
+ if (0 <= edit_flag)
+ use_editor = edit_flag;
+
cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
handle_untracked_files_arg(s);
@@ -1506,6 +1518,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_status_usage, builtin_status_options);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
status_init_config(&s, git_status_config);
argc = parse_options(argc, argv, prefix,
builtin_status_options,
@@ -1675,6 +1690,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_commit_usage, builtin_commit_options);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
status_init_config(&s, git_commit_config);
s.commit_template = 1;
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
diff --git a/builtin/config.c b/builtin/config.c
index f71fa39b38..865fddd6ce 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -671,9 +671,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
if (use_global_config) {
- char *user_config = expand_user_path("~/.gitconfig", 0);
- char *xdg_config = xdg_config_home("config");
+ char *user_config, *xdg_config;
+ git_global_config(&user_config, &xdg_config);
if (!user_config)
/*
* It is unknown if HOME/.gitconfig exists, so
@@ -695,7 +695,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
}
else if (use_system_config) {
- given_config_source.file = git_etc_gitconfig();
+ given_config_source.file = git_system_config();
given_config_source.scope = CONFIG_SCOPE_SYSTEM;
} else if (use_local_config) {
given_config_source.file = git_pathdup("config");
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 76a6ba3722..e8a7415747 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -90,7 +90,7 @@ static char *get_socket_path(void)
{
struct stat sb;
char *old_dir, *socket;
- old_dir = expand_user_path("~/.git-credential-cache", 0);
+ old_dir = interpolate_path("~/.git-credential-cache", 0);
if (old_dir && !stat(old_dir, &sb) && S_ISDIR(sb.st_mode))
socket = xstrfmt("%s/socket", old_dir);
else
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index ae3c1ba75f..62a4f3c265 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -173,7 +173,7 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix)
if (file) {
string_list_append(&fns, file);
} else {
- if ((file = expand_user_path("~/.git-credentials", 0)))
+ if ((file = interpolate_path("~/.git-credentials", 0)))
string_list_append_nodup(&fns, file);
file = xdg_config_home("credentials");
if (file)
diff --git a/builtin/describe.c b/builtin/describe.c
index 40482d8e9f..e912ba50d7 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -502,7 +502,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)
{
struct rev_info revs;
struct strvec args = STRVEC_INIT;
- struct process_commit_data pcd = { null_oid, oid, dst, &revs};
+ struct process_commit_data pcd = { *null_oid(), oid, dst, &revs};
strvec_pushl(&args, "internal: The first arg is not parsed",
"--objects", "--in-commit-order", "--reverse", "HEAD",
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 176fe7ff2b..cf09559e42 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -2,6 +2,7 @@
#include "cache.h"
#include "config.h"
#include "diff.h"
+#include "diff-merges.h"
#include "commit.h"
#include "revision.h"
#include "builtin.h"
@@ -27,6 +28,12 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
rev.abbrev = 0;
prefix = precompose_argv_prefix(argc, argv, prefix);
+ /*
+ * We need no diff for merges options, and we need to avoid conflict
+ * with our own meaning of "-m".
+ */
+ diff_merges_suppress_options_parsing();
+
argc = setup_revisions(argc, argv, &rev, NULL);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -35,6 +42,8 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
option |= DIFF_INDEX_CACHED;
else if (!strcmp(arg, "--merge-base"))
option |= DIFF_INDEX_MERGE_BASE;
+ else if (!strcmp(arg, "-m"))
+ rev.match_missing = 1;
else
usage(diff_cache_usage);
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 617b9a4101..dd8ce688ba 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -26,8 +26,8 @@
static const char builtin_diff_usage[] =
"git diff [<options>] [<commit>] [--] [<path>...]\n"
-" or: git diff [<options>] --cached [<commit>] [--] [<path>...]\n"
-" or: git diff [<options>] <commit> [--merge-base] [<commit>...] <commit> [--] [<path>...]\n"
+" or: git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]\n"
+" or: git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]\n"
" or: git diff [<options>] <commit>...<commit>] [--] [<path>...]\n"
" or: git diff [<options>] <blob> <blob>]\n"
" or: git diff [<options>] --no-index [--] <path> <path>]\n"
@@ -98,7 +98,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
stuff_change(&revs->diffopt,
blob[0]->mode, canon_mode(st.st_mode),
- &blob[0]->item->oid, &null_oid,
+ &blob[0]->item->oid, null_oid(),
1, 0,
blob[0]->path ? blob[0]->path : path,
path);
diff --git a/builtin/difftool.c b/builtin/difftool.c
index ef25729d49..6a9242a803 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -323,7 +323,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,
struct cache_entry *ce;
int ret;
- ce = make_transient_cache_entry(mode, oid, path, 0);
+ ce = make_transient_cache_entry(mode, oid, path, 0, NULL);
ret = checkout_entry(ce, state, NULL, NULL);
discard_cache_entry(ce);
@@ -585,6 +585,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1);
rc = run_command_v_opt(helper_argv, flags);
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&wtindex);
+
/*
* If the diff includes working copy files and those
* files were modified during the diff, then the changes
@@ -672,7 +675,7 @@ static int run_file_diff(int prompt, const char *prefix,
"GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
NULL
};
- int ret = 0, i;
+ int i;
if (prompt > 0)
env[2] = "GIT_DIFFTOOL_PROMPT=true";
@@ -683,8 +686,7 @@ static int run_file_diff(int prompt, const char *prefix,
strvec_push(&args, "diff");
for (i = 0; i < argc; i++)
strvec_push(&args, argv[i]);
- ret = run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
- exit(ret);
+ return run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
}
int cmd_difftool(int argc, const char **argv, const char *prefix)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 85a76e0ef8..3c20f164f0 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -870,7 +870,7 @@ static void handle_tag(const char *name, struct tag *tag)
p = rewrite_commit((struct commit *)tagged);
if (!p) {
printf("reset %s\nfrom %s\n\n",
- name, oid_to_hex(&null_oid));
+ name, oid_to_hex(null_oid()));
free(buf);
return;
}
@@ -884,7 +884,7 @@ static void handle_tag(const char *name, struct tag *tag)
if (tagged->type == OBJ_TAG) {
printf("reset %s\nfrom %s\n\n",
- name, oid_to_hex(&null_oid));
+ name, oid_to_hex(null_oid()));
}
skip_prefix(name, "refs/tags/", &name);
printf("tag %s\n", name);
@@ -1016,7 +1016,7 @@ static void handle_tags_and_duplicates(struct string_list *extras)
* it.
*/
printf("reset %s\nfrom %s\n\n",
- name, oid_to_hex(&null_oid));
+ name, oid_to_hex(null_oid()));
continue;
}
@@ -1035,7 +1035,7 @@ static void handle_tags_and_duplicates(struct string_list *extras)
if (!reference_excluded_commits) {
/* delete the ref */
printf("reset %s\nfrom %s\n\n",
- name, oid_to_hex(&null_oid));
+ name, oid_to_hex(null_oid()));
continue;
}
/* set ref to commit using oid, not mark */
@@ -1146,7 +1146,7 @@ static void handle_deletes(void)
continue;
printf("reset %s\nfrom %s\n\n",
- refspec->dst, oid_to_hex(&null_oid));
+ refspec->dst, oid_to_hex(null_oid()));
}
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 3afa81cf9a..20406f6775 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -940,7 +940,7 @@ static int store_object(
the_hash_algo->init_fn(&c);
the_hash_algo->update_fn(&c, hdr, hdrlen);
the_hash_algo->update_fn(&c, dat->buf, dat->len);
- the_hash_algo->final_fn(oid.hash, &c);
+ the_hash_algo->final_oid_fn(&oid, &c);
if (oidout)
oidcpy(oidout, &oid);
@@ -1136,7 +1136,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
}
}
git_deflate_end(&s);
- the_hash_algo->final_fn(oid.hash, &c);
+ the_hash_algo->final_oid_fn(&oid, &c);
if (oidout)
oidcpy(oidout, &oid);
@@ -1276,8 +1276,8 @@ static void load_tree(struct tree_entry *root)
e->versions[0].mode = e->versions[1].mode;
e->name = to_atom(c, strlen(c));
c += e->name->str_len + 1;
- hashcpy(e->versions[0].oid.hash, (unsigned char *)c);
- hashcpy(e->versions[1].oid.hash, (unsigned char *)c);
+ oidread(&e->versions[0].oid, (unsigned char *)c);
+ oidread(&e->versions[1].oid, (unsigned char *)c);
c += the_hash_algo->rawsz;
}
free(buf);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 0b90de87c7..fc7b6bb84e 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -48,6 +48,7 @@ enum {
static int fetch_prune_config = -1; /* unspecified */
static int fetch_show_forced_updates = 1;
static uint64_t forced_updates_ms = 0;
+static int prefetch = 0;
static int prune = -1; /* unspecified */
#define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
@@ -82,6 +83,7 @@ static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static int fetch_write_commit_graph = -1;
static int stdin_refspecs = 0;
+static int negotiate_only;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@@ -158,6 +160,8 @@ static struct option builtin_fetch_options[] = {
N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
OPT_INTEGER('j', "jobs", &max_jobs,
N_("number of submodules fetched in parallel")),
+ OPT_BOOL(0, "prefetch", &prefetch,
+ N_("modify the refspec to place all refs within refs/prefetch/")),
OPT_BOOL('p', "prune", &prune,
N_("prune remote-tracking branches no longer on remote")),
OPT_BOOL('P', "prune-tags", &prune_tags,
@@ -202,6 +206,8 @@ static struct option builtin_fetch_options[] = {
TRANSPORT_FAMILY_IPV6),
OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
N_("report that we have only objects reachable from this object")),
+ OPT_BOOL(0, "negotiate-only", &negotiate_only,
+ N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
N_("run 'maintenance --auto' after fetching")),
@@ -436,6 +442,56 @@ static void find_non_local_tags(const struct ref *refs,
oidset_clear(&fetch_oids);
}
+static void filter_prefetch_refspec(struct refspec *rs)
+{
+ int i;
+
+ if (!prefetch)
+ return;
+
+ for (i = 0; i < rs->nr; i++) {
+ struct strbuf new_dst = STRBUF_INIT;
+ char *old_dst;
+ const char *sub = NULL;
+
+ if (rs->items[i].negative)
+ continue;
+ if (!rs->items[i].dst ||
+ (rs->items[i].src &&
+ !strncmp(rs->items[i].src, "refs/tags/", 10))) {
+ int j;
+
+ free(rs->items[i].src);
+ free(rs->items[i].dst);
+
+ for (j = i + 1; j < rs->nr; j++) {
+ rs->items[j - 1] = rs->items[j];
+ rs->raw[j - 1] = rs->raw[j];
+ }
+ rs->nr--;
+ i--;
+ continue;
+ }
+
+ old_dst = rs->items[i].dst;
+ strbuf_addstr(&new_dst, "refs/prefetch/");
+
+ /*
+ * If old_dst starts with "refs/", then place
+ * sub after that prefix. Otherwise, start at
+ * the beginning of the string.
+ */
+ if (!skip_prefix(old_dst, "refs/", &sub))
+ sub = old_dst;
+ strbuf_addstr(&new_dst, sub);
+
+ rs->items[i].dst = strbuf_detach(&new_dst, NULL);
+ rs->items[i].force = 1;
+
+ free(old_dst);
+ }
+}
+
static struct ref *get_ref_map(struct remote *remote,
const struct ref *remote_refs,
struct refspec *rs,
@@ -452,6 +508,10 @@ static struct ref *get_ref_map(struct remote *remote,
struct hashmap existing_refs;
int existing_refs_populated = 0;
+ filter_prefetch_refspec(rs);
+ if (remote)
+ filter_prefetch_refspec(&remote->fetch);
+
if (rs->nr) {
struct refspec *fetch_refspec;
@@ -520,7 +580,7 @@ static struct ref *get_ref_map(struct remote *remote,
if (has_merge &&
!strcmp(branch->remote_name, remote->name))
add_merge_config(&ref_map, remote_refs, branch, &tail);
- } else {
+ } else if (!prefetch) {
ref_map = get_remote_ref(remote_refs, "HEAD");
if (!ref_map)
die(_("Couldn't find remote ref HEAD"));
@@ -652,7 +712,7 @@ static void adjust_refcol_width(const struct ref *ref)
int max, rlen, llen, len;
/* uptodate lines are only shown on high verbosity level */
- if (!verbosity && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
+ if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
return;
max = term_columns();
@@ -688,6 +748,9 @@ static void prepare_format_display(struct ref *ref_map)
struct ref *rm;
const char *format = "full";
+ if (verbosity < 0)
+ return;
+
git_config_get_string_tmp("fetch.output", &format);
if (!strcasecmp(format, "full"))
compact_format = 0;
@@ -767,7 +830,12 @@ static void format_display(struct strbuf *display, char code,
const char *remote, const char *local,
int summary_width)
{
- int width = (summary_width + strlen(summary) - gettext_width(summary));
+ int width;
+
+ if (verbosity < 0)
+ return;
+
+ width = (summary_width + strlen(summary) - gettext_width(summary));
strbuf_addf(display, "%c %-*s ", code, width, summary);
if (!compact_format)
@@ -1066,7 +1134,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
if (want_status == FETCH_HEAD_MERGE)
- warning(_("reject %s because shallow roots are not allowed to be updated"),
+ warning(_("rejected %s because shallow roots are not allowed to be updated"),
rm->peer_ref ? rm->peer_ref->name : rm->name);
continue;
}
@@ -1142,13 +1210,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
"FETCH_HEAD", summary_width);
}
if (note.len) {
- if (verbosity >= 0 && !shown_url) {
+ if (!shown_url) {
fprintf(stderr, _("From %.*s\n"),
url_len, url);
shown_url = 1;
}
- if (verbosity >= 0)
- fprintf(stderr, " %s\n", note.buf);
+ fprintf(stderr, " %s\n", note.buf);
}
}
}
@@ -1368,7 +1435,9 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
if (!has_glob_specials(s)) {
struct object_id oid;
if (get_oid(s, &oid))
- die("%s is not a valid object", s);
+ die(_("%s is not a valid object"), s);
+ if (!has_object(the_repository, &oid, 0))
+ die(_("the object %s does not exist"), s);
oid_array_append(oids, &oid);
continue;
}
@@ -1930,6 +1999,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
fetch_config_from_gitmodules(sfjc, rs);
}
+ if (negotiate_only && !negotiation_tip.nr)
+ die(_("--negotiate-only needs one or more --negotiate-tip=*"));
+
if (deepen_relative) {
if (deepen_relative < 0)
die(_("Negative depth in --deepen is not supported"));
@@ -1986,7 +2058,29 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
}
- if (remote) {
+ if (negotiate_only) {
+ struct oidset acked_commits = OIDSET_INIT;
+ struct oidset_iter iter;
+ const struct object_id *oid;
+
+ if (!remote)
+ die(_("must supply remote when using --negotiate-only"));
+ gtransport = prepare_transport(remote, 1);
+ if (gtransport->smart_options) {
+ gtransport->smart_options->acked_commits = &acked_commits;
+ } else {
+ warning(_("Protocol does not support --negotiate-only, exiting."));
+ return 1;
+ }
+ if (server_options.nr)
+ gtransport->server_options = &server_options;
+ result = transport_fetch_refs(gtransport, NULL);
+
+ oidset_iter_init(&acked_commits, &iter);
+ while ((oid = oidset_iter_next(&iter)))
+ printf("%s\n", oid_to_hex(oid));
+ oidset_clear(&acked_commits);
+ } else if (remote) {
if (filter_options.choice || has_promisor_remote())
fetch_one_setup_partial(remote);
result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index cb9c81a046..89cb6307d4 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -22,6 +22,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
struct ref_array array;
struct ref_filter filter;
struct ref_format format = REF_FORMAT_INIT;
+ struct strbuf output = STRBUF_INIT;
+ struct strbuf err = STRBUF_INIT;
struct option opts[] = {
OPT_BIT('s', "shell", &format.quote_style,
@@ -80,8 +82,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
if (!maxcount || array.nr < maxcount)
maxcount = array.nr;
- for (i = 0; i < maxcount; i++)
- show_ref_array_item(array.items[i], &format);
+ for (i = 0; i < maxcount; i++) {
+ strbuf_reset(&err);
+ strbuf_reset(&output);
+ if (format_ref_array_item(array.items[i], &format, &output, &err))
+ die("%s", err.buf);
+ fwrite(output.buf, 1, output.len, stdout);
+ putchar('\n');
+ }
+
+ strbuf_release(&err);
+ strbuf_release(&output);
ref_array_clear(&array);
+ free_commit_list(filter.with_commit);
+ free_commit_list(filter.no_commit);
+ UNLEAK(sorting);
return 0;
}
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index 52be64a437..fd86e5a861 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -10,18 +10,16 @@ static const char * const for_each_repo_usage[] = {
NULL
};
-static int run_command_on_repo(const char *path,
- void *cbdata)
+static int run_command_on_repo(const char *path, int argc, const char ** argv)
{
int i;
struct child_process child = CHILD_PROCESS_INIT;
- struct strvec *args = (struct strvec *)cbdata;
child.git_cmd = 1;
strvec_pushl(&child.args, "-C", path, NULL);
- for (i = 0; i < args->nr; i++)
- strvec_push(&child.args, args->v[i]);
+ for (i = 0; i < argc; i++)
+ strvec_push(&child.args, argv[i]);
return run_command(&child);
}
@@ -31,7 +29,6 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
static const char *config_key = NULL;
int i, result = 0;
const struct string_list *values;
- struct strvec args = STRVEC_INIT;
const struct option options[] = {
OPT_STRING(0, "config", &config_key, N_("config"),
@@ -45,9 +42,6 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
if (!config_key)
die(_("missing --config=<config>"));
- for (i = 0; i < argc; i++)
- strvec_push(&args, argv[i]);
-
values = repo_config_get_value_multi(the_repository,
config_key);
@@ -59,7 +53,7 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
return 0;
for (i = 0; !result && i < values->nr; i++)
- result = run_command_on_repo(values->items[i].string, &args);
+ result = run_command_on_repo(values->items[i].string, argc, argv);
return result;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 70ff95837a..b42b6fe21f 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -109,7 +109,8 @@ static int fsck_error_func(struct fsck_options *o,
static struct object_array pending;
-static int mark_object(struct object *obj, int type, void *data, struct fsck_options *options)
+static int mark_object(struct object *obj, enum object_type type,
+ void *data, struct fsck_options *options)
{
struct object *parent = data;
@@ -725,7 +726,7 @@ static int fsck_cache_tree(struct cache_tree *it)
static void mark_object_for_connectivity(const struct object_id *oid)
{
- struct object *obj = lookup_unknown_object(oid);
+ struct object *obj = lookup_unknown_object(the_repository, oid);
obj->flags |= HAS_OBJ;
}
@@ -881,6 +882,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
verify_index_checksum = 1;
verify_ce_order = 1;
read_cache();
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
unsigned int mode;
struct blob *blob;
diff --git a/builtin/gc.c b/builtin/gc.c
index ef7226d7bc..9a48eb535f 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -873,55 +873,40 @@ static int maintenance_task_commit_graph(struct maintenance_run_opts *opts)
return 0;
}
-static int fetch_remote(const char *remote, struct maintenance_run_opts *opts)
+static int fetch_remote(struct remote *remote, void *cbdata)
{
+ struct maintenance_run_opts *opts = cbdata;
struct child_process child = CHILD_PROCESS_INIT;
+ if (remote->skip_default_update)
+ return 0;
+
child.git_cmd = 1;
- strvec_pushl(&child.args, "fetch", remote, "--prune", "--no-tags",
+ strvec_pushl(&child.args, "fetch", remote->name,
+ "--prefetch", "--prune", "--no-tags",
"--no-write-fetch-head", "--recurse-submodules=no",
- "--refmap=", NULL);
+ NULL);
if (opts->quiet)
strvec_push(&child.args, "--quiet");
- strvec_pushf(&child.args, "+refs/heads/*:refs/prefetch/%s/*", remote);
-
return !!run_command(&child);
}
-static int append_remote(struct remote *remote, void *cbdata)
-{
- struct string_list *remotes = (struct string_list *)cbdata;
-
- string_list_append(remotes, remote->name);
- return 0;
-}
-
static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
{
- int result = 0;
- struct string_list_item *item;
- struct string_list remotes = STRING_LIST_INIT_DUP;
-
git_config_set_multivar_gently("log.excludedecoration",
"refs/prefetch/",
"refs/prefetch/",
CONFIG_FLAGS_FIXED_VALUE |
CONFIG_FLAGS_MULTI_REPLACE);
- if (for_each_remote(append_remote, &remotes)) {
- error(_("failed to fill remotes"));
- result = 1;
- goto cleanup;
+ if (for_each_remote(fetch_remote, opts)) {
+ error(_("failed to prefetch remotes"));
+ return 1;
}
- for_each_string_list_item(item, &remotes)
- result |= fetch_remote(item->string, opts);
-
-cleanup:
- string_list_clear(&remotes, 0);
- return result;
+ return 0;
}
static int maintenance_task_gc(struct maintenance_run_opts *opts)
@@ -1557,7 +1542,7 @@ static char *launchctl_service_filename(const char *name)
struct strbuf filename = STRBUF_INIT;
strbuf_addf(&filename, "~/Library/LaunchAgents/%s.plist", name);
- expanded = expand_user_path(filename.buf, 1);
+ expanded = interpolate_path(filename.buf, 1);
if (!expanded)
die(_("failed to expand path '%s'"), filename.buf);
@@ -1615,18 +1600,40 @@ static int launchctl_remove_plists(const char *cmd)
launchctl_remove_plist(SCHEDULE_WEEKLY, cmd);
}
+static int launchctl_list_contains_plist(const char *name, const char *cmd)
+{
+ int result;
+ struct child_process child = CHILD_PROCESS_INIT;
+ char *uid = launchctl_get_uid();
+
+ strvec_split(&child.args, cmd);
+ strvec_pushl(&child.args, "list", name, NULL);
+
+ child.no_stderr = 1;
+ child.no_stdout = 1;
+
+ if (start_command(&child))
+ die(_("failed to start launchctl"));
+
+ result = finish_command(&child);
+
+ free(uid);
+
+ /* Returns failure if 'name' doesn't exist. */
+ return !result;
+}
+
static int launchctl_schedule_plist(const char *exec_path, enum schedule_priority schedule, const char *cmd)
{
- FILE *plist;
- int i;
+ int i, fd;
const char *preamble, *repeat;
const char *frequency = get_frequency(schedule);
char *name = launchctl_service_name(frequency);
char *filename = launchctl_service_filename(name);
-
- if (safe_create_leading_directories(filename))
- die(_("failed to create directories for '%s'"), filename);
- plist = xfopen(filename, "w");
+ struct lock_file lk = LOCK_INIT;
+ static unsigned long lock_file_timeout_ms = ULONG_MAX;
+ struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
+ struct stat st;
preamble = "<?xml version=\"1.0\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
@@ -1645,7 +1652,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
"</array>\n"
"<key>StartCalendarInterval</key>\n"
"<array>\n";
- fprintf(plist, preamble, name, exec_path, exec_path, frequency);
+ strbuf_addf(&plist, preamble, name, exec_path, exec_path, frequency);
switch (schedule) {
case SCHEDULE_HOURLY:
@@ -1654,7 +1661,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
"<key>Minute</key><integer>0</integer>\n"
"</dict>\n";
for (i = 1; i <= 23; i++)
- fprintf(plist, repeat, i);
+ strbuf_addf(&plist, repeat, i);
break;
case SCHEDULE_DAILY:
@@ -1664,32 +1671,59 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
"<key>Minute</key><integer>0</integer>\n"
"</dict>\n";
for (i = 1; i <= 6; i++)
- fprintf(plist, repeat, i);
+ strbuf_addf(&plist, repeat, i);
break;
case SCHEDULE_WEEKLY:
- fprintf(plist,
- "<dict>\n"
- "<key>Day</key><integer>0</integer>\n"
- "<key>Hour</key><integer>0</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
- "</dict>\n");
+ strbuf_addstr(&plist,
+ "<dict>\n"
+ "<key>Day</key><integer>0</integer>\n"
+ "<key>Hour</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>0</integer>\n"
+ "</dict>\n");
break;
default:
/* unreachable */
break;
}
- fprintf(plist, "</array>\n</dict>\n</plist>\n");
- fclose(plist);
+ strbuf_addstr(&plist, "</array>\n</dict>\n</plist>\n");
+
+ if (safe_create_leading_directories(filename))
+ die(_("failed to create directories for '%s'"), filename);
+
+ if ((long)lock_file_timeout_ms < 0 &&
+ git_config_get_ulong("gc.launchctlplistlocktimeoutms",
+ &lock_file_timeout_ms))
+ lock_file_timeout_ms = 150;
+
+ fd = hold_lock_file_for_update_timeout(&lk, filename, LOCK_DIE_ON_ERROR,
+ lock_file_timeout_ms);
- /* bootout might fail if not already running, so ignore */
- launchctl_boot_plist(0, filename, cmd);
- if (launchctl_boot_plist(1, filename, cmd))
- die(_("failed to bootstrap service %s"), filename);
+ /*
+ * Does this file already exist? With the intended contents? Is it
+ * registered already? Then it does not need to be re-registered.
+ */
+ if (!stat(filename, &st) && st.st_size == plist.len &&
+ strbuf_read_file(&plist2, filename, plist.len) == plist.len &&
+ !strbuf_cmp(&plist, &plist2) &&
+ launchctl_list_contains_plist(name, cmd))
+ rollback_lock_file(&lk);
+ else {
+ if (write_in_full(fd, plist.buf, plist.len) < 0 ||
+ commit_lock_file(&lk))
+ die_errno(_("could not write '%s'"), filename);
+
+ /* bootout might fail if not already running, so ignore */
+ launchctl_boot_plist(0, filename, cmd);
+ if (launchctl_boot_plist(1, filename, cmd))
+ die(_("failed to bootstrap service %s"), filename);
+ }
free(filename);
free(name);
+ strbuf_release(&plist);
+ strbuf_release(&plist2);
return 0;
}
@@ -1924,6 +1958,7 @@ static int crontab_update_schedule(int run_maintenance, int fd, const char *cmd)
else if (!in_old_region)
fprintf(cron_in, "%s\n", line.buf);
}
+ strbuf_release(&line);
if (run_maintenance) {
struct strbuf line_format = STRBUF_INIT;
@@ -1986,8 +2021,10 @@ static int update_background_schedule(int enable)
cmd = sep + 1;
}
- if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0)
- return error(_("another process is scheduling background maintenance"));
+ if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
+ result = error(_("another process is scheduling background maintenance"));
+ goto cleanup;
+ }
if (!strcmp(scheduler, "launchctl"))
result = launchctl_update_schedule(enable, get_lock_file_fd(&lk), cmd);
@@ -1999,6 +2036,9 @@ static int update_background_schedule(int enable)
die("unknown background scheduler: %s", scheduler);
rollback_lock_file(&lk);
+
+cleanup:
+ free(lock_path);
free(testing);
return result;
}
diff --git a/builtin/grep.c b/builtin/grep.c
index 5de725f904..7d2f8e5adb 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -421,7 +421,7 @@ static int grep_submodule(struct grep_opt *opt,
struct grep_opt subopt;
int hit;
- sub = submodule_from_path(superproject, &null_oid, path);
+ sub = submodule_from_path(superproject, null_oid(), path);
if (!is_submodule_active(superproject, path))
return 0;
@@ -504,6 +504,8 @@ static int grep_cache(struct grep_opt *opt,
if (repo_read_index(repo) < 0)
die(_("index file corrupt"));
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(repo->index);
for (nr = 0; nr < repo->index->cache_nr; nr++) {
const struct cache_entry *ce = repo->index->cache[nr];
@@ -702,10 +704,9 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
int exc_std, int use_index)
{
- struct dir_struct dir;
+ struct dir_struct dir = DIR_INIT;
int i, hit = 0;
- dir_init(&dir);
if (!use_index)
dir.flags |= DIR_NO_GITLINKS;
if (exc_std)
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 640ef4ded5..2e6e2ddd0c 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -53,9 +53,7 @@ static void hash_object(const char *path, const char *type, const char *vpath,
unsigned flags, int literally)
{
int fd;
- fd = open(path, O_RDONLY);
- if (fd < 0)
- die_errno("Cannot open '%s'", path);
+ fd = xopen(path, O_RDONLY);
hash_fd(fd, type, vpath, flags, literally);
}
diff --git a/builtin/help.c b/builtin/help.c
index bb339f0fc8..b7eec06c3d 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -436,10 +436,9 @@ static void exec_viewer(const char *name, const char *page)
warning(_("'%s': unknown man viewer."), name);
}
-static void show_man_page(const char *git_cmd)
+static void show_man_page(const char *page)
{
struct man_viewer_list *viewer;
- const char *page = cmd_to_page(git_cmd);
const char *fallback = getenv("GIT_MAN_VIEWER");
setup_man_path();
@@ -453,9 +452,8 @@ static void show_man_page(const char *git_cmd)
die(_("no man viewer handled the request"));
}
-static void show_info_page(const char *git_cmd)
+static void show_info_page(const char *page)
{
- const char *page = cmd_to_page(git_cmd);
setenv("INFOPATH", system_path(GIT_INFO_PATH), 1);
execlp("info", "info", "gitman", page, (char *)NULL);
die(_("no info viewer handled the request"));
@@ -486,9 +484,8 @@ static void open_html(const char *path)
execl_git_cmd("web--browse", "-c", "help.browser", path, (char *)NULL);
}
-static void show_html_page(const char *git_cmd)
+static void show_html_page(const char *page)
{
- const char *page = cmd_to_page(git_cmd);
struct strbuf page_path; /* it leaks but we exec bellow */
get_html_page_path(&page_path, page);
@@ -548,6 +545,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)
{
int nongit;
enum help_format parsed_help_format;
+ const char *page;
argc = parse_options(argc, argv, prefix, builtin_help_options,
builtin_help_usage, 0);
@@ -606,16 +604,17 @@ int cmd_help(int argc, const char **argv, const char *prefix)
argv[0] = check_git_cmd(argv[0]);
+ page = cmd_to_page(argv[0]);
switch (help_format) {
case HELP_FORMAT_NONE:
case HELP_FORMAT_MAN:
- show_man_page(argv[0]);
+ show_man_page(page);
break;
case HELP_FORMAT_INFO:
- show_info_page(argv[0]);
+ show_info_page(page);
break;
case HELP_FORMAT_WEB:
- show_html_page(argv[0]);
+ show_html_page(page);
break;
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 15507b5cff..6cc4890217 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -338,15 +338,11 @@ static const char *open_pack_file(const char *pack_name)
"pack/tmp_pack_XXXXXX");
pack_name = strbuf_detach(&tmp_file, NULL);
} else {
- output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
- if (output_fd < 0)
- die_errno(_("unable to create '%s'"), pack_name);
+ output_fd = xopen(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
}
nothread_data.pack_fd = output_fd;
} else {
- input_fd = open(pack_name, O_RDONLY);
- if (input_fd < 0)
- die_errno(_("cannot open packfile '%s'"), pack_name);
+ input_fd = xopen(pack_name, O_RDONLY);
output_fd = -1;
nothread_data.pack_fd = input_fd;
}
@@ -369,9 +365,7 @@ static void parse_pack_header(void)
use(sizeof(struct pack_header));
}
-static NORETURN void bad_object(off_t offset, const char *format,
- ...) __attribute__((format (printf, 2, 3)));
-
+__attribute__((format (printf, 2, 3)))
static NORETURN void bad_object(off_t offset, const char *format, ...)
{
va_list params;
@@ -489,7 +483,7 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
bad_object(offset, _("inflate returned %d"), status);
git_inflate_end(&stream);
if (oid)
- the_hash_algo->final_fn(oid->hash, &c);
+ the_hash_algo->final_oid_fn(oid, &c);
return buf == fixed_buf ? NULL : buf;
}
@@ -524,7 +518,7 @@ static void *unpack_raw_entry(struct object_entry *obj,
switch (obj->type) {
case OBJ_REF_DELTA:
- hashcpy(ref_oid->hash, fill(the_hash_algo->rawsz));
+ oidread(ref_oid, fill(the_hash_algo->rawsz));
use(the_hash_algo->rawsz);
break;
case OBJ_OFS_DELTA:
@@ -1358,7 +1352,7 @@ static struct object_entry *append_obj_to_pack(struct hashfile *f,
obj[1].idx.offset += write_compressed(f, buf, size);
obj[0].idx.crc32 = crc32_end(f);
hashflush(f);
- hashcpy(obj->idx.oid.hash, sha1);
+ oidread(&obj->idx.oid, sha1);
return obj;
}
diff --git a/builtin/init-db.c b/builtin/init-db.c
index c19b35f1e6..2167796ff2 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -212,8 +212,9 @@ static int create_default_files(const char *template_path,
* values (since we've just potentially changed what's available on
* disk).
*/
- git_config_get_value("init.templatedir", &init_template_dir);
+ git_config_get_pathname("init.templatedir", &init_template_dir);
copy_templates(template_path, init_template_dir);
+ free((char *)init_template_dir);
git_config_clear();
reset_shared_repository();
git_config(git_default_config, NULL);
diff --git a/builtin/log.c b/builtin/log.c
index 8acd285daf..f75d87e8d7 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -245,6 +245,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
rev->abbrev_commit = 0;
}
+ if (rev->commit_format == CMIT_FMT_USERFORMAT && !w.decorate)
+ decoration_style = 0;
+
if (decoration_style) {
const struct string_list *config_exclude =
repo_config_get_value_multi(the_repository,
@@ -481,6 +484,8 @@ static int git_log_config(const char *var, const char *value, void *cb)
decoration_style = 0; /* maybe warn? */
return 0;
}
+ if (!strcmp(var, "log.diffmerges"))
+ return diff_merges_config(value);
if (!strcmp(var, "log.showroot")) {
default_show_root = git_config_bool(var, value);
return 0;
@@ -632,7 +637,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
repo_init_revisions(the_repository, &rev, prefix);
rev.diff = 1;
rev.always_show_header = 1;
- rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
+ rev.no_walk = 1;
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
memset(&opt, 0, sizeof(opt));
@@ -1966,8 +1971,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
} else if (rev.diffopt.close_file) {
/*
* The diff code parsed --output; it has already opened the
- * file, but but we must instruct it not to close after each
- * diff.
+ * file, but we must instruct it not to close after each diff.
*/
rev.diffopt.no_free = 1;
} else {
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 60a2913a01..29a26ad8ae 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -57,7 +57,7 @@ static const char *tag_modified = "";
static const char *tag_skip_worktree = "";
static const char *tag_resolve_undo = "";
-static void write_eolinfo(const struct index_state *istate,
+static void write_eolinfo(struct index_state *istate,
const struct cache_entry *ce, const char *path)
{
if (show_eol) {
@@ -122,7 +122,7 @@ static void print_debug(const struct cache_entry *ce)
}
}
-static void show_dir_entry(const struct index_state *istate,
+static void show_dir_entry(struct index_state *istate,
const char *tag, struct dir_entry *ent)
{
int len = max_prefix_len;
@@ -139,7 +139,7 @@ static void show_dir_entry(const struct index_state *istate,
write_name(ent->name);
}
-static void show_other_files(const struct index_state *istate,
+static void show_other_files(struct index_state *istate,
const struct dir_struct *dir)
{
int i;
@@ -152,7 +152,7 @@ static void show_other_files(const struct index_state *istate,
}
}
-static void show_killed_files(const struct index_state *istate,
+static void show_killed_files(struct index_state *istate,
const struct dir_struct *dir)
{
int i;
@@ -210,7 +210,7 @@ static void show_submodule(struct repository *superproject,
{
struct repository subrepo;
const struct submodule *sub = submodule_from_path(superproject,
- &null_oid, path);
+ null_oid(), path);
if (repo_submodule_init(&subrepo, superproject, sub))
return;
@@ -254,7 +254,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,
}
}
-static void show_ru_info(const struct index_state *istate)
+static void show_ru_info(struct index_state *istate)
{
struct string_list_item *item;
@@ -317,6 +317,8 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
if (!(show_cached || show_stage || show_deleted || show_modified))
return;
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(repo->index);
for (i = 0; i < repo->index->cache_nr; i++) {
const struct cache_entry *ce = repo->index->cache[i];
struct stat st;
@@ -494,6 +496,8 @@ void overlay_tree_on_index(struct index_state *istate,
die("bad tree-ish %s", tree_name);
/* Hoist the unmerged entries up to stage #3 to make room */
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(istate);
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce = istate->cache[i];
if (!ce_stage(ce))
@@ -603,8 +607,8 @@ static int option_parse_exclude_standard(const struct option *opt,
int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
{
int require_work_tree = 0, show_tag = 0, i;
- const char *max_prefix;
- struct dir_struct dir;
+ char *max_prefix;
+ struct dir_struct dir = DIR_INIT;
struct pattern_list *pl;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct option builtin_ls_files_options[] = {
@@ -674,7 +678,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(ls_files_usage, builtin_ls_files_options);
- dir_init(&dir);
prefix = cmd_prefix;
if (prefix)
prefix_len = strlen(prefix);
@@ -748,6 +751,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
if (pathspec.nr && error_unmatch)
ps_matched = xcalloc(pathspec.nr, 1);
+ if ((dir.flags & DIR_SHOW_IGNORED) && !show_others && !show_cached)
+ die("ls-files -i must be used with either -o or -c");
+
if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)
die("ls-files --ignored needs some exclude pattern");
@@ -781,5 +787,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
}
dir_clear(&dir);
+ free(max_prefix);
return 0;
}
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 1794548c71..f4fd823af8 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -84,6 +84,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION);
dest = argv[0];
+ packet_trace_identity("ls-remote");
+
UNLEAK(sorting);
if (argc > 1) {
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index cfb667a594..01d16ef9e5 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -7,54 +7,103 @@
#include "utf8.h"
#include "strbuf.h"
#include "mailinfo.h"
+#include "parse-options.h"
-static const char mailinfo_usage[] =
- "git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info";
+static const char * const mailinfo_usage[] = {
+ /* TRANSLATORS: keep <> in "<" mail ">" info. */
+ N_("git mailinfo [<options>] <msg> <patch> < mail >info"),
+ NULL,
+};
+
+struct metainfo_charset
+{
+ enum {
+ CHARSET_DEFAULT,
+ CHARSET_NO_REENCODE,
+ CHARSET_EXPLICIT,
+ } policy;
+ const char *charset;
+};
+
+static int parse_opt_explicit_encoding(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct metainfo_charset *meta_charset = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
+ meta_charset->policy = CHARSET_EXPLICIT;
+ meta_charset->charset = arg;
+
+ return 0;
+}
+
+static int parse_opt_quoted_cr(const struct option *opt, const char *arg, int unset)
+{
+ BUG_ON_OPT_NEG(unset);
+
+ if (mailinfo_parse_quoted_cr_action(arg, opt->value) != 0)
+ return error(_("bad action '%s' for '%s'"), arg, "--quoted-cr");
+ return 0;
+}
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
{
- const char *def_charset;
+ struct metainfo_charset meta_charset;
struct mailinfo mi;
int status;
char *msgfile, *patchfile;
+ struct option options[] = {
+ OPT_BOOL('k', NULL, &mi.keep_subject, N_("keep subject")),
+ OPT_BOOL('b', NULL, &mi.keep_non_patch_brackets_in_subject,
+ N_("keep non patch brackets in subject")),
+ OPT_BOOL('m', "message-id", &mi.add_message_id,
+ N_("copy Message-ID to the end of commit message")),
+ OPT_SET_INT_F('u', NULL, &meta_charset.policy,
+ N_("re-code metadata to i18n.commitEncoding"),
+ CHARSET_DEFAULT, PARSE_OPT_NONEG),
+ OPT_SET_INT_F('n', NULL, &meta_charset.policy,
+ N_("disable charset re-coding of metadata"),
+ CHARSET_NO_REENCODE, PARSE_OPT_NONEG),
+ OPT_CALLBACK_F(0, "encoding", &meta_charset, N_("encoding"),
+ N_("re-code metadata to this encoding"),
+ PARSE_OPT_NONEG, parse_opt_explicit_encoding),
+ OPT_BOOL(0, "scissors", &mi.use_scissors, N_("use scissors")),
+ OPT_CALLBACK_F(0, "quoted-cr", &mi.quoted_cr, N_("<action>"),
+ N_("action when quoted CR is found"),
+ PARSE_OPT_NONEG, parse_opt_quoted_cr),
+ OPT_HIDDEN_BOOL(0, "inbody-headers", &mi.use_inbody_headers,
+ N_("use headers in message's body")),
+ OPT_END()
+ };
+
setup_mailinfo(&mi);
+ meta_charset.policy = CHARSET_DEFAULT;
- def_charset = get_commit_output_encoding();
- mi.metainfo_charset = def_charset;
-
- while (1 < argc && argv[1][0] == '-') {
- if (!strcmp(argv[1], "-k"))
- mi.keep_subject = 1;
- else if (!strcmp(argv[1], "-b"))
- mi.keep_non_patch_brackets_in_subject = 1;
- else if (!strcmp(argv[1], "-m") || !strcmp(argv[1], "--message-id"))
- mi.add_message_id = 1;
- else if (!strcmp(argv[1], "-u"))
- mi.metainfo_charset = def_charset;
- else if (!strcmp(argv[1], "-n"))
- mi.metainfo_charset = NULL;
- else if (starts_with(argv[1], "--encoding="))
- mi.metainfo_charset = argv[1] + 11;
- else if (!strcmp(argv[1], "--scissors"))
- mi.use_scissors = 1;
- else if (!strcmp(argv[1], "--no-scissors"))
- mi.use_scissors = 0;
- else if (!strcmp(argv[1], "--no-inbody-headers"))
- mi.use_inbody_headers = 0;
- else
- usage(mailinfo_usage);
- argc--; argv++;
- }
+ argc = parse_options(argc, argv, prefix, options, mailinfo_usage, 0);
- if (argc != 3)
- usage(mailinfo_usage);
+ if (argc != 2)
+ usage_with_options(mailinfo_usage, options);
+
+ switch (meta_charset.policy) {
+ case CHARSET_DEFAULT:
+ mi.metainfo_charset = get_commit_output_encoding();
+ break;
+ case CHARSET_NO_REENCODE:
+ mi.metainfo_charset = NULL;
+ break;
+ case CHARSET_EXPLICIT:
+ break;
+ default:
+ BUG("invalid meta_charset.policy");
+ }
mi.input = stdin;
mi.output = stdout;
- msgfile = prefix_filename(prefix, argv[1]);
- patchfile = prefix_filename(prefix, argv[2]);
+ msgfile = prefix_filename(prefix, argv[0]);
+ patchfile = prefix_filename(prefix, argv[1]);
status = !!mailinfo(&mi, msgfile, patchfile);
clear_mailinfo(&mi);
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 664400b816..7baef30569 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -75,9 +75,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
fprintf(stderr, "corrupt mailbox\n");
exit(1);
}
- fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
- if (fd < 0)
- die_errno("cannot open output file '%s'", name);
+ fd = xopen(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
output = xfdopen(fd, "w");
/* Copy it out, while searching for a line that begins with
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 38ea6ad6ca..c0383fe9df 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -58,6 +58,8 @@ static void merge_one_path(const char *path)
static void merge_all(void)
{
int i;
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
if (!ce_stage(ce))
@@ -80,6 +82,9 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
read_cache();
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
+
i = 1;
if (!strcmp(argv[i], "-o")) {
one_shot = 1;
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
index 4594507420..3583cff71c 100644
--- a/builtin/merge-ours.c
+++ b/builtin/merge-ours.c
@@ -28,6 +28,6 @@ int cmd_merge_ours(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die_errno("read_cache failed");
if (index_differs_from(the_repository, "HEAD", NULL, 0))
- exit(2);
- exit(0);
+ return 2;
+ return 0;
}
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index de8520778d..5dc94d6f88 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -107,15 +107,12 @@ static void show_diff(struct merge_list *entry)
mmfile_t src, dst;
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
+ xdemitcb_t ecb = { .out_line = show_outf };
memset(&xpp, 0, sizeof(xpp));
xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
- ecb.out_hunk = NULL;
- ecb.out_line = show_outf;
- ecb.priv = NULL;
src.ptr = origin(entry, &size);
if (!src.ptr)
diff --git a/builtin/merge.c b/builtin/merge.c
index 388619536a..42a1989d4a 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -56,8 +56,8 @@ struct strategy {
static const char * const builtin_merge_usage[] = {
N_("git merge [<options>] [<commit>...]"),
- N_("git merge --abort"),
- N_("git merge --continue"),
+ "git merge --abort",
+ "git merge --continue",
NULL
};
@@ -88,9 +88,9 @@ static int autostash;
static int no_verify;
static struct strategy all_strategy[] = {
- { "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
+ { "recursive", NO_TRIVIAL },
{ "octopus", DEFAULT_OCTOPUS },
- { "ort", NO_TRIVIAL },
+ { "ort", DEFAULT_TWOHEAD | NO_TRIVIAL },
{ "resolve", 0 },
{ "ours", NO_FAST_FORWARD | NO_TRIVIAL },
{ "subtree", NO_FAST_FORWARD | NO_TRIVIAL },
@@ -393,10 +393,14 @@ static void restore_state(const struct object_id *head,
}
/* This is called when no merge was necessary. */
-static void finish_up_to_date(const char *msg)
+static void finish_up_to_date(void)
{
- if (verbosity >= 0)
- printf("%s%s\n", squash ? _(" (nothing to squash)") : "", msg);
+ if (verbosity >= 0) {
+ if (squash)
+ puts(_("Already up to date. (nothing to squash)"));
+ else
+ puts(_("Already up to date."));
+ }
remove_merge_branch_state(the_repository);
}
@@ -499,7 +503,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
struct strbuf bname = STRBUF_INIT;
struct merge_remote_desc *desc;
const char *ptr;
- char *found_ref;
+ char *found_ref = NULL;
int len, early;
strbuf_branchname(&bname, remote, 0);
@@ -582,6 +586,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
oid_to_hex(&remote_head->object.oid), remote);
cleanup:
+ free(found_ref);
strbuf_release(&buf);
strbuf_release(&bname);
}
@@ -734,7 +739,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
for (x = 0; x < xopts_nr; x++)
if (parse_merge_opt(&o, xopts[x]))
- die(_("Unknown option for merge-recursive: -X%s"), xopts[x]);
+ die(_("unknown strategy option: -X%s"), xopts[x]);
o.branch1 = head_arg;
o.branch2 = merge_remote_util(remoteheads->item)->name;
@@ -857,9 +862,11 @@ static void prepare_to_commit(struct commit_list *remoteheads)
strbuf_commented_addf(&msg, "\n");
}
strbuf_commented_addf(&msg, _(merge_editor_comment));
- strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
- scissors_editor_comment :
- no_scissors_editor_comment), comment_line_char);
+ if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+ strbuf_commented_addf(&msg, _(scissors_editor_comment));
+ else
+ strbuf_commented_addf(&msg,
+ _(no_scissors_editor_comment), comment_line_char);
}
if (signoff)
append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
@@ -1131,9 +1138,7 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
merge_names = &fetch_head_file;
filename = git_path_fetch_head(the_repository);
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- die_errno(_("could not open '%s' for reading"), filename);
+ fd = xopen(filename, O_RDONLY);
if (strbuf_read(merge_names, fd, 0) < 0)
die_errno(_("could not read '%s'"), filename);
@@ -1480,6 +1485,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
fast_forward = FF_NO;
}
+ if (!use_strategies && !pull_twohead &&
+ remoteheads && !remoteheads->next) {
+ char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
+ if (default_strategy)
+ append_strategy(get_strategy(default_strategy));
+ }
if (!use_strategies) {
if (!remoteheads)
; /* already up-to-date */
@@ -1522,7 +1533,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* If head can reach all the merge then we are up to date.
* but first the most common case of merging one remote.
*/
- finish_up_to_date(_("Already up to date."));
+ finish_up_to_date();
goto done;
} else if (fast_forward != FF_NO && !remoteheads->next &&
!common->next &&
@@ -1556,6 +1567,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
&head_commit->object.oid,
&commit->object.oid,
overwrite_ignore)) {
+ apply_autostash(git_path_merge_autostash(the_repository));
ret = 1;
goto done;
}
@@ -1610,13 +1622,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
}
if (up_to_date) {
- finish_up_to_date(_("Already up to date. Yeeah!"));
+ finish_up_to_date();
goto done;
}
}
if (fast_forward == FF_ONLY)
- die(_("Not possible to fast-forward, aborting."));
+ die_ff_impossible();
if (autostash)
create_autostash(the_repository,
@@ -1704,6 +1716,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
fprintf(stderr, _("Merge with strategy %s failed.\n"),
use_strategies[0]->name);
+ apply_autostash(git_path_merge_autostash(the_repository));
ret = 2;
goto done;
} else if (best_strategy == wt_strategy)
@@ -1711,7 +1724,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else {
printf(_("Rewinding the tree to pristine...\n"));
restore_state(&head_commit->object.oid, &stash);
- printf(_("Using the %s to prepare resolving by hand.\n"),
+ printf(_("Using the %s strategy to prepare resolving by hand.\n"),
best_strategy);
try_merge_strategy(best_strategy, common, remoteheads,
head_commit);
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 891991b00d..ae78ca1c02 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -189,5 +189,5 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
used=0; /* reset tree entry buffer for re-use in batch mode */
}
strbuf_release(&sb);
- exit(0);
+ return 0;
}
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 5d3ea445fd..649aa5f9ab 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -164,7 +164,7 @@ int cmd_multi_pack_index(int argc, const char **argv,
if (!opts.object_dir)
opts.object_dir = get_object_directory();
- if (argc == 0)
+ if (!argc)
goto usage;
if (!strcmp(argv[0], "repack"))
@@ -175,10 +175,9 @@ int cmd_multi_pack_index(int argc, const char **argv,
return cmd_multi_pack_index_verify(argc, argv);
else if (!strcmp(argv[0], "expire"))
return cmd_multi_pack_index_expire(argc, argv);
- else {
+
+ error(_("unrecognized subcommand: %s"), argv[0]);
usage:
- error(_("unrecognized subcommand: %s"), argv[0]);
- usage_with_options(builtin_multi_pack_index_usage,
- builtin_multi_pack_index_options);
- }
+ usage_with_options(builtin_multi_pack_index_usage,
+ builtin_multi_pack_index_options);
}
diff --git a/builtin/mv.c b/builtin/mv.c
index 3fccdcb645..c2f96c8e89 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -303,5 +303,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
+ string_list_clear(&src_for_dst, 0);
+ UNLEAK(source);
+ UNLEAK(dest_path);
+ free(submodule_gitfile);
+ free(modes);
return 0;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 74bba39ca8..71c59583a1 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -172,9 +172,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
/* write the template message before editing: */
d->edit_path = git_pathdup("NOTES_EDITMSG");
- fd = open(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (fd < 0)
- die_errno(_("could not create file '%s'"), d->edit_path);
+ fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (d->given)
write_or_die(fd, d->buf.buf, d->buf.len);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index a1e33d7507..ec8503563a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -37,6 +37,134 @@
#include "shallow.h"
#include "promisor-remote.h"
+/*
+ * Objects we are going to pack are collected in the `to_pack` structure.
+ * It contains an array (dynamically expanded) of the object data, and a map
+ * that can resolve SHA1s to their position in the array.
+ */
+static struct packing_data to_pack;
+
+static inline struct object_entry *oe_delta(
+ const struct packing_data *pack,
+ const struct object_entry *e)
+{
+ if (!e->delta_idx)
+ return NULL;
+ if (e->ext_base)
+ return &pack->ext_bases[e->delta_idx - 1];
+ else
+ return &pack->objects[e->delta_idx - 1];
+}
+
+static inline unsigned long oe_delta_size(struct packing_data *pack,
+ const struct object_entry *e)
+{
+ if (e->delta_size_valid)
+ return e->delta_size_;
+
+ /*
+ * pack->delta_size[] can't be NULL because oe_set_delta_size()
+ * must have been called when a new delta is saved with
+ * oe_set_delta().
+ * If oe_delta() returns NULL (i.e. default state, which means
+ * delta_size_valid is also false), then the caller must never
+ * call oe_delta_size().
+ */
+ return pack->delta_size[e - pack->objects];
+}
+
+unsigned long oe_get_size_slow(struct packing_data *pack,
+ const struct object_entry *e);
+
+static inline unsigned long oe_size(struct packing_data *pack,
+ const struct object_entry *e)
+{
+ if (e->size_valid)
+ return e->size_;
+
+ return oe_get_size_slow(pack, e);
+}
+
+static inline void oe_set_delta(struct packing_data *pack,
+ struct object_entry *e,
+ struct object_entry *delta)
+{
+ if (delta)
+ e->delta_idx = (delta - pack->objects) + 1;
+ else
+ e->delta_idx = 0;
+}
+
+static inline struct object_entry *oe_delta_sibling(
+ const struct packing_data *pack,
+ const struct object_entry *e)
+{
+ if (e->delta_sibling_idx)
+ return &pack->objects[e->delta_sibling_idx - 1];
+ return NULL;
+}
+
+static inline struct object_entry *oe_delta_child(
+ const struct packing_data *pack,
+ const struct object_entry *e)
+{
+ if (e->delta_child_idx)
+ return &pack->objects[e->delta_child_idx - 1];
+ return NULL;
+}
+
+static inline void oe_set_delta_child(struct packing_data *pack,
+ struct object_entry *e,
+ struct object_entry *delta)
+{
+ if (delta)
+ e->delta_child_idx = (delta - pack->objects) + 1;
+ else
+ e->delta_child_idx = 0;
+}
+
+static inline void oe_set_delta_sibling(struct packing_data *pack,
+ struct object_entry *e,
+ struct object_entry *delta)
+{
+ if (delta)
+ e->delta_sibling_idx = (delta - pack->objects) + 1;
+ else
+ e->delta_sibling_idx = 0;
+}
+
+static inline void oe_set_size(struct packing_data *pack,
+ struct object_entry *e,
+ unsigned long size)
+{
+ if (size < pack->oe_size_limit) {
+ e->size_ = size;
+ e->size_valid = 1;
+ } else {
+ e->size_valid = 0;
+ if (oe_get_size_slow(pack, e) != size)
+ BUG("'size' is supposed to be the object size!");
+ }
+}
+
+static inline void oe_set_delta_size(struct packing_data *pack,
+ struct object_entry *e,
+ unsigned long size)
+{
+ if (size < pack->oe_delta_size_limit) {
+ e->delta_size_ = size;
+ e->delta_size_valid = 1;
+ } else {
+ packing_data_lock(pack);
+ if (!pack->delta_size)
+ ALLOC_ARRAY(pack->delta_size, pack->nr_alloc);
+ packing_data_unlock(pack);
+
+ pack->delta_size[e - pack->objects] = size;
+ e->delta_size_valid = 0;
+ }
+}
+
#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
#define SIZE(obj) oe_size(&to_pack, obj)
#define SET_SIZE(obj,size) oe_set_size(&to_pack, obj, size)
@@ -56,13 +184,6 @@ static const char *pack_usage[] = {
NULL
};
-/*
- * Objects we are going to pack are collected in the `to_pack` structure.
- * It contains an array (dynamically expanded) of the object data, and a map
- * that can resolve SHA1s to their position in the array.
- */
-static struct packing_data to_pack;
-
static struct pack_idx_entry **written_list;
static uint32_t nr_result, nr_written, nr_seen;
static struct bitmap_index *bitmap_git;
@@ -301,6 +422,17 @@ static void copy_pack_data(struct hashfile *f,
}
}
+static inline int oe_size_greater_than(struct packing_data *pack,
+ const struct object_entry *lhs,
+ unsigned long rhs)
+{
+ if (lhs->size_valid)
+ return lhs->size_ > rhs;
+ if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
+ return 1;
+ return oe_get_size_slow(pack, lhs) > rhs;
+}
+
/* Return 0 if we will bust the pack-size limit */
static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
unsigned long limit, int usable_delta)
@@ -642,6 +774,14 @@ static int mark_tagged(const char *path, const struct object_id *oid, int flag,
return 0;
}
+static inline unsigned char oe_layer(struct packing_data *pack,
+ struct object_entry *e)
+{
+ if (!pack->layer)
+ return 0;
+ return pack->layer[e - pack->objects];
+}
+
static inline void add_to_write_order(struct object_entry **wo,
unsigned int *endp,
struct object_entry *e)
@@ -1030,7 +1170,7 @@ static void write_pack_file(void)
write_order = compute_write_order();
do {
- struct object_id oid;
+ unsigned char hash[GIT_MAX_RAWSZ];
char *pack_tmp_name = NULL;
if (pack_to_stdout)
@@ -1059,13 +1199,13 @@ static void write_pack_file(void)
* If so, rewrite it like in fast-import
*/
if (pack_to_stdout) {
- finalize_hashfile(f, oid.hash, CSUM_HASH_IN_STREAM | CSUM_CLOSE);
+ finalize_hashfile(f, hash, CSUM_HASH_IN_STREAM | CSUM_CLOSE);
} else if (nr_written == nr_remaining) {
- finalize_hashfile(f, oid.hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
+ finalize_hashfile(f, hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
} else {
- int fd = finalize_hashfile(f, oid.hash, 0);
- fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
- nr_written, oid.hash, offset);
+ int fd = finalize_hashfile(f, hash, 0);
+ fixup_pack_header_footer(fd, hash, pack_tmp_name,
+ nr_written, hash, offset);
close(fd);
if (write_bitmap_index) {
if (write_bitmap_index != WRITE_BITMAP_QUIET)
@@ -1100,17 +1240,17 @@ static void write_pack_file(void)
strbuf_addf(&tmpname, "%s-", base_name);
if (write_bitmap_index) {
- bitmap_writer_set_checksum(oid.hash);
+ bitmap_writer_set_checksum(hash);
bitmap_writer_build_type_index(
&to_pack, written_list, nr_written);
}
finish_tmp_packfile(&tmpname, pack_tmp_name,
written_list, nr_written,
- &pack_idx_opts, oid.hash);
+ &pack_idx_opts, hash);
if (write_bitmap_index) {
- strbuf_addf(&tmpname, "%s.bitmap", oid_to_hex(&oid));
+ strbuf_addf(&tmpname, "%s.bitmap", hash_to_hex(hash));
stop_progress(&progress_state);
@@ -1124,7 +1264,7 @@ static void write_pack_file(void)
strbuf_release(&tmpname);
free(pack_tmp_name);
- puts(oid_to_hex(&oid));
+ puts(hash_to_hex(hash));
}
/* mark written objects as written to previous pack */
@@ -2231,6 +2371,26 @@ static pthread_mutex_t progress_mutex;
* progress_mutex for protection.
*/
+static inline int oe_size_less_than(struct packing_data *pack,
+ const struct object_entry *lhs,
+ unsigned long rhs)
+{
+ if (lhs->size_valid)
+ return lhs->size_ < rhs;
+ if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
+ return 0;
+ return oe_get_size_slow(pack, lhs) < rhs;
+}
+
+static inline void oe_set_tree_depth(struct packing_data *pack,
+ struct object_entry *e,
+ unsigned int tree_depth)
+{
+ if (!pack->tree_depth)
+ CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc);
+ pack->tree_depth[e - pack->objects] = tree_depth;
+}
+
/*
* Return the size of the object without doing any delta
* reconstruction (so non-deltas are true object sizes, but deltas
@@ -3151,9 +3311,26 @@ static void read_packs_list_from_stdin(void)
}
/*
- * First handle all of the excluded packs, marking them as kept in-core
- * so that later calls to add_object_entry() discards any objects that
- * are also found in excluded packs.
+ * Arguments we got on stdin may not even be packs. First
+ * check that to avoid segfaulting later on in
+ * e.g. pack_mtime_cmp(), excluded packs are handled below.
+ *
+ * Since we first parsed our STDIN and then sorted the input
+ * lines the pack we error on will be whatever line happens to
+ * sort first. This is lazy, it's enough that we report one
+ * bad case here, we don't need to report the first/last one,
+ * or all of them.
+ */
+ for_each_string_list_item(item, &include_packs) {
+ struct packed_git *p = item->util;
+ if (!p)
+ die(_("could not find pack '%s'"), item->string);
+ }
+
+ /*
+ * Then, handle all of the excluded packs, marking them as
+ * kept in-core so that later calls to add_object_entry()
+ * discards any objects that are also found in excluded packs.
*/
for_each_string_list_item(item, &exclude_packs) {
struct packed_git *p = item->util;
@@ -3228,13 +3405,9 @@ static void read_object_list_from_stdin(void)
}
}
-/* Remember to update object flag allocation in object.h */
-#define OBJECT_ADDED (1u<<20)
-
static void show_commit(struct commit *commit, void *data)
{
add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
- commit->object.flags |= OBJECT_ADDED;
if (write_bitmap_index)
index_commit_for_bitmap(commit);
@@ -3247,7 +3420,6 @@ static void show_object(struct object *obj, const char *name, void *data)
{
add_preferred_base_object(name);
add_object_entry(&obj->oid, obj->type, name, 0);
- obj->flags |= OBJECT_ADDED;
if (use_delta_islands) {
const char *p;
@@ -3328,79 +3500,23 @@ static void show_edge(struct commit *commit)
add_preferred_base(&commit->object.oid);
}
-struct in_pack_object {
- off_t offset;
- struct object *object;
-};
-
-struct in_pack {
- unsigned int alloc;
- unsigned int nr;
- struct in_pack_object *array;
-};
-
-static void mark_in_pack_object(struct object *object, struct packed_git *p, struct in_pack *in_pack)
-{
- in_pack->array[in_pack->nr].offset = find_pack_entry_one(object->oid.hash, p);
- in_pack->array[in_pack->nr].object = object;
- in_pack->nr++;
-}
-
-/*
- * Compare the objects in the offset order, in order to emulate the
- * "git rev-list --objects" output that produced the pack originally.
- */
-static int ofscmp(const void *a_, const void *b_)
+static int add_object_in_unpacked_pack(const struct object_id *oid,
+ struct packed_git *pack,
+ uint32_t pos,
+ void *_data)
{
- struct in_pack_object *a = (struct in_pack_object *)a_;
- struct in_pack_object *b = (struct in_pack_object *)b_;
-
- if (a->offset < b->offset)
- return -1;
- else if (a->offset > b->offset)
- return 1;
- else
- return oidcmp(&a->object->oid, &b->object->oid);
+ add_object_entry(oid, OBJ_NONE, "", 0);
+ return 0;
}
static void add_objects_in_unpacked_packs(void)
{
- struct packed_git *p;
- struct in_pack in_pack;
- uint32_t i;
-
- memset(&in_pack, 0, sizeof(in_pack));
-
- for (p = get_all_packs(the_repository); p; p = p->next) {
- struct object_id oid;
- struct object *o;
-
- if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
- continue;
- if (open_pack_index(p))
- die(_("cannot open pack index"));
-
- ALLOC_GROW(in_pack.array,
- in_pack.nr + p->num_objects,
- in_pack.alloc);
-
- for (i = 0; i < p->num_objects; i++) {
- nth_packed_object_id(&oid, p, i);
- o = lookup_unknown_object(&oid);
- if (!(o->flags & OBJECT_ADDED))
- mark_in_pack_object(o, p, &in_pack);
- o->flags |= OBJECT_ADDED;
- }
- }
-
- if (in_pack.nr) {
- QSORT(in_pack.array, in_pack.nr, ofscmp);
- for (i = 0; i < in_pack.nr; i++) {
- struct object *o = in_pack.array[i].object;
- add_object_entry(&o->oid, o->type, "", 0);
- }
- }
- free(in_pack.array);
+ if (for_each_packed_object(add_object_in_unpacked_pack, NULL,
+ FOR_EACH_OBJECT_PACK_ORDER |
+ FOR_EACH_OBJECT_LOCAL_ONLY |
+ FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
+ FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS))
+ die(_("cannot open pack index"));
}
static int add_loose_object(const struct object_id *oid, const char *path,
@@ -3479,6 +3595,7 @@ static void loosen_unused_packed_objects(void)
{
struct packed_git *p;
uint32_t i;
+ uint32_t loosened_objects_nr = 0;
struct object_id oid;
for (p = get_all_packs(the_repository); p; p = p->next) {
@@ -3492,11 +3609,16 @@ static void loosen_unused_packed_objects(void)
nth_packed_object_id(&oid, p, i);
if (!packlist_find(&to_pack, &oid) &&
!has_sha1_pack_kept_or_nonlocal(&oid) &&
- !loosened_object_can_be_discarded(&oid, p->mtime))
+ !loosened_object_can_be_discarded(&oid, p->mtime)) {
if (force_object_loose(&oid, p->mtime))
die(_("unable to force loose object"));
+ loosened_objects_nr++;
+ }
}
}
+
+ trace2_data_intmax("pack-objects", the_repository,
+ "loosen_unused_packed_objects/loosened", loosened_objects_nr);
}
/*
@@ -3516,7 +3638,7 @@ static int pack_options_allow_reuse(void)
static int get_object_list_from_bitmap(struct rev_info *revs)
{
- if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options)))
+ if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options, 0)))
return -1;
if (pack_options_allow_reuse() &&
@@ -3527,7 +3649,8 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
&reuse_packfile_bitmap)) {
assert(reuse_packfile_objects);
nr_result += reuse_packfile_objects;
- display_progress(progress_state, nr_result);
+ nr_seen += reuse_packfile_objects;
+ display_progress(progress_state, nr_seen);
}
traverse_bitmap_commit_list(bitmap_git, revs,
@@ -3860,6 +3983,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (pack_to_stdout != !base_name || argc)
usage_with_options(pack_usage, pack_objects_options);
+ if (depth < 0)
+ depth = 0;
if (depth >= (1 << OE_DEPTH_BITS)) {
warning(_("delta chain depth %d is too deep, forcing %d"),
depth, (1 << OE_DEPTH_BITS) - 1);
@@ -3870,6 +3995,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
(1U << OE_Z_DELTA_BITS) - 1);
cache_max_small_delta_size = (1U << OE_Z_DELTA_BITS) - 1;
}
+ if (window < 0)
+ window = 0;
strvec_push(&rp, "pack-objects");
if (thin) {
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 7102996c75..8bf5c0acad 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -20,7 +20,7 @@ static int load_all_packs, verbose, alt_odb;
struct llist_item {
struct llist_item *next;
- const struct object_id *oid;
+ struct object_id oid;
};
static struct llist {
struct llist_item *front;
@@ -95,10 +95,10 @@ static struct llist * llist_copy(struct llist *list)
static inline struct llist_item *llist_insert(struct llist *list,
struct llist_item *after,
- const struct object_id *oid)
+ const unsigned char *oid)
{
struct llist_item *new_item = llist_item_get();
- new_item->oid = oid;
+ oidread(&new_item->oid, oid);
new_item->next = NULL;
if (after != NULL) {
@@ -118,7 +118,7 @@ static inline struct llist_item *llist_insert(struct llist *list,
}
static inline struct llist_item *llist_insert_back(struct llist *list,
- const struct object_id *oid)
+ const unsigned char *oid)
{
return llist_insert(list, list->back, oid);
}
@@ -130,9 +130,9 @@ static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
l = (hint == NULL) ? list->front : hint;
while (l) {
- int cmp = oidcmp(l->oid, oid);
+ int cmp = oidcmp(&l->oid, oid);
if (cmp > 0) { /* we insert before this entry */
- return llist_insert(list, prev, oid);
+ return llist_insert(list, prev, oid->hash);
}
if (!cmp) { /* already exists */
return l;
@@ -141,11 +141,11 @@ static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
l = l->next;
}
/* insert at the end */
- return llist_insert_back(list, oid);
+ return llist_insert_back(list, oid->hash);
}
/* returns a pointer to an item in front of sha1 */
-static inline struct llist_item * llist_sorted_remove(struct llist *list, const struct object_id *oid, struct llist_item *hint)
+static inline struct llist_item * llist_sorted_remove(struct llist *list, const unsigned char *oid, struct llist_item *hint)
{
struct llist_item *prev, *l;
@@ -153,7 +153,7 @@ redo_from_start:
l = (hint == NULL) ? list->front : hint;
prev = NULL;
while (l) {
- const int cmp = oidcmp(l->oid, oid);
+ const int cmp = hashcmp(l->oid.hash, oid);
if (cmp > 0) /* not in list, since sorted */
return prev;
if (!cmp) { /* found */
@@ -188,7 +188,7 @@ static void llist_sorted_difference_inplace(struct llist *A,
b = B->front;
while (b) {
- hint = llist_sorted_remove(A, b->oid, hint);
+ hint = llist_sorted_remove(A, b->oid.hash, hint);
b = b->next;
}
}
@@ -260,10 +260,10 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
/* cmp ~ p1 - p2 */
if (cmp == 0) {
p1_hint = llist_sorted_remove(p1->unique_objects,
- (const struct object_id *)(p1_base + p1_off),
+ p1_base + p1_off,
p1_hint);
p2_hint = llist_sorted_remove(p2->unique_objects,
- (const struct object_id *)(p1_base + p1_off),
+ p1_base + p1_off,
p2_hint);
p1_off += p1_step;
p2_off += p2_step;
@@ -455,7 +455,7 @@ static void load_all_objects(void)
l = pl->remaining_objects->front;
while (l) {
hint = llist_insert_sorted_unique(all_objects,
- l->oid, hint);
+ &l->oid, hint);
l = l->next;
}
pl = pl->next;
@@ -521,7 +521,7 @@ static struct pack_list * add_pack(struct packed_git *p)
base += 256 * 4 + ((p->index_version < 2) ? 4 : 8);
step = the_hash_algo->rawsz + ((p->index_version < 2) ? 4 : 0);
while (off < p->num_objects * step) {
- llist_insert_back(l.remaining_objects, (const struct object_id *)(base + off));
+ llist_insert_back(l.remaining_objects, base + off);
off += step;
}
l.all_objects_size = l.remaining_objects->size;
diff --git a/builtin/pull.c b/builtin/pull.c
index e8927fc2ff..b311ea6b9d 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -126,9 +126,9 @@ static struct option pull_options[] = {
/* Options passed to git-merge or git-rebase */
OPT_GROUP(N_("Options related to merging")),
OPT_CALLBACK_F('r', "rebase", &opt_rebase,
- "(false|true|merges|preserve|interactive)",
- N_("incorporate changes by rebasing rather than merging"),
- PARSE_OPT_OPTARG, parse_opt_rebase),
+ "(false|true|merges|preserve|interactive)",
+ N_("incorporate changes by rebasing rather than merging"),
+ PARSE_OPT_OPTARG, parse_opt_rebase),
OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,
N_("do not show a diffstat at the end of the merge"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG),
@@ -893,6 +893,8 @@ static int run_rebase(const struct object_id *newbase,
strvec_pushv(&args, opt_strategy_opts.v);
if (opt_gpg_sign)
strvec_push(&args, opt_gpg_sign);
+ if (opt_signoff)
+ strvec_push(&args, opt_signoff);
if (opt_autostash == 0)
strvec_push(&args, "--no-autostash");
else if (opt_autostash == 1)
@@ -911,12 +913,18 @@ static int run_rebase(const struct object_id *newbase,
return ret;
}
-static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_head)
+static int get_can_ff(struct object_id *orig_head,
+ struct oid_array *merge_heads)
{
int ret;
struct commit_list *list = NULL;
struct commit *merge_head, *head;
+ struct object_id *orig_merge_head;
+
+ if (merge_heads->nr > 1)
+ return 0;
+ orig_merge_head = &merge_heads->oid[0];
head = lookup_commit_reference(the_repository, orig_head);
commit_list_insert(head, &list);
merge_head = lookup_commit_reference(the_repository, orig_merge_head);
@@ -927,9 +935,9 @@ static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_
static void show_advice_pull_non_ff(void)
{
- advise(_("Pulling without specifying how to reconcile divergent branches is\n"
- "discouraged. You can squelch this message by running one of the following\n"
- "commands sometime before your next pull:\n"
+ advise(_("You have divergent branches and need to specify how to reconcile them.\n"
+ "You can do so by running one of the following commands sometime before\n"
+ "your next pull:\n"
"\n"
" git config pull.rebase false # merge (the default strategy)\n"
" git config pull.rebase true # rebase\n"
@@ -947,7 +955,6 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
struct oid_array merge_heads = OID_ARRAY_INIT;
struct object_id orig_head, curr_head;
struct object_id rebase_fork_point;
- int autostash;
int rebase_unspecified = 0;
int can_ff;
@@ -967,8 +974,22 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
parse_repo_refspecs(argc, argv, &repo, &refspecs);
- if (!opt_ff)
+ if (!opt_ff) {
opt_ff = xstrdup_or_null(config_get_ff());
+ /*
+ * A subtle point: opt_ff was set on the line above via
+ * reading from config. opt_rebase, in contrast, is set
+ * before this point via command line options. The setting
+ * of opt_rebase via reading from config (using
+ * config_get_rebase()) does not happen until later. We
+ * are relying on the next if-condition happening before
+ * the config_get_rebase() call so that an explicit
+ * "--rebase" can override a config setting of
+ * pull.ff=only.
+ */
+ if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only"))
+ opt_ff = "--ff";
+ }
if (opt_rebase < 0)
opt_rebase = config_get_rebase(&rebase_unspecified);
@@ -982,8 +1003,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (get_oid("HEAD", &orig_head))
oidclr(&orig_head);
- autostash = config_autostash;
if (opt_rebase) {
+ int autostash = config_autostash;
if (opt_autostash != -1)
autostash = opt_autostash;
@@ -1042,19 +1063,29 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
die(_("Cannot merge multiple branches into empty head."));
return pull_into_void(merge_heads.oid, &curr_head);
}
- if (opt_rebase && merge_heads.nr > 1)
- die(_("Cannot rebase onto multiple branches."));
+ if (merge_heads.nr > 1) {
+ if (opt_rebase)
+ die(_("Cannot rebase onto multiple branches."));
+ if (opt_ff && !strcmp(opt_ff, "--ff-only"))
+ die(_("Cannot fast-forward to multiple branches."));
+ }
- can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
+ can_ff = get_can_ff(&orig_head, &merge_heads);
- if (rebase_unspecified && !opt_ff && !can_ff) {
- if (opt_verbosity >= 0)
- show_advice_pull_non_ff();
+ /* ff-only takes precedence over rebase */
+ if (opt_ff && !strcmp(opt_ff, "--ff-only")) {
+ if (!can_ff)
+ die_ff_impossible();
+ opt_rebase = REBASE_FALSE;
+ }
+ /* If no action specified and we can't fast forward, then warn. */
+ if (!opt_ff && rebase_unspecified && !can_ff) {
+ show_advice_pull_non_ff();
+ die(_("Need to specify how to reconcile divergent branches."));
}
if (opt_rebase) {
int ret = 0;
- int ran_ff = 0;
struct object_id newbase;
struct object_id upstream;
@@ -1065,16 +1096,14 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
submodule_touches_in_range(the_repository, &upstream, &curr_head))
die(_("cannot rebase with locally recorded submodule modifications"));
- if (!autostash) {
- if (can_ff) {
- /* we can fast-forward this without invoking rebase */
- opt_ff = "--ff-only";
- ran_ff = 1;
- ret = run_merge();
- }
- }
- if (!ran_ff)
+
+ if (can_ff) {
+ /* we can fast-forward this without invoking rebase */
+ opt_ff = "--ff-only";
+ ret = run_merge();
+ } else {
ret = run_rebase(&newbase, &upstream);
+ }
if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
diff --git a/builtin/push.c b/builtin/push.c
index 194967ed79..e8b10a9b7e 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -185,82 +185,73 @@ static const char message_detached_head_die[] =
"\n"
" git push %s HEAD:<name-of-remote-branch>\n");
-static void setup_push_upstream(struct remote *remote, struct branch *branch,
- int triangular, int simple)
+static const char *get_upstream_ref(struct branch *branch, const char *remote_name)
{
- if (!branch)
- die(_(message_detached_head_die), remote->name);
if (!branch->merge_nr || !branch->merge || !branch->remote_name)
die(_("The current branch %s has no upstream branch.\n"
"To push the current branch and set the remote as upstream, use\n"
"\n"
" git push --set-upstream %s %s\n"),
branch->name,
- remote->name,
+ remote_name,
branch->name);
if (branch->merge_nr != 1)
die(_("The current branch %s has multiple upstream branches, "
"refusing to push."), branch->name);
- if (triangular)
- die(_("You are pushing to remote '%s', which is not the upstream of\n"
- "your current branch '%s', without telling me what to push\n"
- "to update which remote branch."),
- remote->name, branch->name);
-
- if (simple) {
- /* Additional safety */
- if (strcmp(branch->refname, branch->merge[0]->src))
- die_push_simple(branch, remote);
- }
-
- refspec_appendf(&rs, "%s:%s", branch->refname, branch->merge[0]->src);
-}
-
-static void setup_push_current(struct remote *remote, struct branch *branch)
-{
- if (!branch)
- die(_(message_detached_head_die), remote->name);
- refspec_appendf(&rs, "%s:%s", branch->refname, branch->refname);
-}
-static int is_workflow_triangular(struct remote *remote)
-{
- struct remote *fetch_remote = remote_get(NULL);
- return (fetch_remote && fetch_remote != remote);
+ return branch->merge[0]->src;
}
static void setup_default_push_refspecs(struct remote *remote)
{
- struct branch *branch = branch_get(NULL);
- int triangular = is_workflow_triangular(remote);
+ struct branch *branch;
+ const char *dst;
+ int same_remote;
switch (push_default) {
- default:
case PUSH_DEFAULT_MATCHING:
refspec_append(&rs, ":");
+ return;
+
+ case PUSH_DEFAULT_NOTHING:
+ die(_("You didn't specify any refspecs to push, and "
+ "push.default is \"nothing\"."));
+ return;
+ default:
break;
+ }
+ branch = branch_get(NULL);
+ if (!branch)
+ die(_(message_detached_head_die), remote->name);
+
+ dst = branch->refname;
+ same_remote = !strcmp(remote->name, remote_for_branch(branch, NULL));
+
+ switch (push_default) {
+ default:
case PUSH_DEFAULT_UNSPECIFIED:
case PUSH_DEFAULT_SIMPLE:
- if (triangular)
- setup_push_current(remote, branch);
- else
- setup_push_upstream(remote, branch, triangular, 1);
+ if (!same_remote)
+ break;
+ if (strcmp(branch->refname, get_upstream_ref(branch, remote->name)))
+ die_push_simple(branch, remote);
break;
case PUSH_DEFAULT_UPSTREAM:
- setup_push_upstream(remote, branch, triangular, 0);
+ if (!same_remote)
+ die(_("You are pushing to remote '%s', which is not the upstream of\n"
+ "your current branch '%s', without telling me what to push\n"
+ "to update which remote branch."),
+ remote->name, branch->name);
+ dst = get_upstream_ref(branch, remote->name);
break;
case PUSH_DEFAULT_CURRENT:
- setup_push_current(remote, branch);
- break;
-
- case PUSH_DEFAULT_NOTHING:
- die(_("You didn't specify any refspecs to push, and "
- "push.default is \"nothing\"."));
break;
}
+
+ refspec_appendf(&rs, "%s:%s", branch->refname, dst);
}
static const char message_advice_pull_before_push[] =
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 783b526f6e..eb01f4d790 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -139,7 +139,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.ignore_date = opts->ignore_date;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
if (opts->strategy)
- replay.strategy = opts->strategy;
+ replay.strategy = xstrdup_or_null(opts->strategy);
else if (!replay.strategy && replay.default_strategy) {
replay.strategy = replay.default_strategy;
replay.default_strategy = NULL;
@@ -405,6 +405,7 @@ static int run_sequencer_rebase(struct rebase_options *opts,
flags |= opts->root_with_onto ? TODO_LIST_ROOT_WITH_ONTO : 0;
flags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
flags |= opts->reapply_cherry_picks ? TODO_LIST_REAPPLY_CHERRY_PICKS : 0;
+ flags |= opts->flags & REBASE_NO_QUIET ? TODO_LIST_WARN_SKIPPED_CHERRY_PICKS : 0;
switch (command) {
case ACTION_NONE: {
@@ -485,7 +486,7 @@ static const char * const builtin_rebase_interactive_usage[] = {
int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
{
struct rebase_options opts = REBASE_OPTIONS_INIT;
- struct object_id squash_onto = null_oid;
+ struct object_id squash_onto = *null_oid();
enum action command = ACTION_NONE;
struct option options[] = {
OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"),
@@ -738,6 +739,7 @@ static int finish_rebase(struct rebase_options *opts)
int ret = 0;
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
+ unlink(git_path_auto_merge(the_repository));
apply_autostash(state_dir_path("autostash", opts));
close_object_store(the_repository->objects);
/*
@@ -1139,7 +1141,7 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,
merge_bases = get_merge_bases(onto, head);
if (!merge_bases || merge_bases->next) {
- oidcpy(merge_base, &null_oid);
+ oidcpy(merge_base, null_oid());
goto done;
}
@@ -1712,7 +1714,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
int i;
if (!options.strategy)
- options.strategy = "recursive";
+ options.strategy = "ort";
strbuf_reset(&buf);
for (i = 0; i < strategy_options.nr; i++)
@@ -1917,7 +1919,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
&options.orig_head))
options.head_name = NULL;
else
- die(_("fatal: no such branch/commit '%s'"),
+ die(_("no such branch/commit '%s'"),
branch_name);
} else if (argc == 0) {
/* Do not need to switch branches, we are already on it. */
@@ -2108,6 +2110,8 @@ cleanup:
free(options.head_name);
free(options.gpg_sign_opt);
free(options.cmd);
+ free(options.strategy);
+ strbuf_release(&options.git_format_patch_opt);
free(squash_onto_name);
return ret;
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 6bc12c828a..2d1f97e1ca 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -329,7 +329,7 @@ static void write_head_info(void)
for_each_alternate_ref(show_one_alternate_ref, &seen);
oidset_clear(&seen);
if (!sent_capabilities)
- show_ref("capabilities^{}", &null_oid);
+ show_ref("capabilities^{}", null_oid());
advertise_shallow_grafts(1);
@@ -425,9 +425,6 @@ static int proc_receive_ref_matches(struct command *cmd)
return 0;
}
-static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
-static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
-
static void report_message(const char *prefix, const char *err, va_list params)
{
int sz;
@@ -445,6 +442,7 @@ static void report_message(const char *prefix, const char *err, va_list params)
xwrite(2, msg, sz);
}
+__attribute__((format (printf, 1, 2)))
static void rp_warning(const char *err, ...)
{
va_list params;
@@ -453,6 +451,7 @@ static void rp_warning(const char *err, ...)
va_end(params);
}
+__attribute__((format (printf, 1, 2)))
static void rp_error(const char *err, ...)
{
va_list params;
diff --git a/builtin/repack.c b/builtin/repack.c
index 2847fdfbab..5f9bc74adc 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -20,7 +20,7 @@ static int delta_base_offset = 1;
static int pack_kept_objects = -1;
static int write_bitmaps = -1;
static int use_delta_islands;
-static char *packdir, *packtmp;
+static char *packdir, *packtmp_name, *packtmp;
static const char *const git_repack_usage[] = {
N_("git repack [<options>]"),
@@ -530,7 +530,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
}
packdir = mkpathdup("%s/pack", get_object_directory());
- packtmp = mkpathdup("%s/.tmp-%d-pack", packdir, (int)getpid());
+ packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
+ packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
sigchain_push_common(remove_pack_on_signal);
@@ -573,6 +574,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
repack_promisor_objects(&po_args, &names);
if (existing_packs.nr && delete_redundant) {
+ for_each_string_list_item(item, &names) {
+ strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
+ packtmp_name, item->string);
+ }
if (unpack_unreachable) {
strvec_pushf(&cmd.args,
"--unpack-unreachable=%s",
diff --git a/builtin/rerere.c b/builtin/rerere.c
index fd3be17b97..83d7a778e3 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -28,7 +28,7 @@ static int diff_two(const char *file1, const char *label1,
{
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
+ xdemitcb_t ecb = { .out_line = outf };
mmfile_t minus, plus;
int ret;
@@ -41,8 +41,6 @@ static int diff_two(const char *file1, const char *label1,
xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
- ecb.out_hunk = NULL;
- ecb.out_line = outf;
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index b4d8ea0a35..36cb909eba 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -127,13 +127,15 @@ static void show_commit(struct commit *commit, void *data)
if (info->header_prefix)
fputs(info->header_prefix, stdout);
- if (!revs->graph)
- fputs(get_revision_mark(revs, commit), stdout);
- if (revs->abbrev_commit && revs->abbrev)
- fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev),
- stdout);
- else
- fputs(oid_to_hex(&commit->object.oid), stdout);
+ if (revs->include_header) {
+ if (!revs->graph)
+ fputs(get_revision_mark(revs, commit), stdout);
+ if (revs->abbrev_commit && revs->abbrev)
+ fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev),
+ stdout);
+ else
+ fputs(oid_to_hex(&commit->object.oid), stdout);
+ }
if (revs->print_parents) {
struct commit_list *parents = commit->parents;
while (parents) {
@@ -153,7 +155,7 @@ static void show_commit(struct commit *commit, void *data)
show_decorations(revs, commit);
if (revs->commit_format == CMIT_FMT_ONELINE)
putchar(' ');
- else
+ else if (revs->include_header)
putchar('\n');
if (revs->verbose_header) {
@@ -398,7 +400,8 @@ static inline int parse_missing_action_value(const char *value)
}
static int try_bitmap_count(struct rev_info *revs,
- struct list_objects_filter_options *filter)
+ struct list_objects_filter_options *filter,
+ int filter_provided_objects)
{
uint32_t commit_count = 0,
tag_count = 0,
@@ -433,7 +436,7 @@ static int try_bitmap_count(struct rev_info *revs,
*/
max_count = revs->max_count;
- bitmap_git = prepare_bitmap_walk(revs, filter);
+ bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
if (!bitmap_git)
return -1;
@@ -450,7 +453,8 @@ static int try_bitmap_count(struct rev_info *revs,
}
static int try_bitmap_traversal(struct rev_info *revs,
- struct list_objects_filter_options *filter)
+ struct list_objects_filter_options *filter,
+ int filter_provided_objects)
{
struct bitmap_index *bitmap_git;
@@ -461,7 +465,7 @@ static int try_bitmap_traversal(struct rev_info *revs,
if (revs->max_count >= 0)
return -1;
- bitmap_git = prepare_bitmap_walk(revs, filter);
+ bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
if (!bitmap_git)
return -1;
@@ -471,14 +475,15 @@ static int try_bitmap_traversal(struct rev_info *revs,
}
static int try_bitmap_disk_usage(struct rev_info *revs,
- struct list_objects_filter_options *filter)
+ struct list_objects_filter_options *filter,
+ int filter_provided_objects)
{
struct bitmap_index *bitmap_git;
if (!show_disk_usage)
return -1;
- bitmap_git = prepare_bitmap_walk(revs, filter);
+ bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
if (!bitmap_git)
return -1;
@@ -499,6 +504,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
int bisect_show_vars = 0;
int bisect_find_all = 0;
int use_bitmap_index = 0;
+ int filter_provided_objects = 0;
const char *show_progress = NULL;
if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -508,6 +514,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
repo_init_revisions(the_repository, &revs, prefix);
revs.abbrev = DEFAULT_ABBREV;
revs.commit_format = CMIT_FMT_UNSPECIFIED;
+ revs.include_header = 1;
/*
* Scan the argument list before invoking setup_revisions(), so that we
@@ -599,6 +606,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
list_objects_filter_set_no_filter(&filter_options);
continue;
}
+ if (!strcmp(arg, "--filter-provided-objects")) {
+ filter_provided_objects = 1;
+ continue;
+ }
if (!strcmp(arg, "--filter-print-omitted")) {
arg_print_omitted = 1;
continue;
@@ -619,6 +630,16 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
continue;
}
+ if (!strcmp(arg, ("--commit-header"))) {
+ revs.include_header = 1;
+ continue;
+ }
+
+ if (!strcmp(arg, ("--no-commit-header"))) {
+ revs.include_header = 0;
+ continue;
+ }
+
if (!strcmp(arg, "--disk-usage")) {
show_disk_usage = 1;
info.flags |= REV_LIST_QUIET;
@@ -628,10 +649,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
usage(rev_list_usage);
}
+ if (revs.commit_format != CMIT_FMT_USERFORMAT)
+ revs.include_header = 1;
if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
/* The command line has a --pretty */
info.hdr_termination = '\n';
- if (revs.commit_format == CMIT_FMT_ONELINE)
+ if (revs.commit_format == CMIT_FMT_ONELINE || !revs.include_header)
info.header_prefix = "";
else
info.header_prefix = "commit ";
@@ -665,11 +688,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
progress = start_delayed_progress(show_progress, 0);
if (use_bitmap_index) {
- if (!try_bitmap_count(&revs, &filter_options))
+ if (!try_bitmap_count(&revs, &filter_options, filter_provided_objects))
return 0;
- if (!try_bitmap_disk_usage(&revs, &filter_options))
+ if (!try_bitmap_disk_usage(&revs, &filter_options, filter_provided_objects))
return 0;
- if (!try_bitmap_traversal(&revs, &filter_options))
+ if (!try_bitmap_traversal(&revs, &filter_options, filter_provided_objects))
return 0;
}
@@ -694,6 +717,16 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
return show_bisect_vars(&info, reaches, all);
}
+ if (filter_provided_objects) {
+ struct commit_list *c;
+ for (i = 0; i < revs.pending.nr; i++) {
+ struct object_array_entry *pending = revs.pending.objects + i;
+ pending->item->flags |= NOT_USER_GIVEN;
+ }
+ for (c = revs.commits; c; c = c->next)
+ c->item->object.flags |= NOT_USER_GIVEN;
+ }
+
if (arg_print_omitted)
oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
if (arg_missing_action == MA_PRINT)
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 85bad9052e..22c4e1a4ff 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -435,11 +435,11 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
/* get the usage up to the first line with a -- on it */
for (;;) {
if (strbuf_getline(&sb, stdin) == EOF)
- die("premature end of input");
+ die(_("premature end of input"));
ALLOC_GROW(usage, unb + 1, usz);
if (!strcmp("--", sb.buf)) {
if (unb < 1)
- die("no usage string given before the `--' separator");
+ die(_("no usage string given before the `--' separator"));
usage[unb] = NULL;
break;
}
@@ -545,7 +545,7 @@ static void die_no_single_rev(int quiet)
if (quiet)
exit(1);
else
- die("Needed a single revision");
+ die(_("Needed a single revision"));
}
static const char builtin_rev_parse_usage[] =
@@ -709,10 +709,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--resolve-git-dir")) {
const char *gitdir = argv[++i];
if (!gitdir)
- die("--resolve-git-dir requires an argument");
+ die(_("--resolve-git-dir requires an argument"));
gitdir = resolve_gitdir(gitdir);
if (!gitdir)
- die("not a gitdir '%s'", argv[i]);
+ die(_("not a gitdir '%s'"), argv[i]);
puts(gitdir);
continue;
}
@@ -736,7 +736,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!seen_end_of_options && *arg == '-') {
if (!strcmp(arg, "--git-path")) {
if (!argv[i + 1])
- die("--git-path requires an argument");
+ die(_("--git-path requires an argument"));
strbuf_reset(&buf);
print_path(git_path("%s", argv[i + 1]), prefix,
format,
@@ -746,7 +746,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!strcmp(arg,"-n")) {
if (++i >= argc)
- die("-n requires an argument");
+ die(_("-n requires an argument"));
if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
show(arg);
show(argv[i]);
@@ -759,25 +759,27 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (opt_with_value(arg, "--path-format", &arg)) {
+ if (!arg)
+ die(_("--path-format requires an argument"));
if (!strcmp(arg, "absolute")) {
format = FORMAT_CANONICAL;
} else if (!strcmp(arg, "relative")) {
format = FORMAT_RELATIVE;
} else {
- die("unknown argument to --path-format: %s", arg);
+ die(_("unknown argument to --path-format: %s"), arg);
}
continue;
}
if (!strcmp(arg, "--default")) {
def = argv[++i];
if (!def)
- die("--default requires an argument");
+ die(_("--default requires an argument"));
continue;
}
if (!strcmp(arg, "--prefix")) {
prefix = argv[++i];
if (!prefix)
- die("--prefix requires an argument");
+ die(_("--prefix requires an argument"));
startup_info->prefix = prefix;
output_prefix = 1;
continue;
@@ -846,7 +848,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
else if (!strcmp(arg, "loose"))
abbrev_ref_strict = 0;
else
- die("unknown mode for --abbrev-ref: %s",
+ die(_("unknown mode for --abbrev-ref: %s"),
arg);
}
continue;
@@ -890,7 +892,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (work_tree)
print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
else
- die("this operation must be run in a work tree");
+ die(_("this operation must be run in a work tree"));
continue;
}
if (!strcmp(arg, "--show-superproject-working-tree")) {
@@ -1018,7 +1020,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (strcmp(val, "storage") &&
strcmp(val, "input") &&
strcmp(val, "output"))
- die("unknown mode for --show-object-format: %s",
+ die(_("unknown mode for --show-object-format: %s"),
arg);
puts(the_hash_algo->name);
continue;
@@ -1056,7 +1058,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (verify)
die_no_single_rev(quiet);
if (has_dashdash)
- die("bad revision '%s'", arg);
+ die(_("bad revision '%s'"), arg);
as_is = 1;
if (!show_file(arg, output_prefix))
continue;
diff --git a/builtin/revert.c b/builtin/revert.c
index 237f2f18d4..2e13660e4b 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -191,7 +191,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
struct setup_revision_opt s_r_opt;
opts->revs = xmalloc(sizeof(*opts->revs));
repo_init_revisions(the_repository, opts->revs, NULL);
- opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
+ opts->revs->no_walk = 1;
+ opts->revs->unsorted_input = 1;
if (argc < 2)
usage_with_options(usage_str, options);
if (!strcmp(argv[1], "-"))
diff --git a/builtin/rm.c b/builtin/rm.c
index 4858631e0f..8a24c715e0 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -5,6 +5,7 @@
*/
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "builtin.h"
+#include "advice.h"
#include "config.h"
#include "lockfile.h"
#include "dir.h"
@@ -254,7 +255,7 @@ static struct option builtin_rm_options[] = {
int cmd_rm(int argc, const char **argv, const char *prefix)
{
struct lock_file lock_file = LOCK_INIT;
- int i;
+ int i, ret = 0;
struct pathspec pathspec;
char *seen;
@@ -293,8 +294,12 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
seen = xcalloc(pathspec.nr, 1);
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
+ if (ce_skip_worktree(ce))
+ continue;
if (!ce_path_match(&the_index, ce, &pathspec, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
@@ -308,25 +313,37 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (pathspec.nr) {
const char *original;
int seen_any = 0;
+ char *skip_worktree_seen = NULL;
+ struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
+
for (i = 0; i < pathspec.nr; i++) {
original = pathspec.items[i].original;
- if (!seen[i]) {
- if (!ignore_unmatch) {
- die(_("pathspec '%s' did not match any files"),
- original);
- }
- }
- else {
+ if (seen[i])
seen_any = 1;
- }
+ else if (ignore_unmatch)
+ continue;
+ else if (matches_skip_worktree(&pathspec, i, &skip_worktree_seen))
+ string_list_append(&only_match_skip_worktree, original);
+ else
+ die(_("pathspec '%s' did not match any files"), original);
+
if (!recursive && seen[i] == MATCHED_RECURSIVELY)
die(_("not removing '%s' recursively without -r"),
*original ? original : ".");
}
+ if (only_match_skip_worktree.nr) {
+ advise_on_updating_sparse_paths(&only_match_skip_worktree);
+ ret = 1;
+ }
+ free(skip_worktree_seen);
+ string_list_clear(&only_match_skip_worktree, 0);
+
if (!seen_any)
- exit(0);
+ exit(ret);
}
+ clear_pathspec(&pathspec);
+ free(seen);
if (!index_only)
submodules_absorb_gitdir_if_needed();
@@ -405,5 +422,5 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
- return 0;
+ return ret;
}
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index a7e01667b0..729dea1d25 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -230,6 +230,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.atomic = atomic;
args.stateless_rpc = stateless_rpc;
args.push_options = push_options.nr ? &push_options : NULL;
+ args.url = dest;
if (from_stdin) {
if (args.stateless_rpc) {
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index d6d2dabeca..d77ce7aeb3 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -939,9 +939,12 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
mark = '*';
else
mark = '+';
- printf("%s%c%s",
- get_color_code(i),
- mark, get_color_reset_code());
+ if (mark == ' ')
+ putchar(mark);
+ else
+ printf("%s%c%s",
+ get_color_code(i),
+ mark, get_color_reset_code());
}
putchar(' ');
}
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 8106b03a6b..0e0b9fb95b 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -71,9 +71,11 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)
uint32_t off;
} *entries;
ALLOC_ARRAY(entries, nr);
- for (i = 0; i < nr; i++)
+ for (i = 0; i < nr; i++) {
if (fread(entries[i].oid.hash, hashsz, 1, stdin) != 1)
die("unable to read sha1 %u/%u", i, nr);
+ entries[i].oid.algo = hash_algo_by_ptr(the_hash_algo);
+ }
for (i = 0; i < nr; i++)
if (fread(&entries[i].crc, 4, 1, stdin) != 1)
die("unable to read crc %u/%u", i, nr);
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index d7da50ada5..8ba9f13787 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -14,6 +14,7 @@
#include "unpack-trees.h"
#include "wt-status.h"
#include "quote.h"
+#include "sparse-index.h"
static const char *empty_base = "";
@@ -110,6 +111,8 @@ static int update_working_directory(struct pattern_list *pl)
if (is_index_unborn(r->index))
return UPDATE_SPARSITY_SUCCESS;
+ r->index->sparse_checkout_patterns = pl;
+
memset(&o, 0, sizeof(o));
o.verbose_update = isatty(2);
o.update = 1;
@@ -138,6 +141,7 @@ static int update_working_directory(struct pattern_list *pl)
else
rollback_lock_file(&lock_file);
+ r->index->sparse_checkout_patterns = NULL;
return result;
}
@@ -276,16 +280,20 @@ static int set_config(enum sparse_checkout_mode mode)
"core.sparseCheckoutCone",
mode == MODE_CONE_PATTERNS ? "true" : NULL);
+ if (mode == MODE_NO_PATTERNS)
+ set_sparse_index_config(the_repository, 0);
+
return 0;
}
static char const * const builtin_sparse_checkout_init_usage[] = {
- N_("git sparse-checkout init [--cone]"),
+ N_("git sparse-checkout init [--cone] [--[no-]sparse-index]"),
NULL
};
static struct sparse_checkout_init_opts {
int cone_mode;
+ int sparse_index;
} init_opts;
static int sparse_checkout_init(int argc, const char **argv)
@@ -300,11 +308,15 @@ static int sparse_checkout_init(int argc, const char **argv)
static struct option builtin_sparse_checkout_init_options[] = {
OPT_BOOL(0, "cone", &init_opts.cone_mode,
N_("initialize the sparse-checkout in cone mode")),
+ OPT_BOOL(0, "sparse-index", &init_opts.sparse_index,
+ N_("toggle the use of a sparse index")),
OPT_END(),
};
repo_read_index(the_repository);
+ init_opts.sparse_index = -1;
+
argc = parse_options(argc, argv, NULL,
builtin_sparse_checkout_init_options,
builtin_sparse_checkout_init_usage, 0);
@@ -323,10 +335,20 @@ static int sparse_checkout_init(int argc, const char **argv)
sparse_filename = get_sparse_checkout_filename();
res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
+ if (init_opts.sparse_index >= 0) {
+ if (set_sparse_index_config(the_repository, init_opts.sparse_index) < 0)
+ die(_("failed to modify sparse-index config"));
+
+ /* force an index rewrite */
+ repo_read_index(the_repository);
+ the_repository->index->updated_workdir = 1;
+ }
+
+ core_apply_sparse_checkout = 1;
+
/* If we already have a sparse-checkout file, use it. */
if (res >= 0) {
free(sparse_filename);
- core_apply_sparse_checkout = 1;
return update_working_directory(NULL);
}
@@ -348,6 +370,7 @@ static int sparse_checkout_init(int argc, const char **argv)
add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
strbuf_addstr(&pattern, "!/*/");
add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0);
+ pl.use_cone_patterns = init_opts.cone_mode;
return write_patterns_and_update(&pl);
}
@@ -357,10 +380,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
struct pattern_entry *e = xmalloc(sizeof(*e));
e->patternlen = path->len;
e->pattern = strbuf_detach(path, NULL);
- hashmap_entry_init(&e->ent,
- ignore_case ?
- strihash(e->pattern) :
- strhash(e->pattern));
+ hashmap_entry_init(&e->ent, fspathhash(e->pattern));
hashmap_add(&pl->recursive_hashmap, &e->ent);
@@ -376,10 +396,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
e = xmalloc(sizeof(struct pattern_entry));
e->patternlen = newlen;
e->pattern = xstrndup(oldpattern, newlen);
- hashmap_entry_init(&e->ent,
- ignore_case ?
- strihash(e->pattern) :
- strhash(e->pattern));
+ hashmap_entry_init(&e->ent, fspathhash(e->pattern));
if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
hashmap_add(&pl->parent_hashmap, &e->ent);
@@ -517,19 +534,18 @@ static int modify_pattern_list(int argc, const char **argv, enum modify_type m)
{
int result;
int changed_config = 0;
- struct pattern_list pl;
- memset(&pl, 0, sizeof(pl));
+ struct pattern_list *pl = xcalloc(1, sizeof(*pl));
switch (m) {
case ADD:
if (core_sparse_checkout_cone)
- add_patterns_cone_mode(argc, argv, &pl);
+ add_patterns_cone_mode(argc, argv, pl);
else
- add_patterns_literal(argc, argv, &pl);
+ add_patterns_literal(argc, argv, pl);
break;
case REPLACE:
- add_patterns_from_input(&pl, argc, argv);
+ add_patterns_from_input(pl, argc, argv);
break;
}
@@ -539,12 +555,13 @@ static int modify_pattern_list(int argc, const char **argv, enum modify_type m)
changed_config = 1;
}
- result = write_patterns_and_update(&pl);
+ result = write_patterns_and_update(pl);
if (result && changed_config)
set_config(MODE_NO_PATTERNS);
- clear_pattern_list(&pl);
+ clear_pattern_list(pl);
+ free(pl);
return result;
}
@@ -614,6 +631,9 @@ static int sparse_checkout_disable(int argc, const char **argv)
strbuf_addstr(&match_all, "/*");
add_pattern(strbuf_detach(&match_all, NULL), empty_base, 0, &pl, 0);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.sparse_index = 0;
+
if (update_working_directory(&pl))
die(_("error while refreshing working directory"));
diff --git a/builtin/stash.c b/builtin/stash.c
index c56fed3354..8f42360ca9 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -26,7 +26,7 @@ static const char * const git_stash_usage[] = {
N_("git stash drop [-q|--quiet] [<stash>]"),
N_("git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
N_("git stash branch <branchname> [<stash>]"),
- N_("git stash clear"),
+ "git stash clear",
N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
" [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
@@ -67,7 +67,7 @@ static const char * const git_stash_branch_usage[] = {
};
static const char * const git_stash_clear_usage[] = {
- N_("git stash clear"),
+ "git stash clear",
NULL
};
@@ -761,7 +761,7 @@ static int list_stash(int argc, const char **argv, const char *prefix)
cp.git_cmd = 1;
strvec_pushl(&cp.args, "log", "--format=%gd: %gs", "-g",
- "--first-parent", "-m", NULL);
+ "--first-parent", NULL);
strvec_pushv(&cp.args, argv);
strvec_push(&cp.args, ref_stash);
strvec_push(&cp.args, "--");
@@ -833,7 +833,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
UNTRACKED_NONE,
UNTRACKED_INCLUDE,
UNTRACKED_ONLY
- } show_untracked = UNTRACKED_NONE;
+ } show_untracked = show_include_untracked ? UNTRACKED_INCLUDE : UNTRACKED_NONE;
struct option options[] = {
OPT_SET_INT('u', "include-untracked", &show_untracked,
N_("include untracked files in the stash"),
@@ -876,9 +876,6 @@ static int show_stash(int argc, const char **argv, const char *prefix)
if (show_patch)
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
- if (show_include_untracked)
- show_untracked = UNTRACKED_INCLUDE;
-
if (!show_stat && !show_patch) {
free_stash_info(&info);
return 0;
@@ -902,10 +899,14 @@ static int show_stash(int argc, const char **argv, const char *prefix)
diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt);
break;
case UNTRACKED_ONLY:
- diff_root_tree_oid(&info.u_tree, "", &rev.diffopt);
+ if (info.has_u)
+ diff_root_tree_oid(&info.u_tree, "", &rev.diffopt);
break;
case UNTRACKED_INCLUDE:
- diff_include_untracked(&info, &rev.diffopt);
+ if (info.has_u)
+ diff_include_untracked(&info, &rev.diffopt);
+ else
+ diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt);
break;
}
log_tree_diff_flush(&rev);
@@ -990,9 +991,8 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
{
int i;
int found = 0;
- struct dir_struct dir;
+ struct dir_struct dir = DIR_INIT;
- dir_init(&dir);
if (include_untracked != INCLUDE_ALL_FILES)
setup_standard_excludes(&dir);
@@ -1412,6 +1412,8 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
int i;
char *ps_matched = xcalloc(ps->nr, 1);
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++)
ce_path_match(&the_index, active_cache[i], ps,
ps_matched);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9d505a6329..ef2776a9e4 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -19,7 +19,6 @@
#include "diffcore.h"
#include "diff.h"
#include "object-store.h"
-#include "dir.h"
#include "advice.h"
#define OPT_QUIET (1 << 0)
@@ -188,11 +187,13 @@ static char *relative_url(const char *remote_url,
out = xstrdup(sb.buf + 2);
else
out = xstrdup(sb.buf);
- strbuf_reset(&sb);
- if (!up_path || !is_relative)
+ if (!up_path || !is_relative) {
+ strbuf_release(&sb);
return out;
+ }
+ strbuf_reset(&sb);
strbuf_addf(&sb, "%s%s", up_path, out);
free(out);
return strbuf_detach(&sb, NULL);
@@ -426,7 +427,8 @@ static int module_list(int argc, const char **argv, const char *prefix)
const struct cache_entry *ce = list.entries[i];
if (ce_stage(ce))
- printf("%06o %s U\t", ce->ce_mode, oid_to_hex(&null_oid));
+ printf("%06o %s U\t", ce->ce_mode,
+ oid_to_hex(null_oid()));
else
printf("%06o %s %d\t", ce->ce_mode,
oid_to_hex(&ce->oid), ce_stage(ce));
@@ -466,7 +468,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
displaypath = get_submodule_displaypath(path, info->prefix);
- sub = submodule_from_path(the_repository, &null_oid, path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
if (!sub)
die(_("No url found for submodule path '%s' in .gitmodules"),
@@ -623,7 +625,7 @@ static void init_submodule(const char *path, const char *prefix,
displaypath = get_submodule_displaypath(path, prefix);
- sub = submodule_from_path(the_repository, &null_oid, path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
if (!sub)
die(_("No url found for submodule path '%s' in .gitmodules"),
@@ -783,14 +785,14 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
struct strbuf buf = STRBUF_INIT;
const char *git_dir;
- if (!submodule_from_path(the_repository, &null_oid, path))
+ if (!submodule_from_path(the_repository, null_oid(), path))
die(_("no submodule mapping found in .gitmodules for path '%s'"),
path);
displaypath = get_submodule_displaypath(path, prefix);
if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
- print_status(flags, 'U', path, &null_oid, displaypath);
+ print_status(flags, 'U', path, null_oid(), displaypath);
goto cleanup;
}
@@ -916,7 +918,7 @@ static int module_name(int argc, const char **argv, const char *prefix)
if (argc != 2)
usage(_("git submodule--helper name <path>"));
- sub = submodule_from_path(the_repository, &null_oid, argv[1]);
+ sub = submodule_from_path(the_repository, null_oid(), argv[1]);
if (!sub)
die(_("no submodule mapping found in .gitmodules for path '%s'"),
@@ -1040,7 +1042,7 @@ static void generate_submodule_summary(struct summary_cb *info,
char *errmsg = NULL;
int total_commits = -1;
- if (!info->cached && oideq(&p->oid_dst, &null_oid)) {
+ if (!info->cached && oideq(&p->oid_dst, null_oid())) {
if (S_ISGITLINK(p->mod_dst)) {
struct ref_store *refs = get_submodule_ref_store(p->sm_path);
if (refs)
@@ -1177,7 +1179,7 @@ static void prepare_submodule_summary(struct summary_cb *info,
if (info->for_status && p->status != 'A' &&
(sub = submodule_from_path(the_repository,
- &null_oid, p->sm_path))) {
+ null_oid(), p->sm_path))) {
char *config_key = NULL;
const char *value;
int ignore_all = 0;
@@ -1299,7 +1301,7 @@ static int module_summary(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "cached", &cached,
N_("use the commit stored in the index instead of the submodule HEAD")),
OPT_BOOL(0, "files", &files,
- N_("to compare the commit in the index with that in the submodule HEAD")),
+ N_("compare the commit in the index with that in the submodule HEAD")),
OPT_BOOL(0, "for-status", &for_status,
N_("skip submodules with 'ignore_config' value set to 'all'")),
OPT_INTEGER('n', "summary-limit", &summary_limit,
@@ -1373,7 +1375,7 @@ static void sync_submodule(const char *path, const char *prefix,
if (!is_submodule_active(the_repository, path))
return;
- sub = submodule_from_path(the_repository, &null_oid, path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
if (sub && sub->url) {
if (starts_with_dot_dot_slash(sub->url) ||
@@ -1525,7 +1527,7 @@ static void deinit_submodule(const char *path, const char *prefix,
struct strbuf sb_config = STRBUF_INIT;
char *sub_git_dir = xstrfmt("%s/.git", path);
- sub = submodule_from_path(the_repository, &null_oid, path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
if (!sub || !sub->name)
goto cleanup;
@@ -1657,45 +1659,20 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
return 0;
}
-static int clone_submodule(const char *path, const char *gitdir, const char *url,
- const char *depth, struct string_list *reference, int dissociate,
- int quiet, int progress, int single_branch)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
-
- strvec_push(&cp.args, "clone");
- strvec_push(&cp.args, "--no-checkout");
- if (quiet)
- strvec_push(&cp.args, "--quiet");
- if (progress)
- strvec_push(&cp.args, "--progress");
- if (depth && *depth)
- strvec_pushl(&cp.args, "--depth", depth, NULL);
- if (reference->nr) {
- struct string_list_item *item;
- for_each_string_list_item(item, reference)
- strvec_pushl(&cp.args, "--reference",
- item->string, NULL);
- }
- if (dissociate)
- strvec_push(&cp.args, "--dissociate");
- if (gitdir && *gitdir)
- strvec_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
- if (single_branch >= 0)
- strvec_push(&cp.args, single_branch ?
- "--single-branch" :
- "--no-single-branch");
-
- strvec_push(&cp.args, "--");
- strvec_push(&cp.args, url);
- strvec_push(&cp.args, path);
-
- cp.git_cmd = 1;
- prepare_submodule_repo_env(&cp.env_array);
- cp.no_stdin = 1;
-
- return run_command(&cp);
-}
+struct module_clone_data {
+ const char *prefix;
+ const char *path;
+ const char *name;
+ const char *url;
+ const char *depth;
+ struct string_list reference;
+ unsigned int quiet: 1;
+ unsigned int progress: 1;
+ unsigned int dissociate: 1;
+ unsigned int require_init: 1;
+ int single_branch;
+};
+#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
struct submodule_alternate_setup {
const char *submodule_name;
@@ -1801,37 +1778,128 @@ static void prepare_possible_alternates(const char *sm_name,
free(error_strategy);
}
-static int module_clone(int argc, const char **argv, const char *prefix)
+static int clone_submodule(struct module_clone_data *clone_data)
{
- const char *name = NULL, *url = NULL, *depth = NULL;
- int quiet = 0;
- int progress = 0;
- char *p, *path = NULL, *sm_gitdir;
- struct strbuf sb = STRBUF_INIT;
- struct string_list reference = STRING_LIST_INIT_NODUP;
- int dissociate = 0, require_init = 0;
+ char *p, *sm_gitdir;
char *sm_alternate = NULL, *error_strategy = NULL;
- int single_branch = -1;
+ struct strbuf sb = STRBUF_INIT;
+ struct child_process cp = CHILD_PROCESS_INIT;
+
+ strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), clone_data->name);
+ sm_gitdir = absolute_pathdup(sb.buf);
+ strbuf_reset(&sb);
+
+ if (!is_absolute_path(clone_data->path)) {
+ strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_data->path);
+ clone_data->path = strbuf_detach(&sb, NULL);
+ } else {
+ clone_data->path = xstrdup(clone_data->path);
+ }
+
+ if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
+ die(_("refusing to create/use '%s' in another submodule's "
+ "git dir"), sm_gitdir);
+
+ if (!file_exists(sm_gitdir)) {
+ if (safe_create_leading_directories_const(sm_gitdir) < 0)
+ die(_("could not create directory '%s'"), sm_gitdir);
+
+ prepare_possible_alternates(clone_data->name, &clone_data->reference);
+
+ strvec_push(&cp.args, "clone");
+ strvec_push(&cp.args, "--no-checkout");
+ if (clone_data->quiet)
+ strvec_push(&cp.args, "--quiet");
+ if (clone_data->progress)
+ strvec_push(&cp.args, "--progress");
+ if (clone_data->depth && *(clone_data->depth))
+ strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
+ if (clone_data->reference.nr) {
+ struct string_list_item *item;
+ for_each_string_list_item(item, &clone_data->reference)
+ strvec_pushl(&cp.args, "--reference",
+ item->string, NULL);
+ }
+ if (clone_data->dissociate)
+ strvec_push(&cp.args, "--dissociate");
+ if (sm_gitdir && *sm_gitdir)
+ strvec_pushl(&cp.args, "--separate-git-dir", sm_gitdir, NULL);
+ if (clone_data->single_branch >= 0)
+ strvec_push(&cp.args, clone_data->single_branch ?
+ "--single-branch" :
+ "--no-single-branch");
+
+ strvec_push(&cp.args, "--");
+ strvec_push(&cp.args, clone_data->url);
+ strvec_push(&cp.args, clone_data->path);
+
+ cp.git_cmd = 1;
+ prepare_submodule_repo_env(&cp.env_array);
+ cp.no_stdin = 1;
+
+ if(run_command(&cp))
+ die(_("clone of '%s' into submodule path '%s' failed"),
+ clone_data->url, clone_data->path);
+ } else {
+ if (clone_data->require_init && !access(clone_data->path, X_OK) &&
+ !is_empty_dir(clone_data->path))
+ die(_("directory not empty: '%s'"), clone_data->path);
+ if (safe_create_leading_directories_const(clone_data->path) < 0)
+ die(_("could not create directory '%s'"), clone_data->path);
+ strbuf_addf(&sb, "%s/index", sm_gitdir);
+ unlink_or_warn(sb.buf);
+ strbuf_reset(&sb);
+ }
+
+ connect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);
+
+ p = git_pathdup_submodule(clone_data->path, "config");
+ if (!p)
+ die(_("could not get submodule directory for '%s'"), clone_data->path);
+
+ /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
+ git_config_get_string("submodule.alternateLocation", &sm_alternate);
+ if (sm_alternate)
+ git_config_set_in_file(p, "submodule.alternateLocation",
+ sm_alternate);
+ git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+ if (error_strategy)
+ git_config_set_in_file(p, "submodule.alternateErrorStrategy",
+ error_strategy);
+
+ free(sm_alternate);
+ free(error_strategy);
+
+ strbuf_release(&sb);
+ free(sm_gitdir);
+ free(p);
+ return 0;
+}
+
+static int module_clone(int argc, const char **argv, const char *prefix)
+{
+ int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
+ struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
struct option module_clone_options[] = {
- OPT_STRING(0, "prefix", &prefix,
+ OPT_STRING(0, "prefix", &clone_data.prefix,
N_("path"),
N_("alternative anchor for relative paths")),
- OPT_STRING(0, "path", &path,
+ OPT_STRING(0, "path", &clone_data.path,
N_("path"),
N_("where the new submodule will be cloned to")),
- OPT_STRING(0, "name", &name,
+ OPT_STRING(0, "name", &clone_data.name,
N_("string"),
N_("name of the new submodule")),
- OPT_STRING(0, "url", &url,
+ OPT_STRING(0, "url", &clone_data.url,
N_("string"),
N_("url where to clone the submodule from")),
- OPT_STRING_LIST(0, "reference", &reference,
+ OPT_STRING_LIST(0, "reference", &clone_data.reference,
N_("repo"),
N_("reference repository")),
OPT_BOOL(0, "dissociate", &dissociate,
N_("use --reference only while cloning")),
- OPT_STRING(0, "depth", &depth,
+ OPT_STRING(0, "depth", &clone_data.depth,
N_("string"),
N_("depth for shallow clones")),
OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
@@ -1839,7 +1907,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
N_("force cloning progress")),
OPT_BOOL(0, "require-init", &require_init,
N_("disallow cloning into non-empty directory")),
- OPT_BOOL(0, "single-branch", &single_branch,
+ OPT_BOOL(0, "single-branch", &clone_data.single_branch,
N_("clone only one branch, HEAD or --branch")),
OPT_END()
};
@@ -1855,67 +1923,16 @@ static int module_clone(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_clone_options,
git_submodule_helper_usage, 0);
- if (argc || !url || !path || !*path)
+ clone_data.dissociate = !!dissociate;
+ clone_data.quiet = !!quiet;
+ clone_data.progress = !!progress;
+ clone_data.require_init = !!require_init;
+
+ if (argc || !clone_data.url || !clone_data.path || !*(clone_data.path))
usage_with_options(git_submodule_helper_usage,
module_clone_options);
- strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
- sm_gitdir = absolute_pathdup(sb.buf);
- strbuf_reset(&sb);
-
- if (!is_absolute_path(path)) {
- strbuf_addf(&sb, "%s/%s", get_git_work_tree(), path);
- path = strbuf_detach(&sb, NULL);
- } else
- path = xstrdup(path);
-
- if (validate_submodule_git_dir(sm_gitdir, name) < 0)
- die(_("refusing to create/use '%s' in another submodule's "
- "git dir"), sm_gitdir);
-
- if (!file_exists(sm_gitdir)) {
- if (safe_create_leading_directories_const(sm_gitdir) < 0)
- die(_("could not create directory '%s'"), sm_gitdir);
-
- prepare_possible_alternates(name, &reference);
-
- if (clone_submodule(path, sm_gitdir, url, depth, &reference, dissociate,
- quiet, progress, single_branch))
- die(_("clone of '%s' into submodule path '%s' failed"),
- url, path);
- } else {
- if (require_init && !access(path, X_OK) && !is_empty_dir(path))
- die(_("directory not empty: '%s'"), path);
- if (safe_create_leading_directories_const(path) < 0)
- die(_("could not create directory '%s'"), path);
- strbuf_addf(&sb, "%s/index", sm_gitdir);
- unlink_or_warn(sb.buf);
- strbuf_reset(&sb);
- }
-
- connect_work_tree_and_git_dir(path, sm_gitdir, 0);
-
- p = git_pathdup_submodule(path, "config");
- if (!p)
- die(_("could not get submodule directory for '%s'"), path);
-
- /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
- git_config_get_string("submodule.alternateLocation", &sm_alternate);
- if (sm_alternate)
- git_config_set_in_file(p, "submodule.alternateLocation",
- sm_alternate);
- git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
- if (error_strategy)
- git_config_set_in_file(p, "submodule.alternateErrorStrategy",
- error_strategy);
-
- free(sm_alternate);
- free(error_strategy);
-
- strbuf_release(&sb);
- free(sm_gitdir);
- free(path);
- free(p);
+ clone_submodule(&clone_data);
return 0;
}
@@ -1925,7 +1942,7 @@ static void determine_submodule_update_strategy(struct repository *r,
const char *update,
struct submodule_update_strategy *out)
{
- const struct submodule *sub = submodule_from_path(r, &null_oid, path);
+ const struct submodule *sub = submodule_from_path(r, null_oid(), path);
char *key;
const char *val;
@@ -2077,7 +2094,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
goto cleanup;
}
- sub = submodule_from_path(the_repository, &null_oid, ce->name);
+ sub = submodule_from_path(the_repository, null_oid(), ce->name);
if (suc->recursive_prefix)
displaypath = relative_path(suc->recursive_prefix,
@@ -2395,7 +2412,7 @@ static const char *remote_submodule_branch(const char *path)
const char *branch = NULL;
char *key;
- sub = submodule_from_path(the_repository, &null_oid, path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
if (!sub)
return NULL;
@@ -2533,7 +2550,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
path = argv[1];
- sub = submodule_from_path(the_repository, &null_oid, path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
if (!sub)
BUG("We could get the submodule handle before?");
@@ -2744,6 +2761,181 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
return !!ret;
}
+struct add_data {
+ const char *prefix;
+ const char *branch;
+ const char *reference_path;
+ const char *sm_path;
+ const char *sm_name;
+ const char *repo;
+ const char *realrepo;
+ int depth;
+ unsigned int force: 1;
+ unsigned int quiet: 1;
+ unsigned int progress: 1;
+ unsigned int dissociate: 1;
+};
+#define ADD_DATA_INIT { .depth = -1 }
+
+static void show_fetch_remotes(FILE *output, const char *git_dir_path)
+{
+ struct child_process cp_remote = CHILD_PROCESS_INIT;
+ struct strbuf sb_remote_out = STRBUF_INIT;
+
+ cp_remote.git_cmd = 1;
+ strvec_pushf(&cp_remote.env_array,
+ "GIT_DIR=%s", git_dir_path);
+ strvec_push(&cp_remote.env_array, "GIT_WORK_TREE=.");
+ strvec_pushl(&cp_remote.args, "remote", "-v", NULL);
+ if (!capture_command(&cp_remote, &sb_remote_out, 0)) {
+ char *next_line;
+ char *line = sb_remote_out.buf;
+ while ((next_line = strchr(line, '\n')) != NULL) {
+ size_t len = next_line - line;
+ if (strip_suffix_mem(line, &len, " (fetch)"))
+ fprintf(output, " %.*s\n", (int)len, line);
+ line = next_line + 1;
+ }
+ }
+
+ strbuf_release(&sb_remote_out);
+}
+
+static int add_submodule(const struct add_data *add_data)
+{
+ char *submod_gitdir_path;
+ struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
+
+ /* perhaps the path already exists and is already a git repo, else clone it */
+ if (is_directory(add_data->sm_path)) {
+ struct strbuf sm_path = STRBUF_INIT;
+ strbuf_addstr(&sm_path, add_data->sm_path);
+ submod_gitdir_path = xstrfmt("%s/.git", add_data->sm_path);
+ if (is_nonbare_repository_dir(&sm_path))
+ printf(_("Adding existing repo at '%s' to the index\n"),
+ add_data->sm_path);
+ else
+ die(_("'%s' already exists and is not a valid git repo"),
+ add_data->sm_path);
+ strbuf_release(&sm_path);
+ free(submod_gitdir_path);
+ } else {
+ struct child_process cp = CHILD_PROCESS_INIT;
+ submod_gitdir_path = xstrfmt(".git/modules/%s", add_data->sm_name);
+
+ if (is_directory(submod_gitdir_path)) {
+ if (!add_data->force) {
+ fprintf(stderr, _("A git directory for '%s' is found "
+ "locally with remote(s):"),
+ add_data->sm_name);
+ show_fetch_remotes(stderr, submod_gitdir_path);
+ free(submod_gitdir_path);
+ die(_("If you want to reuse this local git "
+ "directory instead of cloning again from\n"
+ " %s\n"
+ "use the '--force' option. If the local git "
+ "directory is not the correct repo\n"
+ "or if you are unsure what this means, choose "
+ "another name with the '--name' option.\n"),
+ add_data->realrepo);
+ } else {
+ printf(_("Reactivating local git directory for "
+ "submodule '%s'\n"), add_data->sm_name);
+ }
+ }
+ free(submod_gitdir_path);
+
+ clone_data.prefix = add_data->prefix;
+ clone_data.path = add_data->sm_path;
+ clone_data.name = add_data->sm_name;
+ clone_data.url = add_data->realrepo;
+ clone_data.quiet = add_data->quiet;
+ clone_data.progress = add_data->progress;
+ if (add_data->reference_path)
+ string_list_append(&clone_data.reference,
+ xstrdup(add_data->reference_path));
+ clone_data.dissociate = add_data->dissociate;
+ if (add_data->depth >= 0)
+ clone_data.depth = xstrfmt("%d", add_data->depth);
+
+ if (clone_submodule(&clone_data))
+ return -1;
+
+ prepare_submodule_repo_env(&cp.env_array);
+ cp.git_cmd = 1;
+ cp.dir = add_data->sm_path;
+ strvec_pushl(&cp.args, "checkout", "-f", "-q", NULL);
+
+ if (add_data->branch) {
+ strvec_pushl(&cp.args, "-B", add_data->branch, NULL);
+ strvec_pushf(&cp.args, "origin/%s", add_data->branch);
+ }
+
+ if (run_command(&cp))
+ die(_("unable to checkout submodule '%s'"), add_data->sm_path);
+ }
+ return 0;
+}
+
+static int add_clone(int argc, const char **argv, const char *prefix)
+{
+ int force = 0, quiet = 0, dissociate = 0, progress = 0;
+ struct add_data add_data = ADD_DATA_INIT;
+
+ struct option options[] = {
+ OPT_STRING('b', "branch", &add_data.branch,
+ N_("branch"),
+ N_("branch of repository to checkout on cloning")),
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT_STRING(0, "path", &add_data.sm_path,
+ N_("path"),
+ N_("where the new submodule will be cloned to")),
+ OPT_STRING(0, "name", &add_data.sm_name,
+ N_("string"),
+ N_("name of the new submodule")),
+ OPT_STRING(0, "url", &add_data.realrepo,
+ N_("string"),
+ N_("url where to clone the submodule from")),
+ OPT_STRING(0, "reference", &add_data.reference_path,
+ N_("repo"),
+ N_("reference repository")),
+ OPT_BOOL(0, "dissociate", &dissociate,
+ N_("use --reference only while cloning")),
+ OPT_INTEGER(0, "depth", &add_data.depth,
+ N_("depth for shallow clones")),
+ OPT_BOOL(0, "progress", &progress,
+ N_("force cloning progress")),
+ OPT__FORCE(&force, N_("allow adding an otherwise ignored submodule path"),
+ PARSE_OPT_NOCOMPLETE),
+ OPT__QUIET(&quiet, "suppress output for cloning a submodule"),
+ OPT_END()
+ };
+
+ const char *const usage[] = {
+ N_("git submodule--helper add-clone [<options>...] "
+ "--url <url> --path <path> --name <name>"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+ if (argc != 0)
+ usage_with_options(usage, options);
+
+ add_data.prefix = prefix;
+ add_data.progress = !!progress;
+ add_data.dissociate = !!dissociate;
+ add_data.force = !!force;
+ add_data.quiet = !!quiet;
+
+ if (add_submodule(&add_data))
+ return 1;
+
+ return 0;
+}
+
#define SUPPORT_SUPER_PREFIX (1<<0)
struct cmd_struct {
@@ -2756,6 +2948,7 @@ static struct cmd_struct commands[] = {
{"list", module_list, 0},
{"name", module_name, 0},
{"clone", module_clone, 0},
+ {"add-clone", add_clone, 0},
{"update-module-mode", module_update_module_mode, 0},
{"update-clone", update_clone, 0},
{"ensure-core-worktree", ensure_core_worktree, 0},
diff --git a/builtin/tag.c b/builtin/tag.c
index d403417b56..065b6bf093 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -39,6 +39,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
struct ref_format *format)
{
struct ref_array array;
+ struct strbuf output = STRBUF_INIT;
+ struct strbuf err = STRBUF_INIT;
char *to_free = NULL;
int i;
@@ -63,8 +65,17 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
filter_refs(&array, filter, FILTER_REFS_TAGS);
ref_array_sort(sorting, &array);
- for (i = 0; i < array.nr; i++)
- show_ref_array_item(array.items[i], format);
+ for (i = 0; i < array.nr; i++) {
+ strbuf_reset(&output);
+ strbuf_reset(&err);
+ if (format_ref_array_item(array.items[i], format, &output, &err))
+ die("%s", err.buf);
+ fwrite(output.buf, 1, output.len, stdout);
+ putchar('\n');
+ }
+
+ strbuf_release(&err);
+ strbuf_release(&output);
ref_array_clear(&array);
free(to_free);
@@ -135,7 +146,7 @@ static int verify_tag(const char *name, const char *ref,
const struct object_id *oid, void *cb_data)
{
int flags;
- const struct ref_format *format = cb_data;
+ struct ref_format *format = cb_data;
flags = GPG_VERIFY_VERBOSE;
if (format->format)
@@ -282,9 +293,7 @@ static void create_tag(const struct object_id *object, const char *object_ref,
/* write the template message before editing: */
path = git_pathdup("TAG_EDITMSG");
- fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (fd < 0)
- die_errno(_("could not create file '%s'"), path);
+ fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (opt->message_given) {
write_or_die(fd, buf->buf, buf->len);
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 4a70b17f8f..4a9466295b 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -355,7 +355,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
struct object_id base_oid;
if (type == OBJ_REF_DELTA) {
- hashcpy(base_oid.hash, fill(the_hash_algo->rawsz));
+ oidread(&base_oid, fill(the_hash_algo->rawsz));
use(the_hash_algo->rawsz);
delta_data = get_data(delta_size);
if (dry_run || !delta_data) {
@@ -421,7 +421,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
* has not been resolved yet.
*/
oidclr(&obj_list[nr].oid);
- add_delta_to_list(nr, &null_oid, base_offset, delta_data, delta_size);
+ add_delta_to_list(nr, null_oid(), base_offset,
+ delta_data, delta_size);
return;
}
}
@@ -576,7 +577,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
the_hash_algo->init_fn(&ctx);
unpack_all();
the_hash_algo->update_fn(&ctx, buffer, offset);
- the_hash_algo->final_fn(oid.hash, &ctx);
+ the_hash_algo->final_oid_fn(&oid, &ctx);
if (strict) {
write_rest();
if (fsck_finish(&fsck_options))
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 79087bccea..187203e8bb 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -95,9 +95,7 @@ static int create_file(const char *path)
{
int fd;
path = get_mtime_path(path);
- fd = open(path, O_CREAT | O_RDWR, 0644);
- if (fd < 0)
- die_errno(_("failed to create file %s"), path);
+ fd = xopen(path, O_CREAT | O_RDWR, 0644);
return fd;
}
@@ -745,6 +743,8 @@ static int do_reupdate(int ac, const char **av,
*/
has_head = 0;
redo:
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(&the_index);
for (pos = 0; pos < active_nr; pos++) {
const struct cache_entry *ce = active_cache[pos];
struct cache_entry *old = NULL;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 8771453493..0d0a80da61 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -30,7 +30,7 @@ struct add_opts {
int detach;
int quiet;
int checkout;
- int keep_locked;
+ const char *keep_locked;
};
static int show_only;
@@ -118,10 +118,8 @@ static void prune_worktrees(void)
struct dirent *d;
if (!dir)
return;
- while ((d = readdir(dir)) != NULL) {
+ while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
char *path;
- if (is_dot_or_dotdot(d->d_name))
- continue;
strbuf_reset(&reason);
if (should_prune_worktree(d->d_name, &reason, &path, expire))
prune_worktree(d->d_name, reason.buf);
@@ -304,10 +302,10 @@ static int add_worktree(const char *path, const char *refname,
* after the preparation is over.
*/
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
- if (!opts->keep_locked)
- write_file(sb.buf, "initializing");
+ if (opts->keep_locked)
+ write_file(sb.buf, "%s", opts->keep_locked);
else
- write_file(sb.buf, "added with --lock");
+ write_file(sb.buf, _("initializing"));
strbuf_addf(&sb_git, "%s/.git", path);
if (safe_create_leading_directories_const(sb_git.buf))
@@ -331,7 +329,7 @@ static int add_worktree(const char *path, const char *refname,
*/
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
- write_file(sb.buf, "%s", oid_to_hex(&null_oid));
+ write_file(sb.buf, "%s", oid_to_hex(null_oid()));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@@ -394,7 +392,7 @@ done:
cp.argv = NULL;
cp.trace2_hook_name = "post-checkout";
strvec_pushl(&cp.args, absolute_path(hook),
- oid_to_hex(&null_oid),
+ oid_to_hex(null_oid()),
oid_to_hex(&commit->object.oid),
"1", NULL);
ret = run_command(&cp);
@@ -477,6 +475,8 @@ static int add(int ac, const char **av, const char *prefix)
const char *branch;
const char *new_branch = NULL;
const char *opt_track = NULL;
+ const char *lock_reason = NULL;
+ int keep_locked = 0;
struct option options[] = {
OPT__FORCE(&opts.force,
N_("checkout <branch> even if already checked out in other worktree"),
@@ -487,7 +487,9 @@ static int add(int ac, const char **av, const char *prefix)
N_("create or reset a branch")),
OPT_BOOL('d', "detach", &opts.detach, N_("detach HEAD at named commit")),
OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
- OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
+ OPT_BOOL(0, "lock", &keep_locked, N_("keep the new working tree locked")),
+ OPT_STRING(0, "reason", &lock_reason, N_("string"),
+ N_("reason for locking")),
OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
OPT_PASSTHRU(0, "track", &opt_track, NULL,
N_("set up tracking mode (see git-branch(1))"),
@@ -502,6 +504,13 @@ static int add(int ac, const char **av, const char *prefix)
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("-b, -B, and --detach are mutually exclusive"));
+ if (lock_reason && !keep_locked)
+ die(_("--reason requires --lock"));
+ if (lock_reason)
+ opts.keep_locked = lock_reason;
+ else if (keep_locked)
+ opts.keep_locked = _("added with --lock");
+
if (ac < 1 || ac > 2)
usage_with_options(worktree_usage, options);