aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/bundle.c5
-rw-r--r--builtin/checkout.c21
-rw-r--r--builtin/commit.c2
-rw-r--r--builtin/config.c2
-rw-r--r--builtin/diff-tree.c13
-rw-r--r--builtin/get-tar-commit-id.c1
-rw-r--r--builtin/index-pack.c9
-rw-r--r--builtin/ls-remote.c15
-rw-r--r--builtin/notes.c22
-rw-r--r--builtin/patch-id.c93
-rw-r--r--builtin/stash.c23
11 files changed, 161 insertions, 45 deletions
diff --git a/builtin/bundle.c b/builtin/bundle.c
index d5d41a8f67..86d0ed7049 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -207,12 +207,13 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
+ if (!startup_info->have_repository)
+ die(_("Need a repository to unbundle."));
+
if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
ret = 1;
goto cleanup;
}
- if (!startup_info->have_repository)
- die(_("Need a repository to unbundle."));
if (progress)
strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
_("Unbundling objects"), NULL);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 3cf44b4683..1748d68c96 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1572,6 +1572,10 @@ static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts,
static int checkout_branch(struct checkout_opts *opts,
struct branch_info *new_branch_info)
{
+ int noop_switch = (!new_branch_info->name &&
+ !opts->new_branch &&
+ !opts->force_detach);
+
if (opts->pathspec.nr)
die(_("paths cannot be used with switching branches"));
@@ -1583,9 +1587,14 @@ static int checkout_branch(struct checkout_opts *opts,
die(_("'%s' cannot be used with switching branches"),
"--[no]-overlay");
- if (opts->writeout_stage)
- die(_("'%s' cannot be used with switching branches"),
- "--ours/--theirs");
+ if (opts->writeout_stage) {
+ const char *msg;
+ if (noop_switch)
+ msg = _("'%s' needs the paths to check out");
+ else
+ msg = _("'%s' cannot be used with switching branches");
+ die(msg, "--ours/--theirs");
+ }
if (opts->force && opts->merge)
die(_("'%s' cannot be used with '%s'"), "-f", "-m");
@@ -1612,10 +1621,8 @@ static int checkout_branch(struct checkout_opts *opts,
die(_("Cannot switch branch to a non-commit '%s'"),
new_branch_info->name);
- if (!opts->switch_branch_doing_nothing_is_ok &&
- !new_branch_info->name &&
- !opts->new_branch &&
- !opts->force_detach)
+ if (noop_switch &&
+ !opts->switch_branch_doing_nothing_is_ok)
die(_("missing branch or commit argument"));
if (!opts->implicit_detach &&
diff --git a/builtin/commit.c b/builtin/commit.c
index dec78dfb86..66427ba82d 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -41,7 +41,7 @@
static const char * const builtin_commit_usage[] = {
N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
- " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]\n"
+ " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]\n"
" [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
" [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
" [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
diff --git a/builtin/config.c b/builtin/config.c
index 20a0b64090..97e4d5f57c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -17,7 +17,7 @@
static const char *const builtin_config_usage[] = {
N_("git config list [<file-option>] [<display-option>] [--includes]"),
- N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
N_("git config rename-section [<file-option>] <old-name> <new-name>"),
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 0d3c611aac..b8df1d4b79 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -8,6 +8,7 @@
#include "read-cache-ll.h"
#include "repository.h"
#include "revision.h"
+#include "tmp-objdir.h"
#include "tree.h"
static struct rev_info log_tree_opt;
@@ -166,6 +167,13 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
opt->diffopt.rotate_to_strict = 1;
+ if (opt->remerge_diff) {
+ opt->remerge_objdir = tmp_objdir_create("remerge-diff");
+ if (!opt->remerge_objdir)
+ die(_("unable to create temporary object directory"));
+ tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1);
+ }
+
/*
* NOTE! We expect "a..b" to expand to "^a b" but it is
* perfectly valid for revision range parser to yield "b ^a",
@@ -230,5 +238,10 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
diff_free(&opt->diffopt);
}
+ if (opt->remerge_diff) {
+ tmp_objdir_destroy(opt->remerge_objdir);
+ opt->remerge_objdir = NULL;
+ }
+
return diff_result_code(&opt->diffopt);
}
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index 66a7389f9f..7195a072ed 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -35,6 +35,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix
if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER)
return 1;
+ errno = 0;
len = strtol(content, &end, 10);
if (errno == ERANGE || end == content || len < 0)
return 1;
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index fd968d673d..763b01372a 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1868,6 +1868,15 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (!index_name && pack_name)
index_name = derive_filename(pack_name, "pack", "idx", &index_name_buf);
+ /*
+ * Packfiles and indices do not carry enough information to be able to
+ * identify their object hash. So when we are neither in a repository
+ * nor has the user told us which object hash to use we have no other
+ * choice but to guess the object hash.
+ */
+ if (!the_repository->hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
if (rev_index) {
opts.flags |= verify ? WRITE_REV_VERIFY : WRITE_REV;
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index debf2d4f88..6da63a67f5 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -91,6 +91,21 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION);
dest = argv[0];
+ /*
+ * TODO: This is buggy, but required for transport helpers. When a
+ * transport helper advertises a "refspec", then we'd add that to a
+ * list of refspecs via `refspec_append()`, which transitively depends
+ * on `the_hash_algo`. Thus, when the hash algorithm isn't properly set
+ * up, this would lead to a segfault.
+ *
+ * We really should fix this in the transport helper logic such that we
+ * lazily parse refspec capabilities _after_ we have learned about the
+ * remote's object format. Otherwise, we may end up misparsing refspecs
+ * depending on what object hash the remote uses.
+ */
+ if (!the_repository->hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
packet_trace_identity("ls-remote");
if (argc > 1) {
diff --git a/builtin/notes.c b/builtin/notes.c
index d9c356e354..4cc5bfedc3 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -114,7 +114,6 @@ struct note_msg {
};
struct note_data {
- int given;
int use_editor;
int stripspace;
char *edit_path;
@@ -193,7 +192,7 @@ static void write_commented_object(int fd, const struct object_id *object)
static void prepare_note_data(const struct object_id *object, struct note_data *d,
const struct object_id *old_note)
{
- if (d->use_editor || !d->given) {
+ if (d->use_editor || !d->msg_nr) {
int fd;
struct strbuf buf = STRBUF_INIT;
@@ -201,7 +200,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
d->edit_path = git_pathdup("NOTES_EDITMSG");
fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (d->given)
+ if (d->msg_nr)
write_or_die(fd, d->buf.buf, d->buf.len);
else if (old_note)
copy_obj_to_fd(fd, old_note);
@@ -515,7 +514,6 @@ static int add(int argc, const char **argv, const char *prefix)
if (d.msg_nr)
concat_messages(&d);
- d.given = !!d.buf.len;
object_ref = argc > 1 ? argv[1] : "HEAD";
@@ -528,7 +526,7 @@ static int add(int argc, const char **argv, const char *prefix)
if (note) {
if (!force) {
free_notes(t);
- if (d.given) {
+ if (d.msg_nr) {
free_note_data(&d);
return error(_("Cannot add notes. "
"Found existing notes for object %s. "
@@ -690,14 +688,14 @@ static int append_edit(int argc, const char **argv, const char *prefix)
usage_with_options(usage, options);
}
- if (d.msg_nr)
+ if (d.msg_nr) {
concat_messages(&d);
- d.given = !!d.buf.len;
-
- if (d.given && edit)
- fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
- "for the 'edit' subcommand.\n"
- "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"));
+ if (edit)
+ fprintf(stderr, _("The -m/-F/-c/-C options have been "
+ "deprecated for the 'edit' subcommand.\n"
+ "Please use 'git notes add -f -m/-F/-c/-C' "
+ "instead.\n"));
+ }
object_ref = 1 < argc ? argv[1] : "HEAD";
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index d790ae6354..35c1179f7e 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -7,10 +7,9 @@
#include "parse-options.h"
#include "setup.h"
-static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
+static void flush_current_id(struct object_id *id, struct object_id *result)
{
- if (patchlen)
- printf("%s %s\n", oid_to_hex(result), oid_to_hex(id));
+ printf("%s %s\n", oid_to_hex(result), oid_to_hex(id));
}
static int remove_space(char *line)
@@ -60,9 +59,27 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
return 1;
}
+/*
+ * flag bits to control get_one_patchid()'s behaviour.
+ *
+ * STABLE/VERBATIM are given from the command line option as
+ * --stable/--verbatim. FIND_HEADER conveys the internal state
+ * maintained by the caller to allow the function to avoid mistaking
+ * lines of log message before seeing the "diff" part as the beginning
+ * of the next patch.
+ */
+enum {
+ GOPID_STABLE = (1<<0), /* --stable */
+ GOPID_VERBATIM = (1<<1), /* --verbatim */
+ GOPID_FIND_HEADER = (1<<2), /* stop at the beginning of patch message */
+};
+
static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
- struct strbuf *line_buf, int stable, int verbatim)
+ struct strbuf *line_buf, unsigned flags)
{
+ int stable = flags & GOPID_STABLE;
+ int verbatim = flags & GOPID_VERBATIM;
+ int find_header = flags & GOPID_FIND_HEADER;
int patchlen = 0, found_next = 0;
int before = -1, after = -1;
int diff_is_binary = 0;
@@ -77,24 +94,40 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
const char *p = line;
int len;
- /* Possibly skip over the prefix added by "log" or "format-patch" */
- if (!skip_prefix(line, "commit ", &p) &&
- !skip_prefix(line, "From ", &p) &&
- starts_with(line, "\\ ") && 12 < strlen(line)) {
- if (verbatim)
- the_hash_algo->update_fn(&ctx, line, strlen(line));
- continue;
- }
-
- if (!get_oid_hex(p, next_oid)) {
- found_next = 1;
- break;
+ /*
+ * The caller hasn't seen us find a patch header and
+ * return to it, or we have started processing patch
+ * and may encounter the beginning of the next patch.
+ */
+ if (find_header) {
+ /*
+ * If we see a line that begins with "<object name>",
+ * "commit <object name>" or "From <object name>", it is
+ * the beginning of a patch. Return to the caller, as
+ * we are done with the one we have been processing.
+ */
+ if (skip_prefix(line, "commit ", &p))
+ ;
+ else if (skip_prefix(line, "From ", &p))
+ ;
+ if (!get_oid_hex(p, next_oid)) {
+ if (verbatim)
+ the_hash_algo->update_fn(&ctx, line, strlen(line));
+ found_next = 1;
+ break;
+ }
}
/* Ignore commit comments */
if (!patchlen && !starts_with(line, "diff "))
continue;
+ /*
+ * We are past the commit log message. Prepare to
+ * stop at the beginning of the next patch header.
+ */
+ find_header = 1;
+
/* Parsing diff header? */
if (before == -1) {
if (starts_with(line, "GIT binary patch") ||
@@ -127,6 +160,16 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
break;
}
+ /*
+ * A hunk about an incomplete line may have this
+ * marker at the end, which should just be ignored.
+ */
+ if (starts_with(line, "\\ ") && 12 < strlen(line)) {
+ if (verbatim)
+ the_hash_algo->update_fn(&ctx, line, strlen(line));
+ continue;
+ }
+
if (diff_is_binary) {
if (starts_with(line, "diff ")) {
diff_is_binary = 0;
@@ -173,17 +216,20 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
return patchlen;
}
-static void generate_id_list(int stable, int verbatim)
+static void generate_id_list(unsigned flags)
{
struct object_id oid, n, result;
int patchlen;
struct strbuf line_buf = STRBUF_INIT;
oidclr(&oid, the_repository->hash_algo);
+ flags |= GOPID_FIND_HEADER;
while (!feof(stdin)) {
- patchlen = get_one_patchid(&n, &result, &line_buf, stable, verbatim);
- flush_current_id(patchlen, &oid, &result);
+ patchlen = get_one_patchid(&n, &result, &line_buf, flags);
+ if (patchlen)
+ flush_current_id(&oid, &result);
oidcpy(&oid, &n);
+ flags &= ~GOPID_FIND_HEADER;
}
strbuf_release(&line_buf);
}
@@ -219,6 +265,7 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix)
/* if nothing is set, default to unstable */
struct patch_id_opts config = {0, 0};
int opts = 0;
+ unsigned flags = 0;
struct option builtin_patch_id_options[] = {
OPT_CMDMODE(0, "unstable", &opts,
N_("use the unstable patch-id algorithm"), 1),
@@ -250,7 +297,11 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix)
if (!the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
- generate_id_list(opts ? opts > 1 : config.stable,
- opts ? opts == 3 : config.verbatim);
+ if (opts ? opts > 1 : config.stable)
+ flags |= GOPID_STABLE;
+ if (opts ? opts == 3 : config.verbatim)
+ flags |= GOPID_VERBATIM;
+ generate_id_list(flags);
+
return 0;
}
diff --git a/builtin/stash.c b/builtin/stash.c
index 46b981c4dd..80ccfc7a08 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1671,7 +1671,28 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
}
}
- if (keep_index == 1 && !is_null_oid(&info.i_tree)) {
+ /*
+ * When keeping staged entries, we need to reset the working
+ * directory to match the state of our index. This can be
+ * skipped when the index is the empty tree, because there is
+ * nothing to reset in that case:
+ *
+ * - When the index has any file, regardless of whether
+ * staged or not, the tree cannot be empty by definition
+ * and thus we enter the condition.
+ *
+ * - When the index has no files, the only thing we need to
+ * care about is untracked files when `--include-untracked`
+ * is given. But as we already execute git-clean(1) further
+ * up to delete such untracked files we don't have to do
+ * anything here, either.
+ *
+ * We thus skip calling git-checkout(1) in this case, also
+ * because running it on an empty tree will cause it to fail
+ * due to the pathspec not matching anything.
+ */
+ if (keep_index == 1 && !is_null_oid(&info.i_tree) &&
+ !is_empty_tree_oid(&info.i_tree, the_repository->hash_algo)) {
struct child_process cp = CHILD_PROCESS_INIT;
cp.git_cmd = 1;