summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c7
-rw-r--r--builtin/branch.c7
-rw-r--r--builtin/checkout.c90
-rw-r--r--builtin/credential.c2
-rw-r--r--builtin/difftool.c14
-rw-r--r--builtin/fetch.c119
-rw-r--r--builtin/fsck.c12
-rw-r--r--builtin/help.c3
-rw-r--r--builtin/log.c23
-rw-r--r--builtin/merge-file.c2
-rw-r--r--builtin/merge.c3
-rw-r--r--builtin/notes.c11
-rw-r--r--builtin/pack-objects.c2
-rw-r--r--builtin/pull.c2
-rw-r--r--builtin/receive-pack.c180
-rw-r--r--builtin/repack.c2
-rw-r--r--builtin/replace.c3
-rw-r--r--builtin/reset.c113
-rw-r--r--builtin/show-branch.c12
-rw-r--r--builtin/submodule--helper.c21
-rw-r--r--builtin/upload-archive.c5
-rw-r--r--builtin/var.c7
-rw-r--r--builtin/worktree.c27
23 files changed, 406 insertions, 261 deletions
diff --git a/builtin/add.c b/builtin/add.c
index ef6b619c45..a010b2c325 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -302,15 +302,11 @@ int interactive_add(const char **argv, const char *prefix, int patch)
static int edit_patch(int argc, const char **argv, const char *prefix)
{
char *file = git_pathdup("ADD_EDIT.patch");
- const char *apply_argv[] = { "apply", "--recount", "--cached",
- NULL, NULL };
struct child_process child = CHILD_PROCESS_INIT;
struct rev_info rev;
int out;
struct stat st;
- apply_argv[3] = file;
-
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
if (read_cache() < 0)
@@ -338,7 +334,8 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
die(_("Empty patch. Aborted."));
child.git_cmd = 1;
- child.argv = apply_argv;
+ strvec_pushl(&child.args, "apply", "--recount", "--cached", file,
+ NULL);
if (run_command(&child))
die(_("Could not apply '%s'"), file);
diff --git a/builtin/branch.c b/builtin/branch.c
index 81b5c111cb..6c8b0fcc11 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -192,6 +192,7 @@ static void delete_branch_config(const char *branchname)
static int delete_branches(int argc, const char **argv, int force, int kinds,
int quiet)
{
+ struct worktree **worktrees;
struct commit *head_rev = NULL;
struct object_id oid;
char *name = NULL;
@@ -228,6 +229,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
if (!head_rev)
die(_("Couldn't look up commit object for HEAD"));
}
+
+ worktrees = get_worktrees();
+
for (i = 0; i < argc; i++, strbuf_reset(&bname)) {
char *target = NULL;
int flags = 0;
@@ -238,7 +242,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
if (kinds == FILTER_REFS_BRANCHES) {
const struct worktree *wt =
- find_shared_symref("HEAD", name);
+ find_shared_symref(worktrees, "HEAD", name);
if (wt) {
error(_("Cannot delete branch '%s' "
"checked out at '%s'"),
@@ -299,6 +303,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
free(name);
strbuf_release(&bname);
+ free_worktrees(worktrees);
return ret;
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index cbf73b8c9f..72beeb49aa 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -91,8 +91,8 @@ struct checkout_opts {
};
struct branch_info {
- const char *name; /* The short name used */
- const char *path; /* The full name of a real branch */
+ char *name; /* The short name used */
+ char *path; /* The full name of a real branch */
struct commit *commit; /* The named commit */
char *refname; /* The full name of the ref being checked out. */
struct object_id oid; /* The object ID of the commit being checked out. */
@@ -103,6 +103,14 @@ struct branch_info {
char *checkout;
};
+static void branch_info_release(struct branch_info *info)
+{
+ free(info->name);
+ free(info->path);
+ free(info->refname);
+ free(info->checkout);
+}
+
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
@@ -688,9 +696,12 @@ static void setup_branch_path(struct branch_info *branch)
repo_get_oid_committish(the_repository, branch->name, &branch->oid);
strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
- if (strcmp(buf.buf, branch->name))
+ if (strcmp(buf.buf, branch->name)) {
+ free(branch->name);
branch->name = xstrdup(buf.buf);
+ }
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
+ free(branch->path);
branch->path = strbuf_detach(&buf, NULL);
}
@@ -874,7 +885,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
int ret;
struct strbuf err = STRBUF_INIT;
- ret = safe_create_reflog(refname, 1, &err);
+ ret = safe_create_reflog(refname, &err);
if (ret) {
fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
opts->new_orphan_branch, err.buf);
@@ -894,7 +905,9 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
opts->new_branch_log,
opts->quiet,
opts->track);
- new_branch_info->name = opts->new_branch;
+ free(new_branch_info->name);
+ free(new_branch_info->refname);
+ new_branch_info->name = xstrdup(opts->new_branch);
setup_branch_path(new_branch_info);
}
@@ -1062,8 +1075,7 @@ static int switch_branches(const struct checkout_opts *opts,
struct branch_info *new_branch_info)
{
int ret = 0;
- struct branch_info old_branch_info;
- void *path_to_free;
+ struct branch_info old_branch_info = { 0 };
struct object_id rev;
int flag, writeout_error = 0;
int do_merge = 1;
@@ -1071,25 +1083,32 @@ static int switch_branches(const struct checkout_opts *opts,
trace2_cmd_mode("branch");
memset(&old_branch_info, 0, sizeof(old_branch_info));
- old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
+ old_branch_info.path = resolve_refdup("HEAD", 0, &rev, &flag);
if (old_branch_info.path)
old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
if (!(flag & REF_ISSYMREF))
- old_branch_info.path = NULL;
+ FREE_AND_NULL(old_branch_info.path);
- if (old_branch_info.path)
- skip_prefix(old_branch_info.path, "refs/heads/", &old_branch_info.name);
+ if (old_branch_info.path) {
+ const char *const prefix = "refs/heads/";
+ const char *p;
+ if (skip_prefix(old_branch_info.path, prefix, &p))
+ old_branch_info.name = xstrdup(p);
+ else
+ BUG("should be able to skip past '%s' in '%s'!",
+ prefix, old_branch_info.path);
+ }
if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
if (new_branch_info->name)
BUG("'switch --orphan' should never accept a commit as starting point");
new_branch_info->commit = NULL;
- new_branch_info->name = "(empty)";
+ new_branch_info->name = xstrdup("(empty)");
do_merge = 1;
}
if (!new_branch_info->name) {
- new_branch_info->name = "HEAD";
+ new_branch_info->name = xstrdup("HEAD");
new_branch_info->commit = old_branch_info.commit;
if (!new_branch_info->commit)
die(_("You are on a branch yet to be born"));
@@ -1102,7 +1121,7 @@ static int switch_branches(const struct checkout_opts *opts,
if (do_merge) {
ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
if (ret) {
- free(path_to_free);
+ branch_info_release(&old_branch_info);
return ret;
}
}
@@ -1113,7 +1132,8 @@ static int switch_branches(const struct checkout_opts *opts,
update_refs_for_switch(opts, &old_branch_info, new_branch_info);
ret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);
- free(path_to_free);
+ branch_info_release(&old_branch_info);
+
return ret || writeout_error;
}
@@ -1145,16 +1165,15 @@ static void setup_new_branch_info_and_source_tree(
struct tree **source_tree = &opts->source_tree;
struct object_id branch_rev;
- new_branch_info->name = arg;
+ new_branch_info->name = xstrdup(arg);
setup_branch_path(new_branch_info);
if (!check_refname_format(new_branch_info->path, 0) &&
!read_ref(new_branch_info->path, &branch_rev))
oidcpy(rev, &branch_rev);
- else {
- free((char *)new_branch_info->path);
- new_branch_info->path = NULL; /* not an existing branch */
- }
+ else
+ /* not an existing branch */
+ FREE_AND_NULL(new_branch_info->path);
new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
if (!new_branch_info->commit) {
@@ -1517,7 +1536,7 @@ static struct option *add_common_options(struct checkout_opts *opts,
OPT_BOOL(0, "progress", &opts->show_progress, N_("force progress reporting")),
OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge with the new branch")),
OPT_STRING(0, "conflict", &opts->conflict_style, N_("style"),
- N_("conflict style (merge or diff3)")),
+ N_("conflict style (merge, diff3, or zdiff3)")),
OPT_END()
};
struct option *newopts = parse_options_concat(prevopts, options);
@@ -1574,12 +1593,11 @@ static char cb_option = 'b';
static int checkout_main(int argc, const char **argv, const char *prefix,
struct checkout_opts *opts, struct option *options,
- const char * const usagestr[])
+ const char * const usagestr[],
+ struct branch_info *new_branch_info)
{
- struct branch_info new_branch_info;
int parseopt_flags = 0;
- memset(&new_branch_info, 0, sizeof(new_branch_info));
opts->overwrite_ignore = 1;
opts->prefix = prefix;
opts->show_progress = -1;
@@ -1688,7 +1706,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->track == BRANCH_TRACK_UNSPECIFIED &&
!opts->new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
- &new_branch_info, opts, &rev);
+ new_branch_info, opts, &rev);
argv += n;
argc -= n;
} else if (!opts->accept_ref && opts->from_treeish) {
@@ -1697,7 +1715,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (get_oid_mb(opts->from_treeish, &rev))
die(_("could not resolve %s"), opts->from_treeish);
- setup_new_branch_info_and_source_tree(&new_branch_info,
+ setup_new_branch_info_and_source_tree(new_branch_info,
opts, &rev,
opts->from_treeish);
@@ -1717,7 +1735,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
* Try to give more helpful suggestion.
* new_branch && argc > 1 will be caught later.
*/
- if (opts->new_branch && argc == 1 && !new_branch_info.commit)
+ if (opts->new_branch && argc == 1 && !new_branch_info->commit)
die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
argv[0], opts->new_branch);
@@ -1766,11 +1784,10 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
strbuf_release(&buf);
}
- UNLEAK(opts);
if (opts->patch_mode || opts->pathspec.nr)
- return checkout_paths(opts, &new_branch_info);
+ return checkout_paths(opts, new_branch_info);
else
- return checkout_branch(opts, &new_branch_info);
+ return checkout_branch(opts, new_branch_info);
}
int cmd_checkout(int argc, const char **argv, const char *prefix)
@@ -1789,6 +1806,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_END()
};
int ret;
+ struct branch_info new_branch_info = { 0 };
memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
@@ -1819,7 +1837,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
options = add_checkout_path_options(&opts, options);
ret = checkout_main(argc, argv, prefix, &opts,
- options, checkout_usage);
+ options, checkout_usage, &new_branch_info);
+ branch_info_release(&new_branch_info);
+ clear_pathspec(&opts.pathspec);
FREE_AND_NULL(options);
return ret;
}
@@ -1840,6 +1860,7 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
OPT_END()
};
int ret;
+ struct branch_info new_branch_info = { 0 };
memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
@@ -1859,7 +1880,8 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
cb_option = 'c';
ret = checkout_main(argc, argv, prefix, &opts,
- options, switch_branch_usage);
+ options, switch_branch_usage, &new_branch_info);
+ branch_info_release(&new_branch_info);
FREE_AND_NULL(options);
return ret;
}
@@ -1881,6 +1903,7 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
OPT_END()
};
int ret;
+ struct branch_info new_branch_info = { 0 };
memset(&opts, 0, sizeof(opts));
opts.accept_ref = 0;
@@ -1896,7 +1919,8 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
options = add_checkout_path_options(&opts, options);
ret = checkout_main(argc, argv, prefix, &opts,
- options, restore_usage);
+ options, restore_usage, &new_branch_info);
+ branch_info_release(&new_branch_info);
FREE_AND_NULL(options);
return ret;
}
diff --git a/builtin/credential.c b/builtin/credential.c
index d75dcdc64a..d7b304fa08 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -4,7 +4,7 @@
#include "config.h"
static const char usage_msg[] =
- "git credential [fill|approve|reject]";
+ "git credential (fill|approve|reject)";
int cmd_credential(int argc, const char **argv, const char *prefix)
{
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 4931c10845..4ee40fe3a0 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -202,15 +202,10 @@ static void changed_files(struct hashmap *result, const char *index_path,
{
struct child_process update_index = CHILD_PROCESS_INIT;
struct child_process diff_files = CHILD_PROCESS_INIT;
- struct strbuf index_env = STRBUF_INIT, buf = STRBUF_INIT;
- const char *git_dir = absolute_path(get_git_dir()), *env[] = {
- NULL, NULL
- };
+ struct strbuf buf = STRBUF_INIT;
+ const char *git_dir = absolute_path(get_git_dir());
FILE *fp;
- strbuf_addf(&index_env, "GIT_INDEX_FILE=%s", index_path);
- env[0] = index_env.buf;
-
strvec_pushl(&update_index.args,
"--git-dir", git_dir, "--work-tree", workdir,
"update-index", "--really-refresh", "-q",
@@ -222,7 +217,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
update_index.use_shell = 0;
update_index.clean_on_exit = 1;
update_index.dir = workdir;
- update_index.env = env;
+ strvec_pushf(&update_index.env_array, "GIT_INDEX_FILE=%s", index_path);
/* Ignore any errors of update-index */
run_command(&update_index);
@@ -235,7 +230,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
diff_files.clean_on_exit = 1;
diff_files.out = -1;
diff_files.dir = workdir;
- diff_files.env = env;
+ strvec_pushf(&diff_files.env_array, "GIT_INDEX_FILE=%s", index_path);
if (start_command(&diff_files))
die("could not obtain raw diff");
fp = xfdopen(diff_files.out, "r");
@@ -248,7 +243,6 @@ static void changed_files(struct hashmap *result, const char *index_path,
fclose(fp);
if (finish_command(&diff_files))
die("diff-files did not exit properly");
- strbuf_release(&index_env);
strbuf_release(&buf);
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index f7abbc31ff..e45185cf9c 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -28,6 +28,7 @@
#include "promisor-remote.h"
#include "commit-graph.h"
#include "shallow.h"
+#include "worktree.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -552,7 +553,7 @@ static struct ref *get_ref_map(struct remote *remote,
for (i = 0; i < fetch_refspec->nr; i++)
get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
} else if (refmap.nr) {
- die("--refmap option is only meaningful with command-line refspec(s).");
+ die("--refmap option is only meaningful with command-line refspec(s)");
} else {
/* Use the defaults */
struct branch *branch = branch_get(NULL);
@@ -583,7 +584,7 @@ static struct ref *get_ref_map(struct remote *remote,
} else if (!prefetch) {
ref_map = get_remote_ref(remote_refs, "HEAD");
if (!ref_map)
- die(_("Couldn't find remote ref HEAD"));
+ die(_("couldn't find remote ref HEAD"));
ref_map->fetch_head_status = FETCH_HEAD_MERGE;
tail = &ref_map->next;
}
@@ -848,13 +849,12 @@ static void format_display(struct strbuf *display, char code,
static int update_local_ref(struct ref *ref,
struct ref_transaction *transaction,
- const char *remote,
- const struct ref *remote_ref,
- struct strbuf *display,
- int summary_width)
+ const char *remote, const struct ref *remote_ref,
+ struct strbuf *display, int summary_width,
+ struct worktree **worktrees)
{
struct commit *current = NULL, *updated;
- struct branch *current_branch = branch_get(NULL);
+ const struct worktree *wt;
const char *pretty_ref = prettify_refname(ref->name);
int fast_forward = 0;
@@ -868,16 +868,17 @@ static int update_local_ref(struct ref *ref,
return 0;
}
- if (current_branch &&
- !strcmp(ref->name, current_branch->name) &&
- !(update_head_ok || is_bare_repository()) &&
- !is_null_oid(&ref->old_oid)) {
+ if (!update_head_ok &&
+ (wt = find_shared_symref(worktrees, "HEAD", ref->name)) &&
+ !wt->is_bare && !is_null_oid(&ref->old_oid)) {
/*
* If this is the head, and it's not okay to update
* the head, and the old value of the head isn't empty...
*/
format_display(display, '!', _("[rejected]"),
- _("can't fetch in current branch"),
+ wt->is_current ?
+ _("can't fetch in current branch") :
+ _("checked out in another worktree"),
remote, pretty_ref, summary_width);
return 1;
}
@@ -1067,16 +1068,17 @@ static void close_fetch_head(struct fetch_head *fetch_head)
}
static const char warn_show_forced_updates[] =
-N_("Fetch normally indicates which branches had a forced update,\n"
- "but that check has been disabled. To re-enable, use '--show-forced-updates'\n"
- "flag or run 'git config fetch.showForcedUpdates true'.");
+N_("fetch normally indicates which branches had a forced update,\n"
+ "but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
+ "flag or run 'git config fetch.showForcedUpdates true'");
static const char warn_time_show_forced_updates[] =
-N_("It took %.2f seconds to check forced updates. You can use\n"
+N_("it took %.2f seconds to check forced updates; you can use\n"
"'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates false'\n"
- " to avoid this check.\n");
+ "to avoid this check\n");
static int store_updated_refs(const char *raw_url, const char *remote_name,
- int connectivity_checked, struct ref *ref_map)
+ int connectivity_checked, struct ref *ref_map,
+ struct worktree **worktrees)
{
struct fetch_head fetch_head;
int url_len, i, rc = 0;
@@ -1205,7 +1207,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
strbuf_reset(&note);
if (ref) {
rc |= update_local_ref(ref, transaction, what,
- rm, &note, summary_width);
+ rm, &note, summary_width,
+ worktrees);
free(ref);
} else if (write_fetch_head || dry_run) {
/*
@@ -1298,7 +1301,9 @@ static int check_exist_and_connected(struct ref *ref_map)
return check_connected(iterate_ref_map, &rm, &opt);
}
-static int fetch_and_consume_refs(struct transport *transport, struct ref *ref_map)
+static int fetch_and_consume_refs(struct transport *transport,
+ struct ref *ref_map,
+ struct worktree **worktrees)
{
int connectivity_checked = 1;
int ret;
@@ -1319,10 +1324,8 @@ static int fetch_and_consume_refs(struct transport *transport, struct ref *ref_m
}
trace2_region_enter("fetch", "consume_refs", the_repository);
- ret = store_updated_refs(transport->url,
- transport->remote->name,
- connectivity_checked,
- ref_map);
+ ret = store_updated_refs(transport->url, transport->remote->name,
+ connectivity_checked, ref_map, worktrees);
trace2_region_leave("fetch", "consume_refs", the_repository);
out:
@@ -1385,18 +1388,18 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
return result;
}
-static void check_not_current_branch(struct ref *ref_map)
+static void check_not_current_branch(struct ref *ref_map,
+ struct worktree **worktrees)
{
- struct branch *current_branch = branch_get(NULL);
-
- if (is_bare_repository() || !current_branch)
- return;
-
+ const struct worktree *wt;
for (; ref_map; ref_map = ref_map->next)
- if (ref_map->peer_ref && !strcmp(current_branch->refname,
- ref_map->peer_ref->name))
- die(_("Refusing to fetch into current branch %s "
- "of non-bare repository"), current_branch->refname);
+ if (ref_map->peer_ref &&
+ (wt = find_shared_symref(worktrees, "HEAD",
+ ref_map->peer_ref->name)) &&
+ !wt->is_bare)
+ die(_("refusing to fetch into branch '%s' "
+ "checked out at '%s'"),
+ ref_map->peer_ref->name, wt->path);
}
static int truncate_fetch_head(void)
@@ -1414,10 +1417,10 @@ static void set_option(struct transport *transport, const char *name, const char
{
int r = transport_set_option(transport, name, value);
if (r < 0)
- die(_("Option \"%s\" value \"%s\" is not valid for %s"),
+ die(_("option \"%s\" value \"%s\" is not valid for %s"),
name, value, transport->url);
if (r > 0)
- warning(_("Option \"%s\" is ignored for %s\n"),
+ warning(_("option \"%s\" is ignored for %s\n"),
name, transport->url);
}
@@ -1451,7 +1454,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
old_nr = oids->nr;
for_each_glob_ref(add_oid, s, oids);
if (old_nr == oids->nr)
- warning("Ignoring --negotiation-tip=%s because it does not match any refs",
+ warning("ignoring --negotiation-tip=%s because it does not match any refs",
s);
}
smart_options->negotiation_tips = oids;
@@ -1489,12 +1492,13 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
if (transport->smart_options)
add_negotiation_tips(transport->smart_options);
else
- warning("Ignoring --negotiation-tip because the protocol does not support it.");
+ warning("ignoring --negotiation-tip because the protocol does not support it");
}
return transport;
}
-static void backfill_tags(struct transport *transport, struct ref *ref_map)
+static void backfill_tags(struct transport *transport, struct ref *ref_map,
+ struct worktree **worktrees)
{
int cannot_reuse;
@@ -1515,7 +1519,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
- fetch_and_consume_refs(transport, ref_map);
+ fetch_and_consume_refs(transport, ref_map, worktrees);
if (gsecondary) {
transport_disconnect(gsecondary);
@@ -1533,6 +1537,7 @@ static int do_fetch(struct transport *transport,
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
int must_list_refs = 1;
+ struct worktree **worktrees = get_worktrees();
if (tags == TAGS_DEFAULT) {
if (transport->remote->fetch_tags == 2)
@@ -1588,7 +1593,7 @@ static int do_fetch(struct transport *transport,
ref_map = get_ref_map(transport->remote, remote_refs, rs,
tags, &autotags);
if (!update_head_ok)
- check_not_current_branch(ref_map);
+ check_not_current_branch(ref_map, worktrees);
if (tags == TAGS_DEFAULT && autotags)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
@@ -1606,7 +1611,7 @@ static int do_fetch(struct transport *transport,
transport->url);
}
}
- if (fetch_and_consume_refs(transport, ref_map)) {
+ if (fetch_and_consume_refs(transport, ref_map, worktrees)) {
free_refs(ref_map);
retcode = 1;
goto cleanup;
@@ -1651,11 +1656,11 @@ static int do_fetch(struct transport *transport,
else
warning(_("unknown branch type"));
} else {
- warning(_("no source branch found.\n"
- "you need to specify exactly one branch with the --set-upstream option."));
+ warning(_("no source branch found;\n"
+ "you need to specify exactly one branch with the --set-upstream option"));
}
}
- skip:
+skip:
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
@@ -1665,11 +1670,12 @@ static int do_fetch(struct transport *transport,
ref_map = NULL;
find_non_local_tags(remote_refs, &ref_map, &tail);
if (ref_map)
- backfill_tags(transport, ref_map);
+ backfill_tags(transport, ref_map, worktrees);
free_refs(ref_map);
}
- cleanup:
+cleanup:
+ free_worktrees(worktrees);
return retcode;
}
@@ -1790,7 +1796,7 @@ static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
struct parallel_fetch_state *state = cb;
const char *remote = task_cb;
- state->result = error(_("Could not fetch %s"), remote);
+ state->result = error(_("could not fetch %s"), remote);
return 0;
}
@@ -1845,7 +1851,7 @@ static int fetch_multiple(struct string_list *list, int max_children)
if (verbosity >= 0)
printf(_("Fetching %s\n"), name);
if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
- error(_("Could not fetch %s"), name);
+ error(_("could not fetch %s"), name);
result = 1;
}
strvec_pop(&argv);
@@ -1906,8 +1912,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
int remote_via_config = remote_is_configured(remote, 0);
if (!remote)
- die(_("No remote repository specified. Please, specify either a URL or a\n"
- "remote name from which new revisions should be fetched."));
+ die(_("no remote repository specified; please specify either a URL or a\n"
+ "remote name from which new revisions should be fetched"));
gtransport = prepare_transport(remote, 1);
@@ -1942,7 +1948,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
if (!strcmp(argv[i], "tag")) {
i++;
if (i >= argc)
- die(_("You need to specify a tag name."));
+ die(_("you need to specify a tag name"));
refspec_appendf(&rs, "refs/tags/%s:refs/tags/%s",
argv[i], argv[i]);
@@ -2010,7 +2016,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (deepen_relative) {
if (deepen_relative < 0)
- die(_("Negative depth in --deepen is not supported"));
+ die(_("negative depth in --deepen is not supported"));
if (depth)
die(_("--deepen and --depth are mutually exclusive"));
depth = xstrfmt("%d", deepen_relative);
@@ -2047,14 +2053,15 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
/* All arguments are assumed to be remotes or groups */
for (i = 0; i < argc; i++)
if (!add_remote_or_group(argv[i], &list))
- die(_("No such remote or remote group: %s"), argv[i]);
+ die(_("no such remote or remote group: %s"),
+ argv[i]);
} else {
/* Single remote or group */
(void) add_remote_or_group(argv[0], &list);
if (list.nr > 1) {
/* More than one remote */
if (argc > 1)
- die(_("Fetching a group and specifying refspecs does not make sense"));
+ die(_("fetching a group and specifying refspecs does not make sense"));
} else {
/* Zero or one remotes */
remote = remote_get(argv[0]);
@@ -2075,7 +2082,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (gtransport->smart_options) {
gtransport->smart_options->acked_commits = &acked_commits;
} else {
- warning(_("Protocol does not support --negotiate-only, exiting."));
+ warning(_("protocol does not support --negotiate-only, exiting"));
return 1;
}
if (server_options.nr)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 27b9e78094..9e54892311 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -944,15 +944,13 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
if (the_repository->settings.core_commit_graph) {
struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
- const char *verify_argv[] = { "commit-graph", "verify", NULL, NULL, NULL };
prepare_alt_odb(the_repository);
for (odb = the_repository->objects->odb; odb; odb = odb->next) {
child_process_init(&commit_graph_verify);
- commit_graph_verify.argv = verify_argv;
commit_graph_verify.git_cmd = 1;
- verify_argv[2] = "--object-dir";
- verify_argv[3] = odb->path;
+ strvec_pushl(&commit_graph_verify.args, "commit-graph",
+ "verify", "--object-dir", odb->path, NULL);
if (run_command(&commit_graph_verify))
errors_found |= ERROR_COMMIT_GRAPH;
}
@@ -960,15 +958,13 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
if (the_repository->settings.core_multi_pack_index) {
struct child_process midx_verify = CHILD_PROCESS_INIT;
- const char *midx_argv[] = { "multi-pack-index", "verify", NULL, NULL, NULL };
prepare_alt_odb(the_repository);
for (odb = the_repository->objects->odb; odb; odb = odb->next) {
child_process_init(&midx_verify);
- midx_verify.argv = midx_argv;
midx_verify.git_cmd = 1;
- midx_argv[2] = "--object-dir";
- midx_argv[3] = odb->path;
+ strvec_pushl(&midx_verify.args, "multi-pack-index",
+ "verify", "--object-dir", odb->path, NULL);
if (run_command(&midx_verify))
errors_found |= ERROR_MULTI_PACK_INDEX;
}
diff --git a/builtin/help.c b/builtin/help.c
index 75cd2fb407..d387131dd8 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -212,11 +212,10 @@ static int check_emacsclient_version(void)
{
struct strbuf buffer = STRBUF_INIT;
struct child_process ec_process = CHILD_PROCESS_INIT;
- const char *argv_ec[] = { "emacsclient", "--version", NULL };
int version;
/* emacsclient prints its version number on stderr */
- ec_process.argv = argv_ec;
+ strvec_pushl(&ec_process.args, "emacsclient", "--version", NULL);
ec_process.err = -1;
ec_process.stdout_to_stderr = 1;
if (start_command(&ec_process))
diff --git a/builtin/log.c b/builtin/log.c
index f75d87e8d7..93ace0dde7 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -245,10 +245,24 @@ 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 (rev->commit_format == CMIT_FMT_USERFORMAT) {
+ if (!w.decorate) {
+ /*
+ * Disable decoration loading if the format will not
+ * show them anyway.
+ */
+ decoration_style = 0;
+ } else if (!decoration_style) {
+ /*
+ * If we are going to show them, make sure we do load
+ * them here, but taking care not to override a
+ * specific style set by config or --decorate.
+ */
+ decoration_style = DECORATE_SHORT_REFS;
+ }
+ }
- if (decoration_style) {
+ if (decoration_style || rev->simplify_by_decoration) {
const struct string_list *config_exclude =
repo_config_get_value_multi(the_repository,
"log.excludeDecoration");
@@ -260,7 +274,8 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
item->string);
}
- rev->show_decorations = 1;
+ if (decoration_style)
+ rev->show_decorations = 1;
load_ref_decorations(&decoration_filter, decoration_style);
}
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 06a2f90c48..e695867ee5 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -34,6 +34,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
+ OPT_SET_INT(0, "zdiff3", &xmp.style, N_("use a zealous diff3 based merge"),
+ XDL_MERGE_ZEALOUS_DIFF3),
OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
XDL_MERGE_FAVOR_OURS),
OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
diff --git a/builtin/merge.c b/builtin/merge.c
index ea3112e0c0..5f0476b0b7 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -310,10 +310,9 @@ static int save_state(struct object_id *stash)
int len;
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf buffer = STRBUF_INIT;
- const char *argv[] = {"stash", "create", NULL};
int rc = -1;
- cp.argv = argv;
+ strvec_pushl(&cp.args, "stash", "create", NULL);
cp.out = -1;
cp.git_cmd = 1;
diff --git a/builtin/notes.c b/builtin/notes.c
index 71c59583a1..118db9e455 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -134,14 +134,13 @@ static void copy_obj_to_fd(int fd, const struct object_id *oid)
static void write_commented_object(int fd, const struct object_id *object)
{
- const char *show_args[5] =
- {"show", "--stat", "--no-notes", oid_to_hex(object), NULL};
struct child_process show = CHILD_PROCESS_INIT;
struct strbuf buf = STRBUF_INIT;
struct strbuf cbuf = STRBUF_INIT;
/* Invoke "git show --stat --no-notes $object" */
- show.argv = show_args;
+ strvec_pushl(&show.args, "show", "--stat", "--no-notes",
+ oid_to_hex(object), NULL);
show.no_stdin = 1;
show.out = -1;
show.err = 0;
@@ -861,15 +860,19 @@ static int merge(int argc, const char **argv, const char *prefix)
update_ref(msg.buf, default_notes_ref(), &result_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
else { /* Merge has unresolved conflicts */
+ struct worktree **worktrees;
const struct worktree *wt;
/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
update_ref(msg.buf, "NOTES_MERGE_PARTIAL", &result_oid, NULL,
0, UPDATE_REFS_DIE_ON_ERR);
/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
- wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
+ worktrees = get_worktrees();
+ wt = find_shared_symref(worktrees, "NOTES_MERGE_REF",
+ default_notes_ref());
if (wt)
die(_("a notes merge into %s is already in-progress at %s"),
default_notes_ref(), wt->path);
+ free_worktrees(worktrees);
if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
die(_("failed to store link to current notes ref (%s)"),
default_notes_ref());
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 857be7826f..b36ed828d8 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -3397,7 +3397,7 @@ static void read_object_list_from_stdin(void)
if (feof(stdin))
break;
if (!ferror(stdin))
- die("BUG: fgets returned NULL, not EOF, not error!");
+ BUG("fgets returned NULL, not EOF, not error!");
if (errno != EINTR)
die_errno("fgets");
clearerr(stdin);
diff --git a/builtin/pull.c b/builtin/pull.c
index 1cfaf9f343..c8457619d8 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -970,7 +970,7 @@ static void show_advice_pull_non_ff(void)
"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 false # merge\n"
" git config pull.rebase true # rebase\n"
" git config pull.ff only # fast-forward only\n"
"\n"
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 49b846d960..4f92e6f059 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -175,7 +175,7 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
strbuf_addf(&fsck_msg_types, "%c%s=%s",
fsck_msg_types.len ? ',' : '=', var, value);
else
- warning("Skipping unknown msg id '%s'", var);
+ warning("skipping unknown msg id '%s'", var);
return 0;
}
@@ -769,8 +769,10 @@ static void prepare_push_cert_sha1(struct child_process *proc)
memset(&sigcheck, '\0', sizeof(sigcheck));
bogs = parse_signed_buffer(push_cert.buf, push_cert.len);
- check_signature(push_cert.buf, bogs, push_cert.buf + bogs,
- push_cert.len - bogs, &sigcheck);
+ sigcheck.payload = xmemdupz(push_cert.buf, bogs);
+ sigcheck.payload_len = bogs;
+ check_signature(&sigcheck, push_cert.buf + bogs,
+ push_cert.len - bogs);
nonce_status = check_nonce(push_cert.buf, bogs);
}
@@ -812,16 +814,13 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
{
struct child_process proc = CHILD_PROCESS_INIT;
struct async muxer;
- const char *argv[2];
int code;
+ const char *hook_path = find_hook(hook_name);
- argv[0] = find_hook(hook_name);
- if (!argv[0])
+ if (!hook_path)
return 0;
- argv[1] = NULL;
-
- proc.argv = argv;
+ strvec_push(&proc.args, hook_path);
proc.in = -1;
proc.stdout_to_stderr = 1;
proc.trace2_hook_name = hook_name;
@@ -943,23 +942,21 @@ static int run_receive_hook(struct command *commands,
static int run_update_hook(struct command *cmd)
{
- const char *argv[5];
struct child_process proc = CHILD_PROCESS_INIT;
int code;
+ const char *hook_path = find_hook("update");
- argv[0] = find_hook("update");
- if (!argv[0])
+ if (!hook_path)
return 0;
- argv[1] = cmd->ref_name;
- argv[2] = oid_to_hex(&cmd->old_oid);
- argv[3] = oid_to_hex(&cmd->new_oid);
- argv[4] = NULL;
+ strvec_push(&proc.args, hook_path);
+ strvec_push(&proc.args, cmd->ref_name);
+ strvec_push(&proc.args, oid_to_hex(&cmd->old_oid));
+ strvec_push(&proc.args, oid_to_hex(&cmd->new_oid));
proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
- proc.argv = argv;
proc.trace2_hook_name = "update";
code = start_command(&proc);
@@ -1117,22 +1114,20 @@ static int run_proc_receive_hook(struct command *commands,
struct child_process proc = CHILD_PROCESS_INIT;
struct async muxer;
struct command *cmd;
- const char *argv[2];
struct packet_reader reader;
struct strbuf cap = STRBUF_INIT;
struct strbuf errmsg = STRBUF_INIT;
int hook_use_push_options = 0;
int version = 0;
int code;
+ const char *hook_path = find_hook("proc-receive");
- argv[0] = find_hook("proc-receive");
- if (!argv[0]) {
+ if (!hook_path) {
rp_error("cannot find hook 'proc-receive'");
return -1;
}
- argv[1] = NULL;
- proc.argv = argv;
+ strvec_push(&proc.args, hook_path);
proc.in = -1;
proc.out = -1;
proc.trace2_hook_name = "proc-receive";
@@ -1370,23 +1365,11 @@ static const char *push_to_deploy(unsigned char *sha1,
struct strvec *env,
const char *work_tree)
{
- const char *update_refresh[] = {
- "update-index", "-q", "--ignore-submodules", "--refresh", NULL
- };
- const char *diff_files[] = {
- "diff-files", "--quiet", "--ignore-submodules", "--", NULL
- };
- const char *diff_index[] = {
- "diff-index", "--quiet", "--cached", "--ignore-submodules",
- NULL, "--", NULL
- };
- const char *read_tree[] = {
- "read-tree", "-u", "-m", NULL, NULL
- };
struct child_process child = CHILD_PROCESS_INIT;
- child.argv = update_refresh;
- child.env = env->v;
+ strvec_pushl(&child.args, "update-index", "-q", "--ignore-submodules",
+ "--refresh", NULL);
+ strvec_pushv(&child.env_array, env->v);
child.dir = work_tree;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
@@ -1396,8 +1379,9 @@ static const char *push_to_deploy(unsigned char *sha1,
/* run_command() does not clean up completely; reinitialize */
child_process_init(&child);
- child.argv = diff_files;
- child.env = env->v;
+ strvec_pushl(&child.args, "diff-files", "--quiet",
+ "--ignore-submodules", "--", NULL);
+ strvec_pushv(&child.env_array, env->v);
child.dir = work_tree;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
@@ -1405,12 +1389,13 @@ static const char *push_to_deploy(unsigned char *sha1,
if (run_command(&child))
return "Working directory has unstaged changes";
- /* diff-index with either HEAD or an empty tree */
- diff_index[4] = head_has_history() ? "HEAD" : empty_tree_oid_hex();
-
child_process_init(&child);
- child.argv = diff_index;
- child.env = env->v;
+ strvec_pushl(&child.args, "diff-index", "--quiet", "--cached",
+ "--ignore-submodules",
+ /* diff-index with either HEAD or an empty tree */
+ head_has_history() ? "HEAD" : empty_tree_oid_hex(),
+ "--", NULL);
+ strvec_pushv(&child.env_array, env->v);
child.no_stdin = 1;
child.no_stdout = 1;
child.stdout_to_stderr = 0;
@@ -1418,10 +1403,10 @@ static const char *push_to_deploy(unsigned char *sha1,
if (run_command(&child))
return "Working directory has staged changes";
- read_tree[3] = hash_to_hex(sha1);
child_process_init(&child);
- child.argv = read_tree;
- child.env = env->v;
+ strvec_pushl(&child.args, "read-tree", "-u", "-m", hash_to_hex(sha1),
+ NULL);
+ strvec_pushv(&child.env_array, env->v);
child.dir = work_tree;
child.no_stdin = 1;
child.no_stdout = 1;
@@ -1449,29 +1434,22 @@ static const char *push_to_checkout(unsigned char *hash,
static const char *update_worktree(unsigned char *sha1, const struct worktree *worktree)
{
- const char *retval, *work_tree, *git_dir = NULL;
+ const char *retval, *git_dir;
struct strvec env = STRVEC_INIT;
- if (worktree && worktree->path)
- work_tree = worktree->path;
- else if (git_work_tree_cfg)
- work_tree = git_work_tree_cfg;
- else
- work_tree = "..";
+ if (!worktree || !worktree->path)
+ BUG("worktree->path must be non-NULL");
- if (is_bare_repository())
+ if (worktree->is_bare)
return "denyCurrentBranch = updateInstead needs a worktree";
- if (worktree)
- git_dir = get_worktree_git_dir(worktree);
- if (!git_dir)
- git_dir = get_git_dir();
+ git_dir = get_worktree_git_dir(worktree);
strvec_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
if (!hook_exists(push_to_checkout_hook))
- retval = push_to_deploy(sha1, &env, work_tree);
+ retval = push_to_deploy(sha1, &env, worktree->path);
else
- retval = push_to_checkout(sha1, &env, work_tree);
+ retval = push_to_checkout(sha1, &env, worktree->path);
strvec_clear(&env);
return retval;
@@ -1486,19 +1464,22 @@ static const char *update(struct command *cmd, struct shallow_info *si)
struct object_id *old_oid = &cmd->old_oid;
struct object_id *new_oid = &cmd->new_oid;
int do_update_worktree = 0;
- const struct worktree *worktree = is_bare_repository() ? NULL : find_shared_symref("HEAD", name);
+ struct worktree **worktrees = get_worktrees();
+ const struct worktree *worktree =
+ find_shared_symref(worktrees, "HEAD", name);
/* only refs/... are allowed */
if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
rp_error("refusing to create funny ref '%s' remotely", name);
- return "funny refname";
+ ret = "funny refname";
+ goto out;
}
strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
free(namespaced_name);
namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
- if (worktree) {
+ if (worktree && !worktree->is_bare) {
switch (deny_current_branch) {
case DENY_IGNORE:
break;
@@ -1510,7 +1491,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
rp_error("refusing to update checked out branch: %s", name);
if (deny_current_branch == DENY_UNCONFIGURED)
refuse_unconfigured_deny();
- return "branch is currently checked out";
+ ret = "branch is currently checked out";
+ goto out;
case DENY_UPDATE_INSTEAD:
/* pass -- let other checks intervene first */
do_update_worktree = 1;
@@ -1521,13 +1503,15 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (!is_null_oid(new_oid) && !has_object_file(new_oid)) {
error("unpack should have generated %s, "
"but I can't find it!", oid_to_hex(new_oid));
- return "bad pack";
+ ret = "bad pack";
+ goto out;
}
if (!is_null_oid(old_oid) && is_null_oid(new_oid)) {
if (deny_deletes && starts_with(name, "refs/heads/")) {
rp_error("denying ref deletion for %s", name);
- return "deletion prohibited";
+ ret = "deletion prohibited";
+ goto out;
}
if (worktree || (head_name && !strcmp(namespaced_name, head_name))) {
@@ -1543,9 +1527,11 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (deny_delete_current == DENY_UNCONFIGURED)
refuse_unconfigured_deny_delete_current();
rp_error("refusing to delete the current branch: %s", name);
- return "deletion of the current branch prohibited";
+ ret = "deletion of the current branch prohibited";
+ goto out;
default:
- return "Invalid denyDeleteCurrent setting";
+ ret = "Invalid denyDeleteCurrent setting";
+ goto out;
}
}
}
@@ -1563,25 +1549,28 @@ static const char *update(struct command *cmd, struct shallow_info *si)
old_object->type != OBJ_COMMIT ||
new_object->type != OBJ_COMMIT) {
error("bad sha1 objects for %s", name);
- return "bad ref";
+ ret = "bad ref";
+ goto out;
}
old_commit = (struct commit *)old_object;
new_commit = (struct commit *)new_object;
if (!in_merge_bases(old_commit, new_commit)) {
rp_error("denying non-fast-forward %s"
" (you should pull first)", name);
- return "non-fast-forward";
+ ret = "non-fast-forward";
+ goto out;
}
}
if (run_update_hook(cmd)) {
rp_error("hook declined to update %s", name);
- return "hook declined";
+ ret = "hook declined";
+ goto out;
}
if (do_update_worktree) {
- ret = update_worktree(new_oid->hash, find_shared_symref("HEAD", name));
+ ret = update_worktree(new_oid->hash, worktree);
if (ret)
- return ret;
+ goto out;
}
if (is_null_oid(new_oid)) {
@@ -1589,9 +1578,9 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (!parse_object(the_repository, old_oid)) {
old_oid = NULL;
if (ref_exists(name)) {
- rp_warning("Allowing deletion of corrupt ref.");
+ rp_warning("allowing deletion of corrupt ref");
} else {
- rp_warning("Deleting a non-existent ref.");
+ rp_warning("deleting a non-existent ref");
cmd->did_not_exist = 1;
}
}
@@ -1600,17 +1589,19 @@ static const char *update(struct command *cmd, struct shallow_info *si)
old_oid,
0, "push", &err)) {
rp_error("%s", err.buf);
- strbuf_release(&err);
- return "failed to delete";
+ ret = "failed to delete";
+ } else {
+ ret = NULL; /* good */
}
strbuf_release(&err);
- return NULL; /* good */
}
else {
struct strbuf err = STRBUF_INIT;
if (shallow_update && si->shallow_ref[cmd->index] &&
- update_shallow_ref(cmd, si))
- return "shallow error";
+ update_shallow_ref(cmd, si)) {
+ ret = "shallow error";
+ goto out;
+ }
if (ref_transaction_update(transaction,
namespaced_name,
@@ -1618,14 +1609,16 @@ static const char *update(struct command *cmd, struct shallow_info *si)
0, "push",
&err)) {
rp_error("%s", err.buf);
- strbuf_release(&err);
-
- return "failed to update ref";
+ ret = "failed to update ref";
+ } else {
+ ret = NULL; /* good */
}
strbuf_release(&err);
-
- return NULL; /* good */
}
+
+out:
+ free_worktrees(worktrees);
+ return ret;
}
static void run_update_post_hook(struct command *commands)
@@ -2219,7 +2212,8 @@ static const char *unpack(int err_fd, struct shallow_info *si)
close(err_fd);
return "unable to create temporary object directory";
}
- child.env = tmp_objdir_env(tmp_objdir);
+ if (tmp_objdir)
+ strvec_pushv(&child.env_array, tmp_objdir_env(tmp_objdir));
/*
* Normally we just pass the tmp_objdir environment to the child
@@ -2490,9 +2484,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0);
if (argc > 1)
- usage_msg_opt(_("Too many arguments."), receive_pack_usage, options);
+ usage_msg_opt(_("too many arguments"), receive_pack_usage, options);
if (argc == 0)
- usage_msg_opt(_("You must specify a directory."), receive_pack_usage, options);
+ usage_msg_opt(_("you must specify a directory"), receive_pack_usage, options);
service_dir = argv[0];
@@ -2566,25 +2560,25 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
&push_options);
if (pack_lockfile)
unlink_or_warn(pack_lockfile);
+ sigchain_push(SIGPIPE, SIG_IGN);
if (report_status_v2)
report_v2(commands, unpack_status);
else if (report_status)
report(commands, unpack_status);
+ sigchain_pop(SIGPIPE);
run_receive_hook(commands, "post-receive", 1,
&push_options);
run_update_post_hook(commands);
string_list_clear(&push_options, 0);
if (auto_gc) {
- const char *argv_gc_auto[] = {
- "gc", "--auto", "--quiet", NULL,
- };
struct child_process proc = CHILD_PROCESS_INIT;
proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
proc.git_cmd = proc.close_object_store = 1;
- proc.argv = argv_gc_auto;
+ strvec_pushl(&proc.args, "gc", "--auto", "--quiet",
+ NULL);
if (!start_command(&proc)) {
if (use_sideband)
diff --git a/builtin/repack.c b/builtin/repack.c
index 9b74e0d468..9b0be6a6ab 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -844,7 +844,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
fname_old = mkpathdup("%s-%s%s",
packtmp, item->string, exts[ext].name);
- if (((uintptr_t)item->util) & (1 << ext)) {
+ if (((uintptr_t)item->util) & ((uintptr_t)1 << ext)) {
struct stat statbuffer;
if (!stat(fname_old, &statbuffer)) {
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
diff --git a/builtin/replace.c b/builtin/replace.c
index 946938d011..6ff1734d58 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -258,11 +258,10 @@ static int import_object(struct object_id *oid, enum object_type type,
return error_errno(_("unable to open %s for reading"), filename);
if (!raw && type == OBJ_TREE) {
- const char *argv[] = { "mktree", NULL };
struct child_process cmd = CHILD_PROCESS_INIT;
struct strbuf result = STRBUF_INIT;
- cmd.argv = argv;
+ strvec_push(&cmd.args, "mktree");
cmd.git_cmd = 1;
cmd.in = fd;
cmd.out = -1;
diff --git a/builtin/reset.c b/builtin/reset.c
index 7393595349..b1ff699b43 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -25,6 +25,7 @@
#include "cache-tree.h"
#include "submodule.h"
#include "submodule-config.h"
+#include "dir.h"
#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
@@ -136,21 +137,36 @@ static void update_index_from_diff(struct diff_queue_struct *q,
int intent_to_add = *(int *)data;
for (i = 0; i < q->nr; i++) {
+ int pos;
struct diff_filespec *one = q->queue[i]->one;
- int is_missing = !(one->mode && !is_null_oid(&one->oid));
+ int is_in_reset_tree = one->mode && !is_null_oid(&one->oid);
struct cache_entry *ce;
- if (is_missing && !intent_to_add) {
+ if (!is_in_reset_tree && !intent_to_add) {
remove_file_from_cache(one->path);
continue;
}
ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
0, 0);
+
+ /*
+ * If the file 1) corresponds to an existing index entry with
+ * skip-worktree set, or 2) does not exist in the index but is
+ * outside the sparse checkout definition, add a skip-worktree bit
+ * to the new index entry. Note that a sparse index will be expanded
+ * if this entry is outside the sparse cone - this is necessary
+ * to properly construct the reset sparse directory.
+ */
+ pos = cache_name_pos(one->path, strlen(one->path));
+ if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) ||
+ (pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))
+ ce->ce_flags |= CE_SKIP_WORKTREE;
+
if (!ce)
die(_("make_cache_entry failed for path '%s'"),
one->path);
- if (is_missing) {
+ if (!is_in_reset_tree) {
ce->ce_flags |= CE_INTENT_TO_ADD;
set_object_name_for_intent_to_add_entry(ce);
}
@@ -158,6 +174,82 @@ static void update_index_from_diff(struct diff_queue_struct *q,
}
}
+static int pathspec_needs_expanded_index(const struct pathspec *pathspec)
+{
+ unsigned int i, pos;
+ int res = 0;
+ char *skip_worktree_seen = NULL;
+
+ /*
+ * When using a magic pathspec, assume for the sake of simplicity that
+ * the index needs to be expanded to match all matchable files.
+ */
+ if (pathspec->magic)
+ return 1;
+
+ for (i = 0; i < pathspec->nr; i++) {
+ struct pathspec_item item = pathspec->items[i];
+
+ /*
+ * If the pathspec item has a wildcard, the index should be expanded
+ * if the pathspec has the possibility of matching a subset of entries inside
+ * of a sparse directory (but not the entire directory).
+ *
+ * If the pathspec item is a literal path, the index only needs to be expanded
+ * if a) the pathspec isn't in the sparse checkout cone (to make sure we don't
+ * expand for in-cone files) and b) it doesn't match any sparse directories
+ * (since we can reset whole sparse directories without expanding them).
+ */
+ if (item.nowildcard_len < item.len) {
+ /*
+ * Special case: if the pattern is a path inside the cone
+ * followed by only wildcards, the pattern cannot match
+ * partial sparse directories, so we don't expand the index.
+ */
+ if (path_in_cone_mode_sparse_checkout(item.original, &the_index) &&
+ strspn(item.original + item.nowildcard_len, "*") == item.len - item.nowildcard_len)
+ continue;
+
+ for (pos = 0; pos < active_nr; pos++) {
+ struct cache_entry *ce = active_cache[pos];
+
+ if (!S_ISSPARSEDIR(ce->ce_mode))
+ continue;
+
+ /*
+ * If the pre-wildcard length is longer than the sparse
+ * directory name and the sparse directory is the first
+ * component of the pathspec, need to expand the index.
+ */
+ if (item.nowildcard_len > ce_namelen(ce) &&
+ !strncmp(item.original, ce->name, ce_namelen(ce))) {
+ res = 1;
+ break;
+ }
+
+ /*
+ * If the pre-wildcard length is shorter than the sparse
+ * directory and the pathspec does not match the whole
+ * directory, need to expand the index.
+ */
+ if (!strncmp(item.original, ce->name, item.nowildcard_len) &&
+ wildmatch(item.original, ce->name, 0)) {
+ res = 1;
+ break;
+ }
+ }
+ } else if (!path_in_cone_mode_sparse_checkout(item.original, &the_index) &&
+ !matches_skip_worktree(pathspec, i, &skip_worktree_seen))
+ res = 1;
+
+ if (res > 0)
+ break;
+ }
+
+ free(skip_worktree_seen);
+ return res;
+}
+
static int read_from_tree(const struct pathspec *pathspec,
struct object_id *tree_oid,
int intent_to_add)
@@ -170,7 +262,13 @@ static int read_from_tree(const struct pathspec *pathspec,
opt.format_callback = update_index_from_diff;
opt.format_callback_data = &intent_to_add;
opt.flags.override_submodule_config = 1;
+ opt.flags.recursive = 1;
opt.repo = the_repository;
+ opt.change = diff_change;
+ opt.add_remove = diff_addremove;
+
+ if (pathspec->nr && the_index.sparse_index && pathspec_needs_expanded_index(pathspec))
+ ensure_full_index(&the_index);
if (do_diff_cache(tree_oid, &opt))
return 1;
@@ -249,9 +347,6 @@ static void parse_args(struct pathspec *pathspec,
}
*rev_ret = rev;
- if (read_cache() < 0)
- die(_("index file corrupt"));
-
parse_pathspec(pathspec, 0,
PATHSPEC_PREFER_FULL |
(patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),
@@ -397,6 +492,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (intent_to_add && reset_type != MIXED)
die(_("-N can only be used with --mixed"));
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
+ if (read_cache() < 0)
+ die(_("index file corrupt"));
+
/* Soft reset does not touch the index file nor the working tree
* at all, but requires them in a good order. Other resets reset
* the index file to the tree object we are switching to. */
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 082449293b..f1e8318592 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -761,6 +761,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
char *logmsg;
char *nth_desc;
const char *msg;
+ char *end;
timestamp_t timestamp;
int tz;
@@ -770,11 +771,12 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
reflog = i;
break;
}
- msg = strchr(logmsg, '\t');
- if (!msg)
- msg = "(none)";
- else
- msg++;
+
+ end = strchr(logmsg, '\n');
+ if (end)
+ *end = '\0';
+
+ msg = (*logmsg == '\0') ? "(none)" : logmsg;
reflog_msg[i] = xstrfmt("(%s) %s",
show_date(timestamp, tz,
DATE_MODE(RELATIVE)),
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index e630f0c730..9b25a508e6 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1503,16 +1503,17 @@ static void deinit_submodule(const char *path, const char *prefix,
struct strbuf sb_rm = STRBUF_INIT;
const char *format;
- /*
- * protect submodules containing a .git directory
- * NEEDSWORK: instead of dying, automatically call
- * absorbgitdirs and (possibly) warn.
- */
- if (is_directory(sub_git_dir))
- die(_("Submodule work tree '%s' contains a .git "
- "directory (use 'rm -rf' if you really want "
- "to remove it including all of its history)"),
- displaypath);
+ if (is_directory(sub_git_dir)) {
+ if (!(flags & OPT_QUIET))
+ warning(_("Submodule work tree '%s' contains a .git "
+ "directory. This will be replaced with a "
+ ".git file by using absorbgitdirs."),
+ displaypath);
+
+ absorb_git_dir_into_superproject(path,
+ ABSORB_GITDIR_RECURSE_SUBMODULES);
+
+ }
if (!(flags & OPT_FORCE)) {
struct child_process cp_rm = CHILD_PROCESS_INIT;
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 24654b4c9b..98d028dae6 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -77,7 +77,7 @@ static ssize_t process_input(int child_fd, int band)
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
{
- struct child_process writer = { argv };
+ struct child_process writer = CHILD_PROCESS_INIT;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(upload_archive_usage);
@@ -89,9 +89,10 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
* multiplexed out to our fd#1. If the child dies, we tell the other
* end over channel #3.
*/
- argv[0] = "upload-archive--writer";
writer.out = writer.err = -1;
writer.git_cmd = 1;
+ strvec_push(&writer.args, "upload-archive--writer");
+ strvec_pushv(&writer.args, argv + 1);
if (start_command(&writer)) {
int err = errno;
packet_write_fmt(1, "NACK unable to spawn subprocess\n");
diff --git a/builtin/var.c b/builtin/var.c
index 6c6f46b4ae..491db27429 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -5,6 +5,7 @@
*/
#include "builtin.h"
#include "config.h"
+#include "refs.h"
static const char var_usage[] = "git var (-l | <variable>)";
@@ -27,6 +28,11 @@ static const char *pager(int flag)
return pgm;
}
+static const char *default_branch(int flag)
+{
+ return git_default_branch_name(1);
+}
+
struct git_var {
const char *name;
const char *(*read)(int);
@@ -36,6 +42,7 @@ static struct git_var git_vars[] = {
{ "GIT_AUTHOR_IDENT", git_author_info },
{ "GIT_EDITOR", editor },
{ "GIT_PAGER", pager },
+ { "GIT_DEFAULT_BRANCH", default_branch },
{ "", NULL },
};
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d22ece93e1..a396cfdc64 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -72,7 +72,7 @@ static void delete_worktrees_dir_if_empty(void)
static void prune_worktree(const char *id, const char *reason)
{
if (show_only || verbose)
- printf_ln(_("Removing %s/%s: %s"), "worktrees", id, reason);
+ fprintf_ln(stderr, _("Removing %s/%s: %s"), "worktrees", id, reason);
if (!show_only)
delete_git_dir(id);
}
@@ -349,18 +349,18 @@ static int add_worktree(const char *path, const char *refname,
strvec_push(&cp.args, "--quiet");
}
- cp.env = child_env.v;
+ strvec_pushv(&cp.env_array, child_env.v);
ret = run_command(&cp);
if (ret)
goto done;
if (opts->checkout) {
- cp.argv = NULL;
- strvec_clear(&cp.args);
+ struct child_process cp = CHILD_PROCESS_INIT;
+ cp.git_cmd = 1;
strvec_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
if (opts->quiet)
strvec_push(&cp.args, "--quiet");
- cp.env = child_env.v;
+ strvec_pushv(&cp.env_array, child_env.v);
ret = run_command(&cp);
if (ret)
goto done;
@@ -385,12 +385,11 @@ done:
const char *hook = find_hook("post-checkout");
if (hook) {
const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
- cp.git_cmd = 0;
+ struct child_process cp = CHILD_PROCESS_INIT;
cp.no_stdin = 1;
cp.stdout_to_stderr = 1;
cp.dir = path;
- cp.env = env;
- cp.argv = NULL;
+ strvec_pushv(&cp.env_array, env);
cp.trace2_hook_name = "post-checkout";
strvec_pushl(&cp.args, absolute_path(hook),
oid_to_hex(null_oid()),
@@ -418,24 +417,24 @@ static void print_preparing_worktree_line(int detach,
if (force_new_branch) {
struct commit *commit = lookup_commit_reference_by_name(new_branch);
if (!commit)
- printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
+ fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
else
- printf_ln(_("Preparing worktree (resetting branch '%s'; was at %s)"),
+ fprintf_ln(stderr, _("Preparing worktree (resetting branch '%s'; was at %s)"),
new_branch,
find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
} else if (new_branch) {
- printf_ln(_("Preparing worktree (new branch '%s')"), new_branch);
+ fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
} else {
struct strbuf s = STRBUF_INIT;
if (!detach && !strbuf_check_branch_ref(&s, branch) &&
ref_exists(s.buf))
- printf_ln(_("Preparing worktree (checking out '%s')"),
+ fprintf_ln(stderr, _("Preparing worktree (checking out '%s')"),
branch);
else {
struct commit *commit = lookup_commit_reference_by_name(branch);
if (!commit)
die(_("invalid reference: %s"), branch);
- printf_ln(_("Preparing worktree (detached HEAD %s)"),
+ fprintf_ln(stderr, _("Preparing worktree (detached HEAD %s)"),
find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV));
}
strbuf_release(&s);
@@ -1006,7 +1005,7 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
static void report_repair(int iserr, const char *path, const char *msg, void *cb_data)
{
if (!iserr) {
- printf_ln(_("repair: %s: %s"), msg, path);
+ fprintf_ln(stderr, _("repair: %s: %s"), msg, path);
} else {
int *exit_status = (int *)cb_data;
fprintf_ln(stderr, _("error: %s: %s"), msg, path);