aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c28
-rw-r--r--builtin/apply.c1
-rw-r--r--builtin/bisect--helper.c71
-rw-r--r--builtin/blame.c6
-rw-r--r--builtin/checkout.c2
-rw-r--r--builtin/clone.c6
-rw-r--r--builtin/commit.c11
-rw-r--r--builtin/diff-tree.c3
-rw-r--r--builtin/diff.c2
-rw-r--r--builtin/fast-export.c1
-rw-r--r--builtin/fetch.c17
-rw-r--r--builtin/gc.c6
-rw-r--r--builtin/index-pack.c6
-rw-r--r--builtin/log.c39
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/mailsplit.c2
-rw-r--r--builtin/multi-pack-index.c45
-rw-r--r--builtin/name-rev.c21
-rw-r--r--builtin/pack-objects.c43
-rw-r--r--builtin/pack-redundant.c10
-rw-r--r--builtin/pull.c10
-rw-r--r--builtin/push.c64
-rw-r--r--builtin/rebase.c61
-rw-r--r--builtin/receive-pack.c7
-rw-r--r--builtin/remote.c18
-rw-r--r--builtin/repack.c49
-rw-r--r--builtin/replace.c2
-rw-r--r--builtin/rev-parse.c5
-rw-r--r--builtin/shortlog.c2
-rw-r--r--builtin/show-branch.c4
-rw-r--r--builtin/sparse-checkout.c10
-rw-r--r--builtin/stash.c33
-rw-r--r--builtin/submodule--helper.c142
-rw-r--r--builtin/tag.c4
-rw-r--r--builtin/unpack-objects.c3
-rw-r--r--builtin/update-index.c20
36 files changed, 438 insertions, 318 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 3ffb86a433..145fc9b8f2 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -141,7 +141,16 @@ int add_files_to_cache(const char *prefix,
rev.diffopt.format_callback_data = &data;
rev.diffopt.flags.override_submodule_config = 1;
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
+
+ /*
+ * Use an ODB transaction to optimize adding multiple objects.
+ * This function is invoked from commands other than 'add', which
+ * may not have their own transaction active.
+ */
+ begin_odb_transaction();
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
+ end_odb_transaction();
+
clear_pathspec(&rev.prune_data);
return !!data.add_errors;
}
@@ -236,17 +245,12 @@ int run_add_interactive(const char *revision, const char *patch_mode,
int use_builtin_add_i =
git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
- if (use_builtin_add_i < 0) {
- int experimental;
- if (!git_config_get_bool("add.interactive.usebuiltin",
- &use_builtin_add_i))
- ; /* ok */
- else if (!git_config_get_bool("feature.experimental", &experimental) &&
- experimental)
- use_builtin_add_i = 1;
- }
+ if (use_builtin_add_i < 0 &&
+ git_config_get_bool("add.interactive.usebuiltin",
+ &use_builtin_add_i))
+ use_builtin_add_i = 1;
- if (use_builtin_add_i == 1) {
+ if (use_builtin_add_i != 0) {
enum add_p_mode mode;
if (!patch_mode)
@@ -670,7 +674,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
string_list_clear(&only_match_skip_worktree, 0);
}
- plug_bulk_checkin();
+ begin_odb_transaction();
if (add_renormalize)
exit_status |= renormalize_tracked_files(&pathspec, flags);
@@ -682,7 +686,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (chmod_arg && pathspec.nr)
exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
- unplug_bulk_checkin();
+ end_odb_transaction();
finish:
if (write_locked_index(&the_index, &lock_file,
diff --git a/builtin/apply.c b/builtin/apply.c
index 3f099b9605..555219de40 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,7 +1,6 @@
#include "cache.h"
#include "builtin.h"
#include "parse-options.h"
-#include "lockfile.h"
#include "apply.h"
static const char * const apply_usage[] = {
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 8b2b259ff0..d4eaaa345e 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -329,12 +329,12 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
return 0;
}
-static int mark_good(const char *refname, const struct object_id *oid,
- int flag, void *cb_data)
+static int inc_nr(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
{
- int *m_good = (int *)cb_data;
- *m_good = 0;
- return 1;
+ unsigned int *nr = (unsigned int *)cb_data;
+ (*nr)++;
+ return 0;
}
static const char need_bad_and_good_revision_warning[] =
@@ -384,23 +384,64 @@ static int decide_next(const struct bisect_terms *terms,
vocab_good, vocab_bad, vocab_good, vocab_bad);
}
-static int bisect_next_check(const struct bisect_terms *terms,
- const char *current_term)
+static void bisect_status(struct bisect_state *state,
+ const struct bisect_terms *terms)
{
- int missing_good = 1, missing_bad = 1;
char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
char *good_glob = xstrfmt("%s-*", terms->term_good);
if (ref_exists(bad_ref))
- missing_bad = 0;
+ state->nr_bad = 1;
- for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
- (void *) &missing_good);
+ for_each_glob_ref_in(inc_nr, good_glob, "refs/bisect/",
+ (void *) &state->nr_good);
free(good_glob);
free(bad_ref);
+}
- return decide_next(terms, current_term, missing_good, missing_bad);
+__attribute__((format (printf, 1, 2)))
+static void bisect_log_printf(const char *fmt, ...)
+{
+ struct strbuf buf = STRBUF_INIT;
+ va_list ap;
+
+ va_start(ap, fmt);
+ strbuf_vaddf(&buf, fmt, ap);
+ va_end(ap);
+
+ printf("%s", buf.buf);
+ append_to_file(git_path_bisect_log(), "# %s", buf.buf);
+
+ strbuf_release(&buf);
+}
+
+static void bisect_print_status(const struct bisect_terms *terms)
+{
+ struct bisect_state state = { 0 };
+
+ bisect_status(&state, terms);
+
+ /* If we had both, we'd already be started, and shouldn't get here. */
+ if (state.nr_good && state.nr_bad)
+ return;
+
+ if (!state.nr_good && !state.nr_bad)
+ bisect_log_printf(_("status: waiting for both good and bad commits\n"));
+ else if (state.nr_good)
+ bisect_log_printf(Q_("status: waiting for bad commit, %d good commit known\n",
+ "status: waiting for bad commit, %d good commits known\n",
+ state.nr_good), state.nr_good);
+ else
+ bisect_log_printf(_("status: waiting for good commit(s), bad commit known\n"));
+}
+
+static int bisect_next_check(const struct bisect_terms *terms,
+ const char *current_term)
+{
+ struct bisect_state state = { 0 };
+ bisect_status(&state, terms);
+ return decide_next(terms, current_term, !state.nr_good, !state.nr_bad);
}
static int get_terms(struct bisect_terms *terms)
@@ -433,7 +474,7 @@ static int bisect_terms(struct bisect_terms *terms, const char *option)
if (get_terms(terms))
return error(_("no terms defined"));
- if (option == NULL) {
+ if (!option) {
printf(_("Your current terms are %s for the old state\n"
"and %s for the new state.\n"),
terms->term_good, terms->term_bad);
@@ -606,8 +647,10 @@ static enum bisect_error bisect_next(struct bisect_terms *terms, const char *pre
static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
{
- if (bisect_next_check(terms, NULL))
+ if (bisect_next_check(terms, NULL)) {
+ bisect_print_status(terms);
return BISECT_OK;
+ }
return bisect_next(terms, prefix);
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 8d15b68afc..e33372c56b 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -898,6 +898,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
unsigned int range_i;
long anchor;
const int hexsz = the_hash_algo->hexsz;
+ long num_lines = 0;
setup_default_color_by_age();
git_config(git_blame_config, &output_option);
@@ -1129,7 +1130,10 @@ parse_done:
for (range_i = ranges.nr; range_i > 0; --range_i) {
const struct range *r = &ranges.ranges[range_i - 1];
ent = blame_entry_prepend(ent, r->start, r->end, o);
+ num_lines += (r->end - r->start);
}
+ if (!num_lines)
+ num_lines = sb.num_lines;
o->suspects = ent;
prio_queue_put(&sb.commits, o->commit);
@@ -1158,7 +1162,7 @@ parse_done:
sb.found_guilty_entry = &found_guilty_entry;
sb.found_guilty_entry_data = &pi;
if (show_progress)
- pi.progress = start_delayed_progress(_("Blaming lines"), sb.num_lines);
+ pi.progress = start_delayed_progress(_("Blaming lines"), num_lines);
assign_blame(&sb, opt);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 797681481d..f988936ddf 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -834,7 +834,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
if (ret)
return ret;
o.ancestor = old_branch_info->name;
- if (old_branch_info->name == NULL) {
+ if (!old_branch_info->name) {
strbuf_add_unique_abbrev(&old_commit_shortname,
&old_branch_info->commit->object.oid,
DEFAULT_ABBREV);
diff --git a/builtin/clone.c b/builtin/clone.c
index 5231656379..89a91b0017 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1106,10 +1106,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* apply the remote name provided by --origin only after this second
* call to git_config, to ensure it overrides all config-based values.
*/
- if (option_origin != NULL)
+ if (option_origin) {
+ free(remote_name);
remote_name = xstrdup(option_origin);
+ }
- if (remote_name == NULL)
+ if (!remote_name)
remote_name = xstrdup("origin");
if (!valid_remote_name(remote_name))
diff --git a/builtin/commit.c b/builtin/commit.c
index 009a1de0a3..9bbc7f8075 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -861,7 +861,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
}
s->fp = fopen_for_writing(git_path_commit_editmsg());
- if (s->fp == NULL)
+ if (!s->fp)
die_errno(_("could not open '%s'"), git_path_commit_editmsg());
/* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
@@ -1687,6 +1687,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
struct strbuf err = STRBUF_INIT;
+ int ret = 0;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_commit_usage, builtin_commit_options);
@@ -1721,8 +1722,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
running hooks, writing the trees, and interacting with the user. */
if (!prepare_to_commit(index_file, prefix,
current_head, &s, &author_ident)) {
+ ret = 1;
rollback_index_files();
- return 1;
+ goto cleanup;
}
/* Determine parents */
@@ -1820,7 +1822,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
rollback_index_files();
die(_("failed to write commit object"));
}
- strbuf_release(&author_ident);
free_commit_extra_headers(extra);
if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb,
@@ -1862,7 +1863,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
apply_autostash(git_path_merge_autostash(the_repository));
+cleanup:
+ UNLEAK(author_ident);
UNLEAK(err);
UNLEAK(sb);
- return 0;
+ return ret;
}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 0e0ac1f167..116097a404 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -195,6 +195,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int saved_dcctc = 0;
opt->diffopt.rotate_to_strict = 0;
+ opt->diffopt.no_free = 1;
if (opt->diffopt.detect_rename) {
if (!the_index.cache)
repo_read_index(the_repository);
@@ -217,6 +218,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
}
opt->diffopt.degraded_cc_to_c = saved_dcctc;
opt->diffopt.needed_rename_limit = saved_nrl;
+ opt->diffopt.no_free = 0;
+ diff_free(&opt->diffopt);
}
return diff_result_code(&opt->diffopt, 0);
diff --git a/builtin/diff.c b/builtin/diff.c
index bb7fafca61..3397f44d5a 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -352,7 +352,7 @@ static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
othercount++;
continue;
}
- if (map == NULL)
+ if (!map)
map = bitmap_new();
bitmap_set(map, i);
}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index a7d72697fb..1355b5a96d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -1261,6 +1261,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
revs.diffopt.format_callback = show_filemodify;
revs.diffopt.format_callback_data = &paths_of_changed_objects;
revs.diffopt.flags.recursive = 1;
+ revs.diffopt.no_free = 1;
while ((commit = get_revision(&revs)))
handle_commit(commit, &revs, &paths_of_changed_objects);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index e3791f09ed..ac29c2b1ae 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1440,6 +1440,7 @@ static void check_not_current_branch(struct ref *ref_map,
const struct worktree *wt;
for (; ref_map; ref_map = ref_map->next)
if (ref_map->peer_ref &&
+ starts_with(ref_map->peer_ref->name, "refs/heads/") &&
(wt = find_shared_symref(worktrees, "HEAD",
ref_map->peer_ref->name)) &&
!wt->is_bare)
@@ -2187,6 +2188,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
else if (argc > 1)
die(_("fetch --all does not make sense with refspecs"));
(void) for_each_remote(get_one_remote_for_fetch, &list);
+
+ /* do not do fetch_multiple() of one */
+ if (list.nr == 1)
+ remote = remote_get(list.items[0].string);
} else if (argc == 0) {
/* No arguments -- use default remote */
remote = remote_get(NULL);
@@ -2261,7 +2266,17 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
result = fetch_multiple(&list, max_children);
}
- if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
+
+ /*
+ * This is only needed after fetch_one(), which does not fetch
+ * submodules by itself.
+ *
+ * When we fetch from multiple remotes, fetch_multiple() has
+ * already updated submodules to grab commits necessary for
+ * the fetched history from each remote, so there is no need
+ * to fetch submodules from here.
+ */
+ if (!result && remote && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
struct strvec options = STRVEC_INIT;
int max_children = max_jobs;
diff --git a/builtin/gc.c b/builtin/gc.c
index b335cffa33..daa4535f1c 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -446,7 +446,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
fscanf(fp, scan_fmt, &pid, locking_host) == 2 &&
/* be gentle to concurrent "gc" on remote hosts */
(strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
- if (fp != NULL)
+ if (fp)
fclose(fp);
if (should_exit) {
if (fd >= 0)
@@ -2238,7 +2238,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
goto error;
}
file = fopen_or_warn(filename, "w");
- if (file == NULL)
+ if (!file)
goto error;
unit = "# This file was created and is maintained by Git.\n"
@@ -2267,7 +2267,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
filename = xdg_config_home_systemd("git-maintenance@.service");
file = fopen_or_warn(filename, "w");
- if (file == NULL)
+ if (!file)
goto error;
unit = "# This file was created and is maintained by Git.\n"
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 680b66b063..3e385b4800 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1942,11 +1942,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
free(objects);
strbuf_release(&index_name_buf);
strbuf_release(&rev_index_name_buf);
- if (pack_name == NULL)
+ if (!pack_name)
free((void *) curr_pack);
- if (index_name == NULL)
+ if (!index_name)
free((void *) curr_index);
- if (rev_index_name == NULL)
+ if (!rev_index_name)
free((void *) curr_rev_index);
/*
diff --git a/builtin/log.c b/builtin/log.c
index c211d66d1d..2eb0063cc1 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -417,7 +417,7 @@ static void finish_early_output(struct rev_info *rev)
show_early_header(rev, "done", n);
}
-static int cmd_log_walk(struct rev_info *rev)
+static int cmd_log_walk_no_free(struct rev_info *rev)
{
struct commit *commit;
int saved_nrl = 0;
@@ -444,7 +444,6 @@ static int cmd_log_walk(struct rev_info *rev)
* and HAS_CHANGES being accumulated in rev->diffopt, so be careful to
* retain that state information if replacing rev->diffopt in this loop
*/
- rev->diffopt.no_free = 1;
while ((commit = get_revision(rev)) != NULL) {
if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
/*
@@ -469,8 +468,6 @@ static int cmd_log_walk(struct rev_info *rev)
}
rev->diffopt.degraded_cc_to_c = saved_dcctc;
rev->diffopt.needed_rename_limit = saved_nrl;
- rev->diffopt.no_free = 0;
- diff_free(&rev->diffopt);
if (rev->remerge_diff) {
tmp_objdir_destroy(rev->remerge_objdir);
@@ -484,6 +481,17 @@ static int cmd_log_walk(struct rev_info *rev)
return diff_result_code(&rev->diffopt, 0);
}
+static int cmd_log_walk(struct rev_info *rev)
+{
+ int retval;
+
+ rev->diffopt.no_free = 1;
+ retval = cmd_log_walk_no_free(rev);
+ rev->diffopt.no_free = 0;
+ diff_free(&rev->diffopt);
+ return retval;
+}
+
static int git_log_config(const char *var, const char *value, void *cb)
{
const char *slot_name;
@@ -661,6 +669,11 @@ int cmd_show(int argc, const char **argv, const char *prefix)
init_log_defaults();
git_config(git_log_config, NULL);
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ }
+
memset(&match_all, 0, sizeof(match_all));
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -680,6 +693,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
count = rev.pending.nr;
objects = rev.pending.objects;
+ rev.diffopt.no_free = 1;
for (i = 0; i < count && !ret; i++) {
struct object *o = objects[i].item;
const char *name = objects[i].name;
@@ -725,12 +739,16 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.pending.nr = rev.pending.alloc = 0;
rev.pending.objects = NULL;
add_object_array(o, name, &rev.pending);
- ret = cmd_log_walk(&rev);
+ ret = cmd_log_walk_no_free(&rev);
break;
default:
ret = error(_("unknown type: %d"), o->type);
}
}
+
+ rev.diffopt.no_free = 0;
+ diff_free(&rev.diffopt);
+
free(objects);
return ret;
}
@@ -1012,7 +1030,7 @@ static int open_next_file(struct commit *commit, const char *subject,
if (!quiet)
printf("%s\n", filename.buf + outdir_offset);
- if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) {
+ if (!(rev->diffopt.file = fopen(filename.buf, "w"))) {
error_errno(_("cannot open patch file %s"), filename.buf);
strbuf_release(&filename);
return -1;
@@ -1883,6 +1901,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.diff = 1;
rev.max_parents = 1;
rev.diffopt.flags.recursive = 1;
+ rev.diffopt.no_free = 1;
rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
@@ -2008,13 +2027,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (use_stdout) {
setup_pager();
- } else if (rev.diffopt.close_file) {
- /*
- * The diff code parsed --output; it has already opened the
- * file, but we must instruct it not to close after each diff.
- */
- rev.diffopt.no_free = 1;
- } else {
+ } else if (!rev.diffopt.close_file) {
int saved;
if (!output_directory)
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index d856085e94..df44e5cc0d 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -114,7 +114,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
}
transport = transport_get(remote, NULL);
- if (uploadpack != NULL)
+ if (uploadpack)
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
if (server_options.nr)
transport->server_options = &server_options;
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30952353a3..73509f651b 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -120,7 +120,7 @@ static int populate_maildir_list(struct string_list *list, const char *path)
for (sub = subs; *sub; ++sub) {
free(name);
name = xstrfmt("%s/%s", path, *sub);
- if ((dir = opendir(name)) == NULL) {
+ if (!(dir = opendir(name))) {
if (errno == ENOENT)
continue;
error_errno("cannot opendir %s", name);
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 4480ba3982..5edbb7fe86 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -44,7 +44,7 @@ static char const * const builtin_multi_pack_index_usage[] = {
};
static struct opts_multi_pack_index {
- const char *object_dir;
+ char *object_dir;
const char *preferred_pack;
const char *refs_snapshot;
unsigned long batch_size;
@@ -52,9 +52,23 @@ static struct opts_multi_pack_index {
int stdin_packs;
} opts;
+
+static int parse_object_dir(const struct option *opt, const char *arg,
+ int unset)
+{
+ free(opts.object_dir);
+ if (unset)
+ opts.object_dir = xstrdup(get_object_directory());
+ else
+ opts.object_dir = real_pathdup(arg, 1);
+ return 0;
+}
+
static struct option common_opts[] = {
- OPT_FILENAME(0, "object-dir", &opts.object_dir,
- N_("object directory containing set of packfile and pack-index pairs")),
+ OPT_CALLBACK(0, "object-dir", &opts.object_dir,
+ N_("directory"),
+ N_("object directory containing set of packfile and pack-index pairs"),
+ parse_object_dir),
OPT_END(),
};
@@ -232,31 +246,40 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv)
int cmd_multi_pack_index(int argc, const char **argv,
const char *prefix)
{
+ int res;
struct option *builtin_multi_pack_index_options = common_opts;
git_config(git_default_config, NULL);
+ if (the_repository &&
+ the_repository->objects &&
+ the_repository->objects->odb)
+ opts.object_dir = xstrdup(the_repository->objects->odb->path);
+
argc = parse_options(argc, argv, prefix,
builtin_multi_pack_index_options,
builtin_multi_pack_index_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- if (!opts.object_dir)
- opts.object_dir = get_object_directory();
-
if (!argc)
goto usage;
if (!strcmp(argv[0], "repack"))
- return cmd_multi_pack_index_repack(argc, argv);
+ res = cmd_multi_pack_index_repack(argc, argv);
else if (!strcmp(argv[0], "write"))
- return cmd_multi_pack_index_write(argc, argv);
+ res = cmd_multi_pack_index_write(argc, argv);
else if (!strcmp(argv[0], "verify"))
- return cmd_multi_pack_index_verify(argc, argv);
+ res = cmd_multi_pack_index_verify(argc, argv);
else if (!strcmp(argv[0], "expire"))
- return cmd_multi_pack_index_expire(argc, argv);
+ res = cmd_multi_pack_index_expire(argc, argv);
+ else {
+ error(_("unrecognized subcommand: %s"), argv[0]);
+ goto usage;
+ }
+
+ free(opts.object_dir);
+ return res;
- error(_("unrecognized subcommand: %s"), argv[0]);
usage:
usage_with_options(builtin_multi_pack_index_usage,
builtin_multi_pack_index_options);
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index c59b5699fe..02ea9d1633 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -18,7 +18,7 @@
#define CUTOFF_DATE_SLOP 86400
struct rev_name {
- char *tip_name;
+ const char *tip_name;
timestamp_t taggerdate;
int generation;
int distance;
@@ -84,7 +84,7 @@ static int commit_is_before_cutoff(struct commit *commit)
static int is_valid_rev_name(const struct rev_name *name)
{
- return name && (name->generation || name->tip_name);
+ return name && name->tip_name;
}
static struct rev_name *get_commit_rev_name(const struct commit *commit)
@@ -146,20 +146,9 @@ static struct rev_name *create_or_update_name(struct commit *commit,
{
struct rev_name *name = commit_rev_name_at(&rev_names, commit);
- if (is_valid_rev_name(name)) {
- if (!is_better_name(name, taggerdate, generation, distance, from_tag))
- return NULL;
-
- /*
- * This string might still be shared with ancestors
- * (generation > 0). We can release it here regardless,
- * because the new name that has just won will be better
- * for them as well, so name_rev() will replace these
- * stale pointers when it processes the parents.
- */
- if (!name->generation)
- free(name->tip_name);
- }
+ if (is_valid_rev_name(name) &&
+ !is_better_name(name, taggerdate, generation, distance, from_tag))
+ return NULL;
name->taggerdate = taggerdate;
name->generation = generation;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 014dcd4bc9..0a26de166d 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1357,6 +1357,9 @@ static int want_found_object(const struct object_id *oid, int exclude,
if (incremental)
return 0;
+ if (!is_pack_valid(p))
+ return -1;
+
/*
* When asked to do --local (do not include an object that appears in a
* pack we borrow from elsewhere) or --honor-pack-keep (do not include
@@ -1472,6 +1475,9 @@ static int want_object_in_pack(const struct object_id *oid,
want = want_found_object(oid, exclude, *found_pack);
if (want != -1)
return want;
+
+ *found_pack = NULL;
+ *found_offset = 0;
}
for (m = get_multi_pack_index(the_repository); m; m = m->next) {
@@ -3201,10 +3207,8 @@ static int add_object_entry_from_pack(const struct object_id *oid,
uint32_t pos,
void *_data)
{
- struct rev_info *revs = _data;
- struct object_info oi = OBJECT_INFO_INIT;
off_t ofs;
- enum object_type type;
+ enum object_type type = OBJ_NONE;
display_progress(progress_state, ++nr_seen);
@@ -3215,19 +3219,24 @@ static int add_object_entry_from_pack(const struct object_id *oid,
if (!want_object_in_pack(oid, 0, &p, &ofs))
return 0;
- oi.typep = &type;
- if (packed_object_info(the_repository, p, ofs, &oi) < 0)
- die(_("could not get type of object %s in pack %s"),
- oid_to_hex(oid), p->pack_name);
- else if (type == OBJ_COMMIT) {
- /*
- * commits in included packs are used as starting points for the
- * subsequent revision walk
- */
- add_pending_oid(revs, NULL, oid, 0);
- }
+ if (p) {
+ struct rev_info *revs = _data;
+ struct object_info oi = OBJECT_INFO_INIT;
+
+ oi.typep = &type;
+ if (packed_object_info(the_repository, p, ofs, &oi) < 0) {
+ die(_("could not get type of object %s in pack %s"),
+ oid_to_hex(oid), p->pack_name);
+ } else if (type == OBJ_COMMIT) {
+ /*
+ * commits in included packs are used as starting points for the
+ * subsequent revision walk
+ */
+ add_pending_oid(revs, NULL, oid, 0);
+ }
- stdin_packs_found_nr++;
+ stdin_packs_found_nr++;
+ }
create_object_entry(oid, type, 0, 0, 0, p, ofs);
@@ -3346,6 +3355,8 @@ static void read_packs_list_from_stdin(void)
struct packed_git *p = item->util;
if (!p)
die(_("could not find pack '%s'"), item->string);
+ if (!is_pack_valid(p))
+ die(_("packfile %s cannot be accessed"), p->pack_name);
}
/*
@@ -3369,8 +3380,6 @@ static void read_packs_list_from_stdin(void)
for_each_string_list_item(item, &include_packs) {
struct packed_git *p = item->util;
- if (!p)
- die(_("could not find pack '%s'"), item->string);
for_each_object_in_pack(p,
add_object_entry_from_pack,
&revs,
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 8bf5c0acad..ed9b9013a5 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -101,7 +101,7 @@ static inline struct llist_item *llist_insert(struct llist *list,
oidread(&new_item->oid, oid);
new_item->next = NULL;
- if (after != NULL) {
+ if (after) {
new_item->next = after->next;
after->next = new_item;
if (after == list->back)
@@ -157,7 +157,7 @@ redo_from_start:
if (cmp > 0) /* not in list, since sorted */
return prev;
if (!cmp) { /* found */
- if (prev == NULL) {
+ if (!prev) {
if (hint != NULL && hint != list->front) {
/* we don't know the previous element */
hint = NULL;
@@ -219,7 +219,7 @@ static struct pack_list * pack_list_difference(const struct pack_list *A,
struct pack_list *ret;
const struct pack_list *pl;
- if (A == NULL)
+ if (!A)
return NULL;
pl = B;
@@ -317,7 +317,7 @@ static size_t get_pack_redundancy(struct pack_list *pl)
struct pack_list *subset;
size_t ret = 0;
- if (pl == NULL)
+ if (!pl)
return 0;
while ((subset = pl->next)) {
@@ -611,7 +611,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
while (*(argv + i) != NULL)
add_pack_file(*(argv + i++));
- if (local_packs == NULL)
+ if (!local_packs)
die("Zero packs found!");
load_all_objects();
diff --git a/builtin/pull.c b/builtin/pull.c
index 4d667abc19..01155ba67b 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -72,6 +72,7 @@ static const char * const pull_usage[] = {
static int opt_verbosity;
static char *opt_progress;
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
/* Options passed to git-merge or git-rebase */
static enum rebase_type opt_rebase = -1;
@@ -120,7 +121,7 @@ static struct option pull_options[] = {
N_("force progress reporting"),
PARSE_OPT_NOARG),
OPT_CALLBACK_F(0, "recurse-submodules",
- &recurse_submodules, N_("on-demand"),
+ &recurse_submodules_cli, N_("on-demand"),
N_("control for recursive fetching of submodules"),
PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
@@ -536,8 +537,8 @@ static int run_fetch(const char *repo, const char **refspecs)
strvec_push(&args, opt_tags);
if (opt_prune)
strvec_push(&args, opt_prune);
- if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
- switch (recurse_submodules) {
+ if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+ switch (recurse_submodules_cli) {
case RECURSE_SUBMODULES_ON:
strvec_push(&args, "--recurse-submodules=on");
break;
@@ -1001,6 +1002,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
+ if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+ recurse_submodules = recurse_submodules_cli;
+
if (cleanup_arg)
/*
* this only checks the validity of cleanup_arg; we don't need
diff --git a/builtin/push.c b/builtin/push.c
index cad997965a..86b44f8aa7 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -2,6 +2,7 @@
* "git push"
*/
#include "cache.h"
+#include "branch.h"
#include "config.h"
#include "refs.h"
#include "refspec.h"
@@ -151,7 +152,8 @@ static NORETURN void die_push_simple(struct branch *branch,
* upstream to a non-branch, we should probably be showing
* them the big ugly fully qualified ref.
*/
- const char *advice_maybe = "";
+ const char *advice_pushdefault_maybe = "";
+ const char *advice_automergesimple_maybe = "";
const char *short_upstream = branch->merge[0]->src;
skip_prefix(short_upstream, "refs/heads/", &short_upstream);
@@ -161,9 +163,16 @@ static NORETURN void die_push_simple(struct branch *branch,
* push.default.
*/
if (push_default == PUSH_DEFAULT_UNSPECIFIED)
- advice_maybe = _("\n"
+ advice_pushdefault_maybe = _("\n"
"To choose either option permanently, "
- "see push.default in 'git help config'.");
+ "see push.default in 'git help config'.\n");
+ if (git_branch_track != BRANCH_TRACK_SIMPLE)
+ advice_automergesimple_maybe = _("\n"
+ "To avoid automatically configuring "
+ "upstream branches when their name\n"
+ "doesn't match the local branch, see option "
+ "'simple' of branch.autosetupmerge\n"
+ "in 'git help config'.\n");
die(_("The upstream branch of your current branch does not match\n"
"the name of your current branch. To push to the upstream branch\n"
"on the remote, use\n"
@@ -173,9 +182,10 @@ static NORETURN void die_push_simple(struct branch *branch,
"To push to the branch of the same name on the remote, use\n"
"\n"
" git push %s HEAD\n"
- "%s"),
+ "%s%s"),
remote->name, short_upstream,
- remote->name, advice_maybe);
+ remote->name, advice_pushdefault_maybe,
+ advice_automergesimple_maybe);
}
static const char message_detached_head_die[] =
@@ -185,16 +195,32 @@ static const char message_detached_head_die[] =
"\n"
" git push %s HEAD:<name-of-remote-branch>\n");
-static const char *get_upstream_ref(struct branch *branch, const char *remote_name)
+static const char *get_upstream_ref(int flags, struct branch *branch, const char *remote_name)
{
- if (!branch->merge_nr || !branch->merge || !branch->remote_name)
+ if (branch->merge_nr == 0 && (flags & TRANSPORT_PUSH_AUTO_UPSTREAM)) {
+ /* if missing, assume same; set_upstream will be defined later */
+ return branch->refname;
+ }
+
+ if (!branch->merge_nr || !branch->merge || !branch->remote_name) {
+ const char *advice_autosetup_maybe = "";
+ if (!(flags & TRANSPORT_PUSH_AUTO_UPSTREAM)) {
+ advice_autosetup_maybe = _("\n"
+ "To have this happen automatically for "
+ "branches without a tracking\n"
+ "upstream, see 'push.autoSetupRemote' "
+ "in 'git help config'.\n");
+ }
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"),
+ " git push --set-upstream %s %s\n"
+ "%s"),
branch->name,
remote_name,
- branch->name);
+ branch->name,
+ advice_autosetup_maybe);
+ }
if (branch->merge_nr != 1)
die(_("The current branch %s has multiple upstream branches, "
"refusing to push."), branch->name);
@@ -202,7 +228,7 @@ static const char *get_upstream_ref(struct branch *branch, const char *remote_na
return branch->merge[0]->src;
}
-static void setup_default_push_refspecs(struct remote *remote)
+static void setup_default_push_refspecs(int *flags, struct remote *remote)
{
struct branch *branch;
const char *dst;
@@ -234,7 +260,7 @@ static void setup_default_push_refspecs(struct remote *remote)
case PUSH_DEFAULT_SIMPLE:
if (!same_remote)
break;
- if (strcmp(branch->refname, get_upstream_ref(branch, remote->name)))
+ if (strcmp(branch->refname, get_upstream_ref(*flags, branch, remote->name)))
die_push_simple(branch, remote);
break;
@@ -244,13 +270,21 @@ static void setup_default_push_refspecs(struct remote *remote)
"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);
+ dst = get_upstream_ref(*flags, branch, remote->name);
break;
case PUSH_DEFAULT_CURRENT:
break;
}
+ /*
+ * this is a default push - if auto-upstream is enabled and there is
+ * no upstream defined, then set it (with options 'simple', 'upstream',
+ * and 'current').
+ */
+ if ((*flags & TRANSPORT_PUSH_AUTO_UPSTREAM) && branch->merge_nr == 0)
+ *flags |= TRANSPORT_PUSH_SET_UPSTREAM;
+
refspec_appendf(&rs, "%s:%s", branch->refname, dst);
}
@@ -401,7 +435,7 @@ static int do_push(int flags,
if (remote->push.nr) {
push_refspec = &remote->push;
} else if (!(flags & TRANSPORT_PUSH_MIRROR))
- setup_default_push_refspecs(remote);
+ setup_default_push_refspecs(&flags, remote);
}
errs = 0;
url_nr = push_url_of_remote(remote, &url);
@@ -472,6 +506,10 @@ static int git_push_config(const char *k, const char *v, void *cb)
else
*flags &= ~TRANSPORT_PUSH_FOLLOW_TAGS;
return 0;
+ } else if (!strcmp(k, "push.autosetupremote")) {
+ if (git_config_bool(k, v))
+ *flags |= TRANSPORT_PUSH_AUTO_UPSTREAM;
+ return 0;
} else if (!strcmp(k, "push.gpgsign")) {
const char *value;
if (!git_config_get_value("push.gpgsign", &value)) {
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 27fde7bf28..7ab50cda2a 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1187,11 +1187,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else {
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/interactive", merge_dir());
- if(file_exists(buf.buf)) {
- options.type = REBASE_MERGE;
+ options.type = REBASE_MERGE;
+ if (file_exists(buf.buf))
options.flags |= REBASE_INTERACTIVE_EXPLICIT;
- } else
- options.type = REBASE_MERGE;
}
options.state_dir = merge_dir();
}
@@ -1583,33 +1581,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.upstream_arg = "--root";
}
- /* Make sure the branch to rebase onto is valid. */
- if (keep_base) {
- strbuf_reset(&buf);
- strbuf_addstr(&buf, options.upstream_name);
- strbuf_addstr(&buf, "...");
- options.onto_name = xstrdup(buf.buf);
- } else if (!options.onto_name)
- options.onto_name = options.upstream_name;
- if (strstr(options.onto_name, "...")) {
- if (get_oid_mb(options.onto_name, &merge_base) < 0) {
- if (keep_base)
- die(_("'%s': need exactly one merge base with branch"),
- options.upstream_name);
- else
- die(_("'%s': need exactly one merge base"),
- options.onto_name);
- }
- options.onto = lookup_commit_or_die(&merge_base,
- options.onto_name);
- } else {
- options.onto =
- lookup_commit_reference_by_name(options.onto_name);
- if (!options.onto)
- die(_("Does not point to a valid commit '%s'"),
- options.onto_name);
- }
-
/*
* If the branch to rebase is given, that is the branch we will rebase
* branch_name -- branch/commit being rebased, or
@@ -1659,6 +1630,34 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
} else
BUG("unexpected number of arguments left to parse");
+ /* Make sure the branch to rebase onto is valid. */
+ if (keep_base) {
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, options.upstream_name);
+ strbuf_addstr(&buf, "...");
+ strbuf_addstr(&buf, branch_name);
+ options.onto_name = xstrdup(buf.buf);
+ } else if (!options.onto_name)
+ options.onto_name = options.upstream_name;
+ if (strstr(options.onto_name, "...")) {
+ if (get_oid_mb(options.onto_name, &merge_base) < 0) {
+ if (keep_base)
+ die(_("'%s': need exactly one merge base with branch"),
+ options.upstream_name);
+ else
+ die(_("'%s': need exactly one merge base"),
+ options.onto_name);
+ }
+ options.onto = lookup_commit_or_die(&merge_base,
+ options.onto_name);
+ } else {
+ options.onto =
+ lookup_commit_reference_by_name(options.onto_name);
+ if (!options.onto)
+ die(_("Does not point to a valid commit '%s'"),
+ options.onto_name);
+ }
+
if (options.fork_point > 0) {
struct commit *head =
lookup_commit_reference(the_repository,
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 9aabffa1af..daa153d044 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1664,7 +1664,7 @@ static void check_aliased_update_internal(struct command *cmd,
}
dst_name = strip_namespace(dst_name);
- if ((item = string_list_lookup(list, dst_name)) == NULL)
+ if (!(item = string_list_lookup(list, dst_name)))
return;
cmd->skip_update = 1;
@@ -2214,8 +2214,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
close(err_fd);
return "unable to create temporary object directory";
}
- if (tmp_objdir)
- strvec_pushv(&child.env_array, tmp_objdir_env(tmp_objdir));
+ strvec_pushv(&child.env_array, tmp_objdir_env(tmp_objdir));
/*
* Normally we just pass the tmp_objdir environment to the child
@@ -2538,7 +2537,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
PACKET_READ_CHOMP_NEWLINE |
PACKET_READ_DIE_ON_ERR_PACKET);
- if ((commands = read_head_info(&reader, &shallow)) != NULL) {
+ if ((commands = read_head_info(&reader, &shallow))) {
const char *unpack_status = NULL;
struct string_list push_options = STRING_LIST_INIT_DUP;
diff --git a/builtin/remote.c b/builtin/remote.c
index 5f4cde9d78..d4b69fe778 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1185,14 +1185,22 @@ static int show_push_info_item(struct string_list_item *item, void *cb_data)
static int get_one_entry(struct remote *remote, void *priv)
{
struct string_list *list = priv;
- struct strbuf url_buf = STRBUF_INIT;
+ struct strbuf remote_info_buf = STRBUF_INIT;
const char **url;
int i, url_nr;
if (remote->url_nr > 0) {
- strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
+ struct strbuf promisor_config = STRBUF_INIT;
+ const char *partial_clone_filter = NULL;
+
+ strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name);
+ strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url[0]);
+ if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter))
+ strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter);
+
+ strbuf_release(&promisor_config);
string_list_append(list, remote->name)->util =
- strbuf_detach(&url_buf, NULL);
+ strbuf_detach(&remote_info_buf, NULL);
} else
string_list_append(list, remote->name)->util = NULL;
if (remote->pushurl_nr) {
@@ -1204,9 +1212,9 @@ static int get_one_entry(struct remote *remote, void *priv)
}
for (i = 0; i < url_nr; i++)
{
- strbuf_addf(&url_buf, "%s (push)", url[i]);
+ strbuf_addf(&remote_info_buf, "%s (push)", url[i]);
string_list_append(list, remote->name)->util =
- strbuf_detach(&url_buf, NULL);
+ strbuf_detach(&remote_info_buf, NULL);
}
return 0;
diff --git a/builtin/repack.c b/builtin/repack.c
index d1a563d5b6..0e4aae80c0 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -137,6 +137,8 @@ static void collect_pack_filenames(struct string_list *fname_nonkept_list,
string_list_append_nodup(fname_nonkept_list, fname);
}
closedir(dir);
+
+ string_list_sort(fname_kept_list);
}
static void remove_redundant_pack(const char *dir_name, const char *base_name)
@@ -332,17 +334,38 @@ static int geometry_cmp(const void *va, const void *vb)
return 0;
}
-static void init_pack_geometry(struct pack_geometry **geometry_p)
+static void init_pack_geometry(struct pack_geometry **geometry_p,
+ struct string_list *existing_kept_packs)
{
struct packed_git *p;
struct pack_geometry *geometry;
+ struct strbuf buf = STRBUF_INIT;
*geometry_p = xcalloc(1, sizeof(struct pack_geometry));
geometry = *geometry_p;
for (p = get_all_packs(the_repository); p; p = p->next) {
- if (!pack_kept_objects && p->pack_keep)
- continue;
+ if (!pack_kept_objects) {
+ /*
+ * Any pack that has its pack_keep bit set will appear
+ * in existing_kept_packs below, but this saves us from
+ * doing a more expensive check.
+ */
+ if (p->pack_keep)
+ continue;
+
+ /*
+ * The pack may be kept via the --keep-pack option;
+ * check 'existing_kept_packs' to determine whether to
+ * ignore it.
+ */
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if (string_list_has_string(existing_kept_packs, buf.buf))
+ continue;
+ }
ALLOC_GROW(geometry->pack,
geometry->pack_nr + 1,
@@ -353,6 +376,7 @@ static void init_pack_geometry(struct pack_geometry **geometry_p)
}
QSORT(geometry->pack, geometry->pack_nr, geometry_cmp);
+ strbuf_release(&buf);
}
static void split_pack_geometry(struct pack_geometry *geometry, int factor)
@@ -714,17 +738,20 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strbuf_release(&path);
}
+ packdir = mkpathdup("%s/pack", get_object_directory());
+ packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
+ packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
+
+ collect_pack_filenames(&existing_nonkept_packs, &existing_kept_packs,
+ &keep_pack_list);
+
if (geometric_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
- init_pack_geometry(&geometry);
+ init_pack_geometry(&geometry, &existing_kept_packs);
split_pack_geometry(geometry, geometric_factor);
}
- packdir = mkpathdup("%s/pack", get_object_directory());
- packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
- packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
-
sigchain_push_common(remove_pack_on_signal);
prepare_pack_objects(&cmd, &po_args);
@@ -764,9 +791,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (use_delta_islands)
strvec_push(&cmd.args, "--delta-islands");
- collect_pack_filenames(&existing_nonkept_packs, &existing_kept_packs,
- &keep_pack_list);
-
if (pack_everything & ALL_INTO_ONE) {
repack_promisor_objects(&po_args, &names);
@@ -832,6 +856,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (!names.nr && !po_args.quiet)
printf_ln(_("Nothing new to pack."));
+ string_list_sort(&names);
+
for_each_string_list_item(item, &names) {
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
}
@@ -872,7 +898,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (delete_redundant && pack_everything & ALL_INTO_ONE) {
const int hexsz = the_hash_algo->hexsz;
- string_list_sort(&names);
for_each_string_list_item(item, &existing_nonkept_packs) {
char *sha1;
size_t len = strlen(item->string);
diff --git a/builtin/replace.c b/builtin/replace.c
index 5068f4f0b2..583702a098 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -72,7 +72,7 @@ static int list_replace_refs(const char *pattern, const char *format)
{
struct show_data data;
- if (pattern == NULL)
+ if (!pattern)
pattern = "*";
data.pattern = pattern;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 8480a59f57..b259d8990a 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -476,7 +476,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
/* name(s) */
s = strpbrk(sb.buf, flag_chars);
- if (s == NULL)
+ if (!s)
s = help;
if (s - sb.buf == 1) /* short option only */
@@ -723,6 +723,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
prefix = setup_git_directory();
git_config(git_default_config, NULL);
did_repo_setup = 1;
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
}
if (!strcmp(arg, "--")) {
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 26c5c0cf93..62c4a4eaba 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -81,7 +81,7 @@ static void insert_one_record(struct shortlog *log,
format_subject(&subject, oneline, " ");
buffer = strbuf_detach(&subject, NULL);
- if (item->util == NULL)
+ if (!item->util)
item->util = xcalloc(1, sizeof(struct string_list));
string_list_append(item->util, buffer);
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 330b0553b9..64c649c6a2 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -712,6 +712,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
"--all/--remotes/--independent/--merge-base");
}
+ if (with_current_branch && reflog)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--reflog", "--current");
+
/* If nothing is specified, show all branches by default */
if (ac <= topics && all_heads + all_remotes == 0)
all_heads = 1;
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 0217d44c5b..f91e29b56a 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -128,7 +128,7 @@ static void clean_tracked_sparse_directories(struct repository *r)
* sparse index will not delete directories that contain
* conflicted entries or submodules.
*/
- if (!r->index->sparse_index) {
+ if (r->index->sparse_index == INDEX_EXPANDED) {
/*
* If something, such as a merge conflict or other concern,
* prevents us from converting to a sparse index, then do
@@ -395,7 +395,7 @@ static int update_modes(int *cone_mode, int *sparse_index)
/* Set cone/non-cone mode appropriately */
core_apply_sparse_checkout = 1;
- if (*cone_mode == 1) {
+ if (*cone_mode == 1 || *cone_mode == -1) {
mode = MODE_CONE_PATTERNS;
core_sparse_checkout_cone = 1;
} else {
@@ -413,6 +413,9 @@ static int update_modes(int *cone_mode, int *sparse_index)
/* force an index rewrite */
repo_read_index(the_repository);
the_repository->index->updated_workdir = 1;
+
+ if (!*sparse_index)
+ ensure_full_index(the_repository->index);
}
return 0;
@@ -934,6 +937,9 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
if (argc > 0) {
if (!strcmp(argv[0], "list"))
return sparse_checkout_list(argc, argv);
diff --git a/builtin/stash.c b/builtin/stash.c
index 0c7b6a9588..3fe549f7d3 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -7,6 +7,7 @@
#include "cache-tree.h"
#include "unpack-trees.h"
#include "merge-recursive.h"
+#include "merge-ort-wrappers.h"
#include "strvec.h"
#include "run-command.h"
#include "dir.h"
@@ -492,13 +493,13 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
static int do_apply_stash(const char *prefix, struct stash_info *info,
int index, int quiet)
{
- int ret;
+ int clean, ret;
int has_index = index;
struct merge_options o;
struct object_id c_tree;
struct object_id index_tree;
- struct commit *result;
- const struct object_id *bases[1];
+ struct tree *head, *merge, *merge_base;
+ struct lock_file lock = LOCK_INIT;
read_cache_preload(NULL);
if (refresh_and_write_cache(REFRESH_QUIET, 0, 0))
@@ -541,6 +542,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
o.branch1 = "Updated upstream";
o.branch2 = "Stashed changes";
+ o.ancestor = "Stash base";
if (oideq(&info->b_tree, &c_tree))
o.branch1 = "Version stash was based on";
@@ -551,10 +553,26 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
if (o.verbosity >= 3)
printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
- bases[0] = &info->b_tree;
+ head = lookup_tree(o.repo, &c_tree);
+ merge = lookup_tree(o.repo, &info->w_tree);
+ merge_base = lookup_tree(o.repo, &info->b_tree);
+
+ repo_hold_locked_index(o.repo, &lock, LOCK_DIE_ON_ERROR);
+ clean = merge_ort_nonrecursive(&o, head, merge, merge_base);
+
+ /*
+ * If 'clean' >= 0, reverse the value for 'ret' so 'ret' is 0 when the
+ * merge was clean, and nonzero if the merge was unclean or encountered
+ * an error.
+ */
+ ret = clean >= 0 ? !clean : clean;
+
+ if (ret < 0)
+ rollback_lock_file(&lock);
+ else if (write_locked_index(o.repo->index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ ret = error(_("could not write index"));
- ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
- &result);
if (ret) {
rerere(0);
@@ -1770,6 +1788,9 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, git_stash_usage,
PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
index_file = get_index_file();
strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
(uintmax_t)pid);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b97f02eed5..12ecadd712 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -72,135 +72,6 @@ static char *get_default_remote(void)
return repo_get_default_remote(the_repository);
}
-static int starts_with_dot_slash(const char *str)
-{
- return str[0] == '.' && is_dir_sep(str[1]);
-}
-
-static int starts_with_dot_dot_slash(const char *str)
-{
- return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
-}
-
-/*
- * Returns 1 if it was the last chop before ':'.
- */
-static int chop_last_dir(char **remoteurl, int is_relative)
-{
- char *rfind = find_last_dir_sep(*remoteurl);
- if (rfind) {
- *rfind = '\0';
- return 0;
- }
-
- rfind = strrchr(*remoteurl, ':');
- if (rfind) {
- *rfind = '\0';
- return 1;
- }
-
- if (is_relative || !strcmp(".", *remoteurl))
- die(_("cannot strip one component off url '%s'"),
- *remoteurl);
-
- free(*remoteurl);
- *remoteurl = xstrdup(".");
- return 0;
-}
-
-/*
- * The `url` argument is the URL that navigates to the submodule origin
- * repo. When relative, this URL is relative to the superproject origin
- * URL repo. The `up_path` argument, if specified, is the relative
- * path that navigates from the submodule working tree to the superproject
- * working tree. Returns the origin URL of the submodule.
- *
- * Return either an absolute URL or filesystem path (if the superproject
- * origin URL is an absolute URL or filesystem path, respectively) or a
- * relative file system path (if the superproject origin URL is a relative
- * file system path).
- *
- * When the output is a relative file system path, the path is either
- * relative to the submodule working tree, if up_path is specified, or to
- * the superproject working tree otherwise.
- *
- * NEEDSWORK: This works incorrectly on the domain and protocol part.
- * remote_url url outcome expectation
- * http://a.com/b ../c http://a.com/c as is
- * http://a.com/b/ ../c http://a.com/c same as previous line, but
- * ignore trailing slash in url
- * http://a.com/b ../../c http://c error out
- * http://a.com/b ../../../c http:/c error out
- * http://a.com/b ../../../../c http:c error out
- * http://a.com/b ../../../../../c .:c error out
- * NEEDSWORK: Given how chop_last_dir() works, this function is broken
- * when a local part has a colon in its path component, too.
- */
-static char *relative_url(const char *remote_url,
- const char *url,
- const char *up_path)
-{
- int is_relative = 0;
- int colonsep = 0;
- char *out;
- char *remoteurl = xstrdup(remote_url);
- struct strbuf sb = STRBUF_INIT;
- size_t len = strlen(remoteurl);
-
- if (is_dir_sep(remoteurl[len-1]))
- remoteurl[len-1] = '\0';
-
- if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
- is_relative = 0;
- else {
- is_relative = 1;
- /*
- * Prepend a './' to ensure all relative
- * remoteurls start with './' or '../'
- */
- if (!starts_with_dot_slash(remoteurl) &&
- !starts_with_dot_dot_slash(remoteurl)) {
- strbuf_reset(&sb);
- strbuf_addf(&sb, "./%s", remoteurl);
- free(remoteurl);
- remoteurl = strbuf_detach(&sb, NULL);
- }
- }
- /*
- * When the url starts with '../', remove that and the
- * last directory in remoteurl.
- */
- while (url) {
- if (starts_with_dot_dot_slash(url)) {
- url += 3;
- colonsep |= chop_last_dir(&remoteurl, is_relative);
- } else if (starts_with_dot_slash(url))
- url += 2;
- else
- break;
- }
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
- if (ends_with(url, "/"))
- strbuf_setlen(&sb, sb.len - 1);
- free(remoteurl);
-
- if (starts_with_dot_slash(sb.buf))
- out = xstrdup(sb.buf + 2);
- else
- out = xstrdup(sb.buf);
-
- 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);
-}
-
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
{
char *remoteurl, *resolved_url;
@@ -592,6 +463,18 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
return 0;
}
+static int starts_with_dot_slash(const char *const path)
+{
+ return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
+ PATH_MATCH_XPLATFORM);
+}
+
+static int starts_with_dot_dot_slash(const char *const path)
+{
+ return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
+ PATH_MATCH_XPLATFORM);
+}
+
struct init_cb {
const char *prefix;
const char *superprefix;
@@ -2026,7 +1909,6 @@ struct update_data {
.references = STRING_LIST_INIT_DUP, \
.single_branch = -1, \
.max_jobs = 1, \
- .warn_if_uninitialized = 1, \
}
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
diff --git a/builtin/tag.c b/builtin/tag.c
index e5a8f85693..75dece0e4f 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -364,7 +364,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
strbuf_addstr(sb, "object of unknown type");
break;
case OBJ_COMMIT:
- if ((buf = read_object_file(oid, &type, &size)) != NULL) {
+ if ((buf = read_object_file(oid, &type, &size))) {
subject_len = find_commit_subject(buf, &subject_start);
strbuf_insert(sb, sb->len, subject_start, subject_len);
} else {
@@ -372,7 +372,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
}
free(buf);
- if ((c = lookup_commit_reference(the_repository, oid)) != NULL)
+ if ((c = lookup_commit_reference(the_repository, oid)))
strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
break;
case OBJ_TREE:
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index dbeb0680a5..56d05e2725 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "cache.h"
+#include "bulk-checkin.h"
#include "config.h"
#include "object-store.h"
#include "object.h"
@@ -503,10 +504,12 @@ static void unpack_all(void)
if (!quiet)
progress = start_progress(_("Unpacking objects"), nr_objects);
CALLOC_ARRAY(obj_list, nr_objects);
+ begin_odb_transaction();
for (i = 0; i < nr_objects; i++) {
unpack_one(i);
display_progress(progress, i + 1);
}
+ end_odb_transaction();
stop_progress(&progress);
if (delta_list)
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 876112abb2..43c713c087 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -5,6 +5,7 @@
*/
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
+#include "bulk-checkin.h"
#include "config.h"
#include "lockfile.h"
#include "quote.h"
@@ -57,6 +58,14 @@ static void report(const char *fmt, ...)
if (!verbose)
return;
+ /*
+ * It is possible, though unlikely, that a caller could use the verbose
+ * output to synchronize with addition of objects to the object
+ * database. The current implementation of ODB transactions leaves
+ * objects invisible while a transaction is active, so flush the
+ * transaction here before reporting a change made by update-index.
+ */
+ flush_odb_transaction();
va_start(vp, fmt);
vprintf(fmt, vp);
putchar('\n');
@@ -1116,6 +1125,12 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
*/
parse_options_start(&ctx, argc, argv, prefix,
options, PARSE_OPT_STOP_AT_NON_OPTION);
+
+ /*
+ * Allow the object layer to optimize adding multiple objects in
+ * a batch.
+ */
+ begin_odb_transaction();
while (ctx.argc) {
if (parseopt_state != PARSE_OPT_DONE)
parseopt_state = parse_options_step(&ctx, options,
@@ -1190,6 +1205,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
strbuf_release(&buf);
}
+ /*
+ * By now we have added all of the new objects
+ */
+ end_odb_transaction();
+
if (split_index > 0) {
if (git_config_get_split_index() == 0)
warning(_("core.splitIndex is set to false; "