aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/apply.c104
-rw-r--r--builtin/checkout.c18
-rw-r--r--builtin/clone.c6
-rw-r--r--builtin/commit-tree.c70
-rw-r--r--builtin/commit.c27
-rw-r--r--builtin/config.c6
-rw-r--r--builtin/fast-export.c2
-rw-r--r--builtin/fetch.c8
-rw-r--r--builtin/fmt-merge-msg.c159
-rw-r--r--builtin/for-each-ref.c3
-rw-r--r--builtin/grep.c15
-rw-r--r--builtin/index-pack.c2
-rw-r--r--builtin/init-db.c2
-rw-r--r--builtin/log.c100
-rw-r--r--builtin/ls-files.c7
-rw-r--r--builtin/ls-remote.c11
-rw-r--r--builtin/ls-tree.c6
-rw-r--r--builtin/mailinfo.c3
-rw-r--r--builtin/merge-file.c6
-rw-r--r--builtin/merge.c83
-rw-r--r--builtin/notes.c530
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/reflog.c98
-rw-r--r--builtin/reset.c3
-rw-r--r--builtin/rev-list.c7
-rw-r--r--builtin/revert.c319
-rw-r--r--builtin/tag.c4
27 files changed, 957 insertions, 644 deletions
diff --git a/builtin/apply.c b/builtin/apply.c
index 7ca90472c1..8fc5ec31de 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1854,6 +1854,8 @@ static int match_fragment(struct image *img,
{
int i;
char *fixed_buf, *buf, *orig, *target;
+ struct strbuf fixed;
+ size_t fixed_len;
int preimage_limit;
if (preimage->nr + try_lno <= img->nr) {
@@ -1864,13 +1866,13 @@ static int match_fragment(struct image *img,
if (match_end && (preimage->nr + try_lno != img->nr))
return 0;
} else if (ws_error_action == correct_ws_error &&
- (ws_rule & WS_BLANK_AT_EOF) && match_end) {
+ (ws_rule & WS_BLANK_AT_EOF)) {
/*
- * This hunk that matches at the end extends beyond
- * the end of img, and we are removing blank lines
- * at the end of the file. This many lines from the
- * beginning of the preimage must match with img, and
- * the remainder of the preimage must be blank.
+ * This hunk extends beyond the end of img, and we are
+ * removing blank lines at the end of the file. This
+ * many lines from the beginning of the preimage must
+ * match with img, and the remainder of the preimage
+ * must be blank.
*/
preimage_limit = img->nr - try_lno;
} else {
@@ -1977,12 +1979,12 @@ static int match_fragment(struct image *img,
* use the whitespace from the preimage.
*/
extra_chars = preimage_end - preimage_eof;
- fixed_buf = xmalloc(imgoff + extra_chars);
- memcpy(fixed_buf, img->buf + try, imgoff);
- memcpy(fixed_buf + imgoff, preimage_eof, extra_chars);
- imgoff += extra_chars;
+ strbuf_init(&fixed, imgoff + extra_chars);
+ strbuf_add(&fixed, img->buf + try, imgoff);
+ strbuf_add(&fixed, preimage_eof, extra_chars);
+ fixed_buf = strbuf_detach(&fixed, &fixed_len);
update_pre_post_images(preimage, postimage,
- fixed_buf, imgoff, postlen);
+ fixed_buf, fixed_len, postlen);
return 1;
}
@@ -1999,27 +2001,22 @@ static int match_fragment(struct image *img,
* but in this loop we will only handle the part of the
* preimage that falls within the file.
*/
- fixed_buf = xmalloc(preimage->len + 1);
- buf = fixed_buf;
+ strbuf_init(&fixed, preimage->len + 1);
orig = preimage->buf;
target = img->buf + try;
for (i = 0; i < preimage_limit; i++) {
- size_t fixlen; /* length after fixing the preimage */
size_t oldlen = preimage->line[i].len;
size_t tgtlen = img->line[try_lno + i].len;
- size_t tgtfixlen; /* length after fixing the target line */
- char tgtfixbuf[1024], *tgtfix;
+ size_t fixstart = fixed.len;
+ struct strbuf tgtfix;
int match;
/* Try fixing the line in the preimage */
- fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
+ ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
/* Try fixing the line in the target */
- if (sizeof(tgtfixbuf) > tgtlen)
- tgtfix = tgtfixbuf;
- else
- tgtfix = xmalloc(tgtlen);
- tgtfixlen = ws_fix_copy(tgtfix, target, tgtlen, ws_rule, NULL);
+ strbuf_init(&tgtfix, tgtlen);
+ ws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);
/*
* If they match, either the preimage was based on
@@ -2031,15 +2028,15 @@ static int match_fragment(struct image *img,
* so we might as well take the fix together with their
* real change.
*/
- match = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen));
+ match = (tgtfix.len == fixed.len - fixstart &&
+ !memcmp(tgtfix.buf, fixed.buf + fixstart,
+ fixed.len - fixstart));
- if (tgtfix != tgtfixbuf)
- free(tgtfix);
+ strbuf_release(&tgtfix);
if (!match)
goto unmatch_exit;
orig += oldlen;
- buf += fixlen;
target += tgtlen;
}
@@ -2051,19 +2048,18 @@ static int match_fragment(struct image *img,
* false).
*/
for ( ; i < preimage->nr; i++) {
- size_t fixlen; /* length after fixing the preimage */
+ size_t fixstart = fixed.len; /* start of the fixed preimage */
size_t oldlen = preimage->line[i].len;
int j;
/* Try fixing the line in the preimage */
- fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
+ ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
- for (j = 0; j < fixlen; j++)
- if (!isspace(buf[j]))
+ for (j = fixstart; j < fixed.len; j++)
+ if (!isspace(fixed.buf[j]))
goto unmatch_exit;
orig += oldlen;
- buf += fixlen;
}
/*
@@ -2071,12 +2067,13 @@ static int match_fragment(struct image *img,
* has whitespace breakages unfixed, and fixing them makes the
* hunk match. Update the context lines in the postimage.
*/
+ fixed_buf = strbuf_detach(&fixed, &fixed_len);
update_pre_post_images(preimage, postimage,
- fixed_buf, buf - fixed_buf, 0);
+ fixed_buf, fixed_len, 0);
return 1;
unmatch_exit:
- free(fixed_buf);
+ strbuf_release(&fixed);
return 0;
}
@@ -2244,7 +2241,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
int match_beginning, match_end;
const char *patch = frag->patch;
int size = frag->size;
- char *old, *new, *oldlines, *newlines;
+ char *old, *oldlines;
+ struct strbuf newlines;
int new_blank_lines_at_end = 0;
unsigned long leading, trailing;
int pos, applied_pos;
@@ -2254,16 +2252,16 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
memset(&preimage, 0, sizeof(preimage));
memset(&postimage, 0, sizeof(postimage));
oldlines = xmalloc(size);
- newlines = xmalloc(size);
+ strbuf_init(&newlines, size);
old = oldlines;
- new = newlines;
while (size > 0) {
char first;
int len = linelen(patch, size);
- int plen, added;
+ int plen;
int added_blank_line = 0;
int is_blank_context = 0;
+ size_t start;
if (!len)
break;
@@ -2293,7 +2291,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
/* ... followed by '\No newline'; nothing */
break;
*old++ = '\n';
- *new++ = '\n';
+ strbuf_addch(&newlines, '\n');
add_line_info(&preimage, "\n", 1, LINE_COMMON);
add_line_info(&postimage, "\n", 1, LINE_COMMON);
is_blank_context = 1;
@@ -2315,18 +2313,17 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
if (first == '+' && no_add)
break;
+ start = newlines.len;
if (first != '+' ||
!whitespace_error ||
ws_error_action != correct_ws_error) {
- memcpy(new, patch + 1, plen);
- added = plen;
+ strbuf_add(&newlines, patch + 1, plen);
}
else {
- added = ws_fix_copy(new, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
+ ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
}
- add_line_info(&postimage, new, added,
+ add_line_info(&postimage, newlines.buf + start, newlines.len - start,
(first == '+' ? 0 : LINE_COMMON));
- new += added;
if (first == '+' &&
(ws_rule & WS_BLANK_AT_EOF) &&
ws_blank_line(patch + 1, plen, ws_rule))
@@ -2351,9 +2348,9 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
}
if (inaccurate_eof &&
old > oldlines && old[-1] == '\n' &&
- new > newlines && new[-1] == '\n') {
+ newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
old--;
- new--;
+ strbuf_setlen(&newlines, newlines.len - 1);
}
leading = frag->leading;
@@ -2385,8 +2382,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
pos = frag->newpos ? (frag->newpos - 1) : 0;
preimage.buf = oldlines;
preimage.len = old - oldlines;
- postimage.buf = newlines;
- postimage.len = new - newlines;
+ postimage.buf = newlines.buf;
+ postimage.len = newlines.len;
preimage.line = preimage.line_allocated;
postimage.line = postimage.line_allocated;
@@ -2462,7 +2459,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
}
free(oldlines);
- free(newlines);
+ strbuf_release(&newlines);
free(preimage.line_allocated);
free(postimage.line_allocated);
@@ -2824,11 +2821,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
if (stat_ret < 0) {
struct checkout costate;
/* checkout */
+ memset(&costate, 0, sizeof(costate));
costate.base_dir = "";
- costate.base_dir_len = 0;
- costate.force = 0;
- costate.quiet = 0;
- costate.not_new = 0;
costate.refresh_cache = 1;
if (checkout_entry(*ce, &costate, NULL) ||
lstat(old_name, st))
@@ -3144,11 +3138,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
die("unable to remove %s from index", patch->old_name);
}
if (!cached) {
- if (S_ISGITLINK(patch->old_mode)) {
- if (rmdir(patch->old_name))
- warning("unable to remove submodule %s",
- patch->old_name);
- } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
+ if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
remove_path(patch->old_name);
}
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index acefaaf41a..c3825219c1 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -33,6 +33,7 @@ struct checkout_opts {
int writeout_error;
const char *new_branch;
+ const char *new_orphan_branch;
int new_branch_log;
enum branch_track track;
};
@@ -149,7 +150,7 @@ static int checkout_merged(int pos, struct checkout *state)
read_mmblob(&ours, active_cache[pos+1]->sha1);
read_mmblob(&theirs, active_cache[pos+2]->sha1);
- status = ll_merge(&result_buf, path, &ancestor,
+ status = ll_merge(&result_buf, path, &ancestor, "base",
&ours, "ours", &theirs, "theirs", 0);
free(ancestor.ptr);
free(ours.ptr);
@@ -439,6 +440,7 @@ static int merge_working_tree(struct checkout_opts *opts,
ret = reset_tree(new->commit->tree, opts, 1);
if (ret)
return ret;
+ o.ancestor = old->name;
o.branch1 = new->name;
o.branch2 = "local";
merge_trees(&o, new->commit->tree, work,
@@ -491,8 +493,9 @@ static void update_refs_for_switch(struct checkout_opts *opts,
struct strbuf msg = STRBUF_INIT;
const char *old_desc;
if (opts->new_branch) {
- create_branch(old->name, opts->new_branch, new->name, 0,
- opts->new_branch_log, opts->track);
+ if (!opts->new_orphan_branch)
+ create_branch(old->name, opts->new_branch, new->name, 0,
+ opts->new_branch_log, opts->track);
new->name = opts->new_branch;
setup_branch_path(new);
}
@@ -632,6 +635,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
OPT_SET_INT('t', "track", &opts.track, "track",
BRANCH_TRACK_EXPLICIT),
+ OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
OPT_SET_INT('2', "ours", &opts.writeout_stage, "stage",
2),
OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
@@ -677,6 +681,14 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.new_branch = argv0 + 1;
}
+ if (opts.new_orphan_branch) {
+ if (opts.new_branch)
+ die("--orphan and -b are mutually exclusive");
+ if (opts.track > 0 || opts.new_branch_log)
+ die("--orphan cannot be used with -t or -l");
+ opts.new_branch = opts.new_orphan_branch;
+ }
+
if (conflict_style) {
opts.merge = 1; /* implied */
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
diff --git a/builtin/clone.c b/builtin/clone.c
index 05f8fb4771..0bedde41f0 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -302,6 +302,8 @@ static const struct ref *clone_local(const char *src_repo,
transport = transport_get(remote, src_repo);
ret = transport_get_remote_refs(transport);
transport_disconnect(transport);
+ if (0 <= option_verbosity)
+ printf("done.\n");
return ret;
}
@@ -461,7 +463,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die("could not create leading directories of '%s'", git_dir);
set_git_dir(make_absolute_path(git_dir));
- init_db(option_template, (option_verbosity < 0) ? INIT_DB_QUIET : 0);
+ if (0 <= option_verbosity)
+ printf("Cloning into %s...\n", get_git_dir());
+ init_db(option_template, INIT_DB_QUIET);
/*
* At this point, the config exists, so we do not need the
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 90dac349a3..87f0591c2f 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -9,19 +9,6 @@
#include "builtin.h"
#include "utf8.h"
-/*
- * FIXME! Share the code with "write-tree.c"
- */
-static void check_valid(unsigned char *sha1, enum object_type expect)
-{
- enum object_type type = sha1_object_info(sha1, NULL);
- if (type < 0)
- die("%s is not a valid object", sha1_to_hex(sha1));
- if (type != expect)
- die("%s is not a valid '%s' object", sha1_to_hex(sha1),
- typename(expect));
-}
-
static const char commit_tree_usage[] = "git commit-tree <sha1> [-p <sha1>]* < changelog";
static void new_parent(struct commit *parent, struct commit_list **parents_p)
@@ -38,61 +25,6 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
commit_list_insert(parent, parents_p);
}
-static const char commit_utf8_warn[] =
-"Warning: commit message does not conform to UTF-8.\n"
-"You may want to amend it after fixing the message, or set the config\n"
-"variable i18n.commitencoding to the encoding your project uses.\n";
-
-int commit_tree(const char *msg, unsigned char *tree,
- struct commit_list *parents, unsigned char *ret,
- const char *author)
-{
- int result;
- int encoding_is_utf8;
- struct strbuf buffer;
-
- check_valid(tree, OBJ_TREE);
-
- /* Not having i18n.commitencoding is the same as having utf-8 */
- encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
-
- strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
- strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree));
-
- /*
- * NOTE! This ordering means that the same exact tree merged with a
- * different order of parents will be a _different_ changeset even
- * if everything else stays the same.
- */
- while (parents) {
- struct commit_list *next = parents->next;
- strbuf_addf(&buffer, "parent %s\n",
- sha1_to_hex(parents->item->object.sha1));
- free(parents);
- parents = next;
- }
-
- /* Person/date information */
- if (!author)
- author = git_author_info(IDENT_ERROR_ON_NO_NAME);
- strbuf_addf(&buffer, "author %s\n", author);
- strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
- if (!encoding_is_utf8)
- strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
- strbuf_addch(&buffer, '\n');
-
- /* And add the comment */
- strbuf_addstr(&buffer, msg);
-
- /* And check the encoding */
- if (encoding_is_utf8 && !is_utf8(buffer.buf))
- fprintf(stderr, commit_utf8_warn);
-
- result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
- strbuf_release(&buffer);
- return result;
-}
-
int cmd_commit_tree(int argc, const char **argv, const char *prefix)
{
int i;
@@ -117,7 +49,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
if (get_sha1(b, sha1))
die("Not a valid object name %s", b);
- check_valid(sha1, OBJ_COMMIT);
+ assert_sha1_type(sha1, OBJ_COMMIT);
new_parent(lookup_commit(sha1), &parents);
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 8dd104ee0b..017b8a5536 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -66,7 +66,7 @@ static char *edit_message, *use_message;
static char *author_name, *author_email, *author_date;
static int all, edit_flag, also, interactive, only, amend, signoff;
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
-static int no_post_rewrite;
+static int no_post_rewrite, allow_empty_message;
static char *untracked_files_arg, *force_date;
/*
* The default commit message cleanup mode will remove the lines
@@ -140,9 +140,15 @@ static struct option builtin_commit_options[] = {
OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
- OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
/* end commit contents options */
+ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
+ "ok to record an empty change",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
+ "ok to record a change with an empty message",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+
OPT_END()
};
@@ -307,7 +313,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
* (B) on failure, rollback the real index.
*/
if (all || (also && pathspec && *pathspec)) {
- int fd = hold_locked_index(&index_lock, 1);
+ fd = hold_locked_index(&index_lock, 1);
add_files_to_cache(also ? prefix : NULL, pathspec, 0);
refresh_cache_or_die(refresh_flags);
if (write_cache(fd, active_cache, active_nr) ||
@@ -322,8 +328,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
*
* (1) return the name of the real index file.
*
- * The caller should run hooks on the real index, and run
- * hooks on the real index, and create commit from the_index.
+ * The caller should run hooks on the real index,
+ * and create commit from the_index.
* We still need to refresh the index here.
*/
if (!pathspec || !*pathspec) {
@@ -1017,6 +1023,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
int cmd_status(int argc, const char **argv, const char *prefix)
{
struct wt_status s;
+ int fd;
unsigned char sha1[20];
static struct option builtin_status_options[] = {
OPT__VERBOSE(&verbose),
@@ -1050,6 +1057,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)
read_cache_preload(s.pathspec);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
+
+ fd = hold_locked_index(&index_lock, 0);
+ if (0 <= fd) {
+ if (!write_cache(fd, active_cache, active_nr))
+ commit_locked_index(&index_lock);
+ rollback_lock_file(&index_lock);
+ }
+
s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
s.in_merge = in_merge;
wt_status_collect(&s);
@@ -1293,7 +1308,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (cleanup_mode != CLEANUP_NONE)
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
- if (message_is_empty(&sb)) {
+ if (message_is_empty(&sb) && !allow_empty_message) {
rollback_index_files();
fprintf(stderr, "Aborting commit due to empty commit message.\n");
exit(1);
diff --git a/builtin/config.c b/builtin/config.c
index 4bc46b15fd..f3d1660d02 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -197,7 +197,11 @@ static int get_value(const char *key_, const char *regex_)
git_config_from_file(show_config, system_wide, NULL);
if (do_all && global)
git_config_from_file(show_config, global, NULL);
- git_config_from_file(show_config, local, NULL);
+ if (do_all)
+ git_config_from_file(show_config, local, NULL);
+ git_config_from_parameters(show_config, NULL);
+ if (!do_all && !seen)
+ git_config_from_file(show_config, local, NULL);
if (!do_all && !seen && global)
git_config_from_file(show_config, global, NULL);
if (!do_all && !seen && system_wide)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index b0a4029c94..c6dd71a7bc 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -503,7 +503,7 @@ static void export_marks(char *file)
f = fopen(file, "w");
if (!f)
- error("Unable to open marks file %s for writing.", file);
+ die_errno("Unable to open marks file %s for writing.", file);
for (i = 0; i < idnums.size; i++) {
if (deco->base && deco->base->type == 1) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 957be9f926..8470850415 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -14,10 +14,10 @@
#include "transport.h"
static const char * const builtin_fetch_usage[] = {
- "git fetch [options] [<repository> <refspec>...]",
- "git fetch [options] <group>",
- "git fetch --multiple [options] [<repository> | <group>]...",
- "git fetch --all [options]",
+ "git fetch [<options>] [<repository> [<refspec>...]]",
+ "git fetch [<options>] <group>",
+ "git fetch --multiple [<options>] [<repository> | <group>]...",
+ "git fetch --all [<options>]",
NULL
};
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 9d524000b5..379a03131f 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -4,6 +4,7 @@
#include "diff.h"
#include "revision.h"
#include "tag.h"
+#include "string-list.h"
static const char * const fmt_merge_msg_usage[] = {
"git fmt-merge-msg [--log|--no-log] [--file <file>]",
@@ -24,58 +25,21 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
return 0;
}
-struct list {
- char **list;
- void **payload;
- unsigned nr, alloc;
+struct src_data {
+ struct string_list branch, tag, r_branch, generic;
+ int head_status;
};
-static void append_to_list(struct list *list, char *value, void *payload)
-{
- if (list->nr == list->alloc) {
- list->alloc += 32;
- list->list = xrealloc(list->list, sizeof(char *) * list->alloc);
- list->payload = xrealloc(list->payload,
- sizeof(char *) * list->alloc);
- }
- list->payload[list->nr] = payload;
- list->list[list->nr++] = value;
-}
-
-static int find_in_list(struct list *list, char *value)
-{
- int i;
-
- for (i = 0; i < list->nr; i++)
- if (!strcmp(list->list[i], value))
- return i;
-
- return -1;
-}
-
-static void free_list(struct list *list)
+void init_src_data(struct src_data *data)
{
- int i;
-
- if (list->alloc == 0)
- return;
-
- for (i = 0; i < list->nr; i++) {
- free(list->list[i]);
- free(list->payload[i]);
- }
- free(list->list);
- free(list->payload);
- list->nr = list->alloc = 0;
+ data->branch.strdup_strings = 1;
+ data->tag.strdup_strings = 1;
+ data->r_branch.strdup_strings = 1;
+ data->generic.strdup_strings = 1;
}
-struct src_data {
- struct list branch, tag, r_branch, generic;
- int head_status;
-};
-
-static struct list srcs = { NULL, NULL, 0, 0};
-static struct list origins = { NULL, NULL, 0, 0};
+static struct string_list srcs = { NULL, 0, 0, 1 };
+static struct string_list origins = { NULL, 0, 0, 1 };
static int handle_line(char *line)
{
@@ -83,6 +47,7 @@ static int handle_line(char *line)
unsigned char *sha1;
char *src, *origin;
struct src_data *src_data;
+ struct string_list_item *item;
int pulling_head = 0;
if (len < 43 || line[40] != '\t')
@@ -115,64 +80,62 @@ static int handle_line(char *line)
pulling_head = 1;
}
- i = find_in_list(&srcs, src);
- if (i < 0) {
- i = srcs.nr;
- append_to_list(&srcs, xstrdup(src),
- xcalloc(1, sizeof(struct src_data)));
+ item = unsorted_string_list_lookup(&srcs, src);
+ if (!item) {
+ item = string_list_append(src, &srcs);
+ item->util = xcalloc(1, sizeof(struct src_data));
+ init_src_data(item->util);
}
- src_data = srcs.payload[i];
+ src_data = item->util;
if (pulling_head) {
- origin = xstrdup(src);
+ origin = src;
src_data->head_status |= 1;
} else if (!prefixcmp(line, "branch ")) {
- origin = xstrdup(line + 7);
- append_to_list(&src_data->branch, origin, NULL);
+ origin = line + 7;
+ string_list_append(origin, &src_data->branch);
src_data->head_status |= 2;
} else if (!prefixcmp(line, "tag ")) {
origin = line;
- append_to_list(&src_data->tag, xstrdup(origin + 4), NULL);
+ string_list_append(origin + 4, &src_data->tag);
src_data->head_status |= 2;
} else if (!prefixcmp(line, "remote branch ")) {
- origin = xstrdup(line + 14);
- append_to_list(&src_data->r_branch, origin, NULL);
+ origin = line + 14;
+ string_list_append(origin, &src_data->r_branch);
src_data->head_status |= 2;
} else {
- origin = xstrdup(src);
- append_to_list(&src_data->generic, xstrdup(line), NULL);
+ origin = src;
+ string_list_append(line, &src_data->generic);
src_data->head_status |= 2;
}
if (!strcmp(".", src) || !strcmp(src, origin)) {
int len = strlen(origin);
- if (origin[0] == '\'' && origin[len - 1] == '\'') {
+ if (origin[0] == '\'' && origin[len - 1] == '\'')
origin = xmemdupz(origin + 1, len - 2);
- } else {
- origin = xstrdup(origin);
- }
} else {
char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
sprintf(new_origin, "%s of %s", origin, src);
origin = new_origin;
}
- append_to_list(&origins, origin, sha1);
+ string_list_append(origin, &origins)->util = sha1;
return 0;
}
static void print_joined(const char *singular, const char *plural,
- struct list *list, struct strbuf *out)
+ struct string_list *list, struct strbuf *out)
{
if (list->nr == 0)
return;
if (list->nr == 1) {
- strbuf_addf(out, "%s%s", singular, list->list[0]);
+ strbuf_addf(out, "%s%s", singular, list->items[0].string);
} else {
int i;
strbuf_addstr(out, plural);
for (i = 0; i < list->nr - 1; i++)
- strbuf_addf(out, "%s%s", i > 0 ? ", " : "", list->list[i]);
- strbuf_addf(out, " and %s", list->list[list->nr - 1]);
+ strbuf_addf(out, "%s%s", i > 0 ? ", " : "",
+ list->items[i].string);
+ strbuf_addf(out, " and %s", list->items[list->nr - 1].string);
}
}
@@ -183,8 +146,9 @@ static void shortlog(const char *name, unsigned char *sha1,
int i, count = 0;
struct commit *commit;
struct object *branch;
- struct list subjects = { NULL, NULL, 0, 0 };
+ struct string_list subjects = { NULL, 0, 0, 1 };
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
+ struct strbuf sb = STRBUF_INIT;
branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
if (!branch || branch->type != OBJ_COMMIT)
@@ -198,7 +162,7 @@ static void shortlog(const char *name, unsigned char *sha1,
if (prepare_revision_walk(rev))
die("revision walk setup failed");
while ((commit = get_revision(rev)) != NULL) {
- char *oneline, *bol, *eol;
+ struct pretty_print_context ctx = {0};
/* ignore merges */
if (commit->parents && commit->parents->next)
@@ -208,30 +172,14 @@ static void shortlog(const char *name, unsigned char *sha1,
if (subjects.nr > limit)
continue;
- bol = strstr(commit->buffer, "\n\n");
- if (bol) {
- unsigned char c;
- do {
- c = *++bol;
- } while (isspace(c));
- if (!c)
- bol = NULL;
- }
-
- if (!bol) {
- append_to_list(&subjects, xstrdup(sha1_to_hex(
- commit->object.sha1)),
- NULL);
- continue;
- }
+ format_commit_message(commit, "%s", &sb, &ctx);
+ strbuf_ltrim(&sb);
- eol = strchr(bol, '\n');
- if (eol) {
- oneline = xmemdupz(bol, eol - bol);
- } else {
- oneline = xstrdup(bol);
- }
- append_to_list(&subjects, oneline, NULL);
+ if (!sb.len)
+ string_list_append(sha1_to_hex(commit->object.sha1),
+ &subjects);
+ else
+ string_list_append(strbuf_detach(&sb, NULL), &subjects);
}
if (count > limit)
@@ -243,7 +191,7 @@ static void shortlog(const char *name, unsigned char *sha1,
if (i >= limit)
strbuf_addf(out, " ...\n");
else
- strbuf_addf(out, " %s\n", subjects.list[i]);
+ strbuf_addf(out, " %s\n", subjects.items[i].string);
clear_commit_marks((struct commit *)branch, flags);
clear_commit_marks(head, flags);
@@ -251,7 +199,7 @@ static void shortlog(const char *name, unsigned char *sha1,
rev->commits = NULL;
rev->pending.nr = 0;
- free_list(&subjects);
+ string_list_clear(&subjects, 0);
}
int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
@@ -281,16 +229,19 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
die ("Error in line %d: %.*s", i, len, p);
}
+ if (!srcs.nr)
+ return 0;
+
strbuf_addstr(out, "Merge ");
for (i = 0; i < srcs.nr; i++) {
- struct src_data *src_data = srcs.payload[i];
+ struct src_data *src_data = srcs.items[i].util;
const char *subsep = "";
strbuf_addstr(out, sep);
sep = "; ";
if (src_data->head_status == 1) {
- strbuf_addstr(out, srcs.list[i]);
+ strbuf_addstr(out, srcs.items[i].string);
continue;
}
if (src_data->head_status == 3) {
@@ -319,8 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
print_joined("commit ", "commits ", &src_data->generic,
out);
}
- if (strcmp(".", srcs.list[i]))
- strbuf_addf(out, " of %s", srcs.list[i]);
+ if (strcmp(".", srcs.items[i].string))
+ strbuf_addf(out, " of %s", srcs.items[i].string);
}
if (!strcmp("master", current_branch))
@@ -339,7 +290,7 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
rev.limited = 1;
for (i = 0; i < origins.nr; i++)
- shortlog(origins.list[i], origins.payload[i],
+ shortlog(origins.items[i].string, origins.items[i].util,
head, &rev, limit, out);
}
return 0;
@@ -350,7 +301,9 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
const char *inpath = NULL;
struct option options[] = {
OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"),
- OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
+ { OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL,
+ "alias for --log (deprecated)",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_FILENAME('F', "file", &inpath, "file to read from"),
OPT_END()
};
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 62be1bbfd6..3a97953177 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -227,6 +227,9 @@ static void grab_common_values(struct atom_value *val, int deref, struct object
strcpy(s, sha1_to_hex(obj->sha1));
v->s = s;
}
+ else if (!strcmp(name, "objectname:short")) {
+ v->s = find_unique_abbrev(obj->sha1, DEFAULT_ABBREV);
+ }
}
}
diff --git a/builtin/grep.c b/builtin/grep.c
index 9d30ddb28d..8e928e2170 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -96,6 +96,9 @@ static pthread_cond_t cond_write;
/* Signalled when we are finished with everything. */
static pthread_cond_t cond_result;
+static int print_hunk_marks_between_files;
+static int printed_something;
+
static void add_work(enum work_type type, char *name, void *id)
{
grep_lock();
@@ -159,7 +162,12 @@ static void work_done(struct work_item *w)
for(; todo[todo_done].done && todo_done != todo_start;
todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
w = &todo[todo_done];
- write_or_die(1, w->out.buf, w->out.len);
+ if (w->out.len) {
+ if (print_hunk_marks_between_files && printed_something)
+ write_or_die(1, "--\n", 3);
+ write_or_die(1, w->out.buf, w->out.len);
+ printed_something = 1;
+ }
free(w->name);
free(w->identifier);
}
@@ -946,8 +954,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (online_cpus() == 1 || !grep_threads_ok(&opt))
use_threads = 0;
- if (use_threads)
+ if (use_threads) {
+ if (opt.pre_context || opt.post_context)
+ print_hunk_marks_between_files = 1;
start_threads(&opt);
+ }
#else
use_threads = 0;
#endif
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index b4cf8c53e0..03d0cd2f47 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -11,7 +11,7 @@
#include "exec_cmd.h"
static const char index_pack_usage[] =
-"git index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
+"git index-pack [-v] [-o <index-file>] [{ --keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
struct object_entry
{
diff --git a/builtin/init-db.c b/builtin/init-db.c
index edc40ff574..0271285fad 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -463,7 +463,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
static char git_dir[PATH_MAX+1];
setenv(GIT_DIR_ENVIRONMENT,
- getcwd(git_dir, sizeof(git_dir)), 0);
+ getcwd(git_dir, sizeof(git_dir)), argc > 0);
}
if (init_shared_repository != -1)
diff --git a/builtin/log.c b/builtin/log.c
index a8dd8c989c..976e16f9f2 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -24,6 +24,7 @@
static const char *default_date_mode = NULL;
static int default_show_root = 1;
+static int decoration_style;
static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
@@ -31,11 +32,29 @@ static const char * const builtin_log_usage =
"git log [<options>] [<since>..<until>] [[--] <path>...]\n"
" or: git show [options] <object>...";
+static int parse_decoration_style(const char *var, const char *value)
+{
+ switch (git_config_maybe_bool(var, value)) {
+ case 1:
+ return DECORATE_SHORT_REFS;
+ case 0:
+ return 0;
+ default:
+ break;
+ }
+ if (!strcmp(value, "full"))
+ return DECORATE_FULL_REFS;
+ else if (!strcmp(value, "short"))
+ return DECORATE_SHORT_REFS;
+ return -1;
+}
+
static void cmd_log_init(int argc, const char **argv, const char *prefix,
struct rev_info *rev, struct setup_revision_opt *opt)
{
int i;
- int decoration_style = 0;
+ int decoration_given = 0;
+ struct userformat_want w;
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
@@ -58,7 +77,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
usage(builtin_log_usage);
argc = setup_revisions(argc, argv, rev, opt);
- if (!rev->show_notes_given && !rev->pretty_given)
+ memset(&w, 0, sizeof(w));
+ userformat_find_requirements(NULL, &w);
+
+ if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
rev->show_notes = 1;
if (rev->show_notes)
init_display_notes(&rev->notes_opt);
@@ -74,14 +96,15 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
const char *arg = argv[i];
if (!strcmp(arg, "--decorate")) {
decoration_style = DECORATE_SHORT_REFS;
+ decoration_given = 1;
} else if (!prefixcmp(arg, "--decorate=")) {
const char *v = skip_prefix(arg, "--decorate=");
- if (!strcmp(v, "full"))
- decoration_style = DECORATE_FULL_REFS;
- else if (!strcmp(v, "short"))
- decoration_style = DECORATE_SHORT_REFS;
- else
+ decoration_style = parse_decoration_style(arg, v);
+ if (decoration_style < 0)
die("invalid --decorate option: %s", arg);
+ decoration_given = 1;
+ } else if (!strcmp(arg, "--no-decorate")) {
+ decoration_style = 0;
} else if (!strcmp(arg, "--source")) {
rev->show_source = 1;
} else if (!strcmp(arg, "-h")) {
@@ -89,6 +112,15 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
} else
die("unrecognized argument: %s", arg);
}
+
+ /*
+ * defeat log.decorate configuration interacting with --pretty=raw
+ * from the command line.
+ */
+ if (!decoration_given && rev->pretty_given
+ && rev->commit_format == CMIT_FMT_RAW)
+ decoration_style = 0;
+
if (decoration_style) {
rev->show_decorations = 1;
load_ref_decorations(decoration_style);
@@ -254,6 +286,12 @@ static int git_log_config(const char *var, const char *value, void *cb)
return git_config_string(&fmt_patch_subject_prefix, var, value);
if (!strcmp(var, "log.date"))
return git_config_string(&default_date_mode, var, value);
+ if (!strcmp(var, "log.decorate")) {
+ decoration_style = parse_decoration_style(var, value);
+ if (decoration_style < 0)
+ decoration_style = 0; /* maybe warn? */
+ return 0;
+ }
if (!strcmp(var, "log.showroot")) {
default_show_root = git_config_bool(var, value);
return 0;
@@ -1157,8 +1195,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
return 0;
}
- if (ignore_if_in_upstream)
+ if (ignore_if_in_upstream) {
+ /* Don't say anything if head and upstream are the same. */
+ if (rev.pending.nr == 2) {
+ struct object_array_entry *o = rev.pending.objects;
+ if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
+ return 0;
+ }
get_patch_ids(&rev, &ids, prefix);
+ }
if (!use_stdout)
realstdout = xfdopen(xdup(1), "w");
@@ -1296,8 +1341,11 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
return -1;
}
-static const char cherry_usage[] =
-"git cherry [-v] [<upstream> [<head> [<limit>]]]";
+static const char * const cherry_usage[] = {
+ "git cherry [-v] [<upstream> [<head> [<limit>]]]",
+ NULL
+};
+
int cmd_cherry(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@@ -1308,26 +1356,25 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
const char *upstream;
const char *head = "HEAD";
const char *limit = NULL;
- int verbose = 0;
+ int verbose = 0, abbrev = 0;
- if (argc > 1 && !strcmp(argv[1], "-v")) {
- verbose = 1;
- argc--;
- argv++;
- }
+ struct option options[] = {
+ OPT__ABBREV(&abbrev),
+ OPT__VERBOSE(&verbose),
+ OPT_END()
+ };
- if (argc > 1 && !strcmp(argv[1], "-h"))
- usage(cherry_usage);
+ argc = parse_options(argc, argv, prefix, options, cherry_usage, 0);
switch (argc) {
- case 4:
- limit = argv[3];
- /* FALLTHROUGH */
case 3:
- head = argv[2];
+ limit = argv[2];
/* FALLTHROUGH */
case 2:
- upstream = argv[1];
+ head = argv[1];
+ /* FALLTHROUGH */
+ case 1:
+ upstream = argv[0];
break;
default:
current_branch = branch_get(NULL);
@@ -1337,7 +1384,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
fprintf(stderr, "Could not find a tracked"
" remote branch, please"
" specify <upstream> manually.\n");
- usage(cherry_usage);
+ usage_with_options(cherry_usage, options);
}
upstream = current_branch->merge[0]->dst;
@@ -1390,12 +1437,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
pretty_print_commit(CMIT_FMT_ONELINE, commit,
&buf, &ctx);
printf("%c %s %s\n", sign,
- sha1_to_hex(commit->object.sha1), buf.buf);
+ find_unique_abbrev(commit->object.sha1, abbrev),
+ buf.buf);
strbuf_release(&buf);
}
else {
printf("%c %s\n", sign,
- sha1_to_hex(commit->object.sha1));
+ find_unique_abbrev(commit->object.sha1, abbrev));
}
list = list->next;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index b065061392..c0fbcdcf4f 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -153,8 +153,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
printf("%s%06o %s %d\t",
tag,
ce->ce_mode,
- abbrev ? find_unique_abbrev(ce->sha1,abbrev)
- : sha1_to_hex(ce->sha1),
+ find_unique_abbrev(ce->sha1,abbrev),
ce_stage(ce));
}
write_name_quoted(ce->name + offset, stdout, line_terminator);
@@ -176,9 +175,7 @@ static int show_one_ru(struct string_list_item *item, void *cbdata)
if (!ui->mode[i])
continue;
printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
- abbrev
- ? find_unique_abbrev(ui->sha1[i], abbrev)
- : sha1_to_hex(ui->sha1[i]),
+ find_unique_abbrev(ui->sha1[i], abbrev),
i + 1);
write_name_quoted(path + offset, stdout, line_terminator);
}
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 70f5622d9d..8ee91eb547 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -4,7 +4,8 @@
#include "remote.h"
static const char ls_remote_usage[] =
-"git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>] <repository> <refs>...";
+"git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>]\n"
+" [<repository> [<refs>...]]";
/*
* Is there one among the list of patterns that match the tail part
@@ -73,9 +74,6 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
break;
}
- if (!dest)
- usage(ls_remote_usage);
-
if (argv[i]) {
int j;
pattern = xcalloc(sizeof(const char *), argc - i + 1);
@@ -87,6 +85,11 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
}
}
remote = remote_get(dest);
+ if (!remote) {
+ if (dest)
+ die("bad repository '%s'", dest);
+ die("No remote configured to list refs from.");
+ }
if (!remote->url_nr)
die("remote %s has no configured URL", dest);
transport = transport_get(remote, NULL);
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 4484185afc..dc86b0d9a9 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -103,13 +103,11 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
} else
strcpy(size_text, "-");
printf("%06o %s %s %7s\t", mode, type,
- abbrev ? find_unique_abbrev(sha1, abbrev)
- : sha1_to_hex(sha1),
+ find_unique_abbrev(sha1, abbrev),
size_text);
} else
printf("%06o %s %s\t", mode, type,
- abbrev ? find_unique_abbrev(sha1, abbrev)
- : sha1_to_hex(sha1));
+ find_unique_abbrev(sha1, abbrev));
}
write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
pathname, stdout, line_termination);
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index ce2ef6bede..4a9729b9b3 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -746,7 +746,8 @@ static int is_scissors_line(const struct strbuf *line)
continue;
}
if (i + 1 < len &&
- (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2))) {
+ (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2) ||
+ !memcmp(buf + i, ">%", 2) || !memcmp(buf + i, "%<", 2))) {
in_perforation = 1;
perforation += 2;
scissors += 2;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 69cc683332..610849a653 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -77,8 +77,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
argv[i]);
}
- ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
- &xmp, &result);
+ xmp.ancestor = names[1];
+ xmp.file1 = names[0];
+ xmp.file2 = names[2];
+ ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
for (i = 0; i < 3; i++)
free(mmfs[i].ptr);
diff --git a/builtin/merge.c b/builtin/merge.c
index 3aaec7bed7..37d414b3ba 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -548,13 +548,53 @@ static void write_tree_trivial(unsigned char *sha1)
die("git write-tree failed to write a tree");
}
-static int try_merge_strategy(const char *strategy, struct commit_list *common,
- const char *head_arg)
+int try_merge_command(const char *strategy, struct commit_list *common,
+ const char *head_arg, struct commit_list *remotes)
{
const char **args;
int i = 0, x = 0, ret;
struct commit_list *j;
struct strbuf buf = STRBUF_INIT;
+
+ args = xmalloc((4 + xopts_nr + commit_list_count(common) +
+ commit_list_count(remotes)) * sizeof(char *));
+ strbuf_addf(&buf, "merge-%s", strategy);
+ args[i++] = buf.buf;
+ for (x = 0; x < xopts_nr; x++) {
+ char *s = xmalloc(strlen(xopts[x])+2+1);
+ strcpy(s, "--");
+ strcpy(s+2, xopts[x]);
+ args[i++] = s;
+ }
+ for (j = common; j; j = j->next)
+ args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
+ args[i++] = "--";
+ args[i++] = head_arg;
+ for (j = remotes; j; j = j->next)
+ args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
+ args[i] = NULL;
+ ret = run_command_v_opt(args, RUN_GIT_CMD);
+ strbuf_release(&buf);
+ i = 1;
+ for (x = 0; x < xopts_nr; x++)
+ free((void *)args[i++]);
+ for (j = common; j; j = j->next)
+ free((void *)args[i++]);
+ i += 2;
+ for (j = remotes; j; j = j->next)
+ free((void *)args[i++]);
+ free(args);
+ discard_cache();
+ if (read_cache() < 0)
+ die("failed to read the cache");
+ resolve_undo_clear();
+
+ return ret;
+}
+
+static int try_merge_strategy(const char *strategy, struct commit_list *common,
+ const char *head_arg)
+{
int index_fd;
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
@@ -567,12 +607,13 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
rollback_lock_file(lock);
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
- int clean;
+ int clean, x;
struct commit *result;
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int index_fd;
struct commit_list *reversed = NULL;
struct merge_options o;
+ struct commit_list *j;
if (remoteheads->next) {
error("Not handling anything other than two heads merge.");
@@ -612,39 +653,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
rollback_lock_file(lock);
return clean ? 0 : 1;
} else {
- args = xmalloc((4 + xopts_nr + commit_list_count(common) +
- commit_list_count(remoteheads)) * sizeof(char *));
- strbuf_addf(&buf, "merge-%s", strategy);
- args[i++] = buf.buf;
- for (x = 0; x < xopts_nr; x++) {
- char *s = xmalloc(strlen(xopts[x])+2+1);
- strcpy(s, "--");
- strcpy(s+2, xopts[x]);
- args[i++] = s;
- }
- for (j = common; j; j = j->next)
- args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
- args[i++] = "--";
- args[i++] = head_arg;
- for (j = remoteheads; j; j = j->next)
- args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
- args[i] = NULL;
- ret = run_command_v_opt(args, RUN_GIT_CMD);
- strbuf_release(&buf);
- i = 1;
- for (x = 0; x < xopts_nr; x++)
- free((void *)args[i++]);
- for (j = common; j; j = j->next)
- free((void *)args[i++]);
- i += 2;
- for (j = remoteheads; j; j = j->next)
- free((void *)args[i++]);
- free(args);
- discard_cache();
- if (read_cache() < 0)
- die("failed to read the cache");
- resolve_undo_clear();
- return ret;
+ return try_merge_command(strategy, common, head_arg, remoteheads);
}
}
@@ -667,7 +676,7 @@ static int count_unmerged_entries(void)
return ret;
}
-static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
+int checkout_fast_forward(const unsigned char *head, const unsigned char *remote)
{
struct tree *trees[MAX_UNPACK_TREES];
struct unpack_trees_options opts;
diff --git a/builtin/notes.c b/builtin/notes.c
index 4543d11311..52b72fca68 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -19,13 +19,54 @@
#include "string-list.h"
static const char * const git_notes_usage[] = {
+ "git notes [--ref <notes_ref>] [list [<object>]]",
+ "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+ "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>",
+ "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+ "git notes [--ref <notes_ref>] edit [<object>]",
+ "git notes [--ref <notes_ref>] show [<object>]",
+ "git notes [--ref <notes_ref>] remove [<object>]",
+ "git notes [--ref <notes_ref>] prune",
+ NULL
+};
+
+static const char * const git_notes_list_usage[] = {
"git notes [list [<object>]]",
- "git notes add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
- "git notes copy [-f] <from-object> <to-object>",
- "git notes append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+ NULL
+};
+
+static const char * const git_notes_add_usage[] = {
+ "git notes add [<options>] [<object>]",
+ NULL
+};
+
+static const char * const git_notes_copy_usage[] = {
+ "git notes copy [<options>] <from-object> <to-object>",
+ "git notes copy --stdin [<from-object> <to-object>]...",
+ NULL
+};
+
+static const char * const git_notes_append_usage[] = {
+ "git notes append [<options>] [<object>]",
+ NULL
+};
+
+static const char * const git_notes_edit_usage[] = {
"git notes edit [<object>]",
+ NULL
+};
+
+static const char * const git_notes_show_usage[] = {
"git notes show [<object>]",
+ NULL
+};
+
+static const char * const git_notes_remove_usage[] = {
"git notes remove [<object>]",
+ NULL
+};
+
+static const char * const git_notes_prune_usage[] = {
"git notes prune",
NULL
};
@@ -272,7 +313,6 @@ int commit_notes(struct notes_tree *t, const char *msg)
return 0;
}
-
combine_notes_fn *parse_combine_notes_fn(const char *v)
{
if (!strcasecmp(v, "overwrite"))
@@ -427,22 +467,65 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd)
return ret;
}
-int cmd_notes(int argc, const char **argv, const char *prefix)
+static struct notes_tree *init_notes_check(const char *subcommand)
+{
+ struct notes_tree *t;
+ init_notes(NULL, NULL, NULL, 0);
+ t = &default_notes_tree;
+
+ if (prefixcmp(t->ref, "refs/notes/"))
+ die("Refusing to %s notes in %s (outside of refs/notes/)",
+ subcommand, t->ref);
+ return t;
+}
+
+static int list(int argc, const char **argv, const char *prefix)
{
struct notes_tree *t;
- unsigned char object[20], from_obj[20], new_note[20];
+ unsigned char object[20];
const unsigned char *note;
+ int retval = -1;
+ struct option options[] = {
+ OPT_END()
+ };
+
+ if (argc)
+ argc = parse_options(argc, argv, prefix, options,
+ git_notes_list_usage, 0);
+
+ if (1 < argc) {
+ error("too many parameters");
+ usage_with_options(git_notes_list_usage, options);
+ }
+
+ t = init_notes_check("list");
+ if (argc) {
+ if (get_sha1(argv[0], object))
+ die("Failed to resolve '%s' as a valid ref.", argv[0]);
+ note = get_note(t, object);
+ if (note) {
+ puts(sha1_to_hex(note));
+ retval = 0;
+ } else
+ retval = error("No note found for object %s.",
+ sha1_to_hex(object));
+ } else
+ retval = for_each_note(t, 0, list_each_note, NULL);
+
+ free_notes(t);
+ return retval;
+}
+
+static int add(int argc, const char **argv, const char *prefix)
+{
+ int retval = 0, force = 0;
const char *object_ref;
+ struct notes_tree *t;
+ unsigned char object[20], new_note[20];
char logmsg[100];
-
- int list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0,
- remove = 0, prune = 0, force = 0, from_stdin = 0;
- int given_object = 0, i = 1, retval = 0;
+ const unsigned char *note;
struct msg_arg msg = { 0, 0, STRBUF_INIT };
- const char *rewrite_cmd = NULL;
- const char *override_notes_ref = NULL;
struct option options[] = {
- OPT_GROUP("Notes contents options"),
{ OPTION_CALLBACK, 'm', "message", &msg, "MSG",
"note contents as a string", PARSE_OPT_NONEG,
parse_msg_arg},
@@ -455,196 +538,325 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
"reuse specified note object", PARSE_OPT_NONEG,
parse_reuse_arg},
- OPT_GROUP("Other options"),
OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
- OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
- OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
- "use notes from <notes_ref>"),
- OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
- "load rewriting config for <command> (implies --stdin)"),
OPT_END()
};
- git_config(git_default_config, NULL);
+ argc = parse_options(argc, argv, prefix, options, git_notes_add_usage,
+ 0);
- argc = parse_options(argc, argv, prefix, options, git_notes_usage, 0);
-
- if (override_notes_ref) {
- struct strbuf sb = STRBUF_INIT;
- if (!prefixcmp(override_notes_ref, "refs/notes/"))
- /* we're happy */;
- else if (!prefixcmp(override_notes_ref, "notes/"))
- strbuf_addstr(&sb, "refs/");
- else
- strbuf_addstr(&sb, "refs/notes/");
- strbuf_addstr(&sb, override_notes_ref);
- setenv("GIT_NOTES_REF", sb.buf, 1);
- strbuf_release(&sb);
+ if (1 < argc) {
+ error("too many parameters");
+ usage_with_options(git_notes_add_usage, options);
}
- if (argc && !strcmp(argv[0], "list"))
- list = 1;
- else if (argc && !strcmp(argv[0], "add"))
- add = 1;
- else if (argc && !strcmp(argv[0], "copy"))
- copy = 1;
- else if (argc && !strcmp(argv[0], "append"))
- append = 1;
- else if (argc && !strcmp(argv[0], "edit"))
- edit = 1;
- else if (argc && !strcmp(argv[0], "show"))
- show = 1;
- else if (argc && !strcmp(argv[0], "remove"))
- remove = 1;
- else if (argc && !strcmp(argv[0], "prune"))
- prune = 1;
- else if (!argc) {
- list = 1; /* Default to 'list' if no other subcommand given */
- i = 0;
- }
+ object_ref = argc ? argv[0] : "HEAD";
- if (list + add + copy + append + edit + show + remove + prune != 1)
- usage_with_options(git_notes_usage, options);
+ if (get_sha1(object_ref, object))
+ die("Failed to resolve '%s' as a valid ref.", object_ref);
- if (msg.given && !(add || append || edit)) {
- error("cannot use -m/-F/-c/-C options with %s subcommand.",
- argv[0]);
- usage_with_options(git_notes_usage, options);
- }
+ t = init_notes_check("add");
+ note = get_note(t, object);
- if (msg.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 (note) {
+ if (!force) {
+ retval = error("Cannot add notes. Found existing notes "
+ "for object %s. Use '-f' to overwrite "
+ "existing notes", sha1_to_hex(object));
+ goto out;
+ }
+ fprintf(stderr, "Overwriting existing notes for object %s\n",
+ sha1_to_hex(object));
}
- if (force && !(add || copy)) {
- error("cannot use -f option with %s subcommand.", argv[0]);
- usage_with_options(git_notes_usage, options);
- }
+ create_note(object, &msg, 0, note, new_note);
- if (!copy && rewrite_cmd) {
- error("cannot use --for-rewrite with %s subcommand.", argv[0]);
- usage_with_options(git_notes_usage, options);
- }
- if (!copy && from_stdin) {
- error("cannot use --stdin with %s subcommand.", argv[0]);
- usage_with_options(git_notes_usage, options);
- }
+ if (is_null_sha1(new_note))
+ remove_note(t, object);
+ else
+ add_note(t, object, new_note, combine_notes_overwrite);
- if (copy) {
- const char *from_ref;
- if (from_stdin || rewrite_cmd) {
- if (argc > 1) {
- error("too many parameters");
- usage_with_options(git_notes_usage, options);
- } else {
- return notes_copy_from_stdin(force, rewrite_cmd);
- }
- }
- if (argc < 3) {
- error("too few parameters");
- usage_with_options(git_notes_usage, options);
+ snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
+ is_null_sha1(new_note) ? "removed" : "added", "add");
+ commit_notes(t, logmsg);
+out:
+ free_notes(t);
+ strbuf_release(&(msg.buf));
+ return retval;
+}
+
+static int copy(int argc, const char **argv, const char *prefix)
+{
+ int retval = 0, force = 0, from_stdin = 0;
+ const unsigned char *from_note, *note;
+ const char *object_ref;
+ unsigned char object[20], from_obj[20];
+ struct notes_tree *t;
+ const char *rewrite_cmd = NULL;
+ struct option options[] = {
+ OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
+ OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
+ OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
+ "load rewriting config for <command> (implies "
+ "--stdin)"),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage,
+ 0);
+
+ if (from_stdin || rewrite_cmd) {
+ if (argc) {
+ error("too many parameters");
+ usage_with_options(git_notes_copy_usage, options);
+ } else {
+ return notes_copy_from_stdin(force, rewrite_cmd);
}
- from_ref = argv[i++];
- if (get_sha1(from_ref, from_obj))
- die("Failed to resolve '%s' as a valid ref.", from_ref);
}
- given_object = argc > i;
- object_ref = given_object ? argv[i++] : "HEAD";
-
- if (argc > i || (prune && given_object)) {
+ if (2 < argc) {
error("too many parameters");
- usage_with_options(git_notes_usage, options);
+ usage_with_options(git_notes_copy_usage, options);
}
- if (get_sha1(object_ref, object))
- die("Failed to resolve '%s' as a valid ref.", object_ref);
+ if (get_sha1(argv[0], from_obj))
+ die("Failed to resolve '%s' as a valid ref.", argv[0]);
- init_notes(NULL, NULL, NULL, 0);
- t = &default_notes_tree;
+ object_ref = 1 < argc ? argv[1] : "HEAD";
- if (prefixcmp(t->ref, "refs/notes/"))
- die("Refusing to %s notes in %s (outside of refs/notes/)",
- argv[0], t->ref);
+ if (get_sha1(object_ref, object))
+ die("Failed to resolve '%s' as a valid ref.", object_ref);
+ t = init_notes_check("copy");
note = get_note(t, object);
- /* list command */
-
- if (list) {
- if (given_object) {
- if (note) {
- puts(sha1_to_hex(note));
- goto end;
- }
- } else {
- retval = for_each_note(t, 0, list_each_note, NULL);
- goto end;
+ if (note) {
+ if (!force) {
+ retval = error("Cannot copy notes. Found existing "
+ "notes for object %s. Use '-f' to "
+ "overwrite existing notes",
+ sha1_to_hex(object));
+ goto out;
}
+ fprintf(stderr, "Overwriting existing notes for object %s\n",
+ sha1_to_hex(object));
}
- /* show command */
-
- if ((list || show) && !note) {
- error("No note found for object %s.", sha1_to_hex(object));
- retval = 1;
- goto end;
- } else if (show) {
- const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
- retval = execv_git_cmd(show_args);
- goto end;
+ from_note = get_note(t, from_obj);
+ if (!from_note) {
+ retval = error("Missing notes on source object %s. Cannot "
+ "copy.", sha1_to_hex(from_obj));
+ goto out;
}
- /* add/append/edit/remove/prune command */
+ add_note(t, object, from_note, combine_notes_overwrite);
+ commit_notes(t, "Notes added by 'git notes copy'");
+out:
+ free_notes(t);
+ return retval;
+}
- if ((add || copy) && note) {
- if (!force) {
- error("Cannot %s notes. Found existing notes for object"
- " %s. Use '-f' to overwrite existing notes",
- argv[0], sha1_to_hex(object));
- retval = 1;
- goto end;
- }
- fprintf(stderr, "Overwriting existing notes for object %s\n",
- sha1_to_hex(object));
- }
+static int append_edit(int argc, const char **argv, const char *prefix)
+{
+ const char *object_ref;
+ struct notes_tree *t;
+ unsigned char object[20], new_note[20];
+ const unsigned char *note;
+ char logmsg[100];
+ const char * const *usage;
+ struct msg_arg msg = { 0, 0, STRBUF_INIT };
+ struct option options[] = {
+ { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
+ "note contents as a string", PARSE_OPT_NONEG,
+ parse_msg_arg},
+ { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
+ "note contents in a file", PARSE_OPT_NONEG,
+ parse_file_arg},
+ { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
+ "reuse and edit specified note object", PARSE_OPT_NONEG,
+ parse_reedit_arg},
+ { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
+ "reuse specified note object", PARSE_OPT_NONEG,
+ parse_reuse_arg},
+ OPT_END()
+ };
+ int edit = !strcmp(argv[0], "edit");
+
+ usage = edit ? git_notes_edit_usage : git_notes_append_usage;
+ argc = parse_options(argc, argv, prefix, options, usage,
+ PARSE_OPT_KEEP_ARGV0);
- if (remove) {
- msg.given = 1;
- msg.use_editor = 0;
- strbuf_reset(&(msg.buf));
+ if (2 < argc) {
+ error("too many parameters");
+ usage_with_options(usage, options);
}
- if (prune) {
- hashclr(new_note);
- prune_notes(t);
- goto commit;
- } else if (copy) {
- const unsigned char *from_note = get_note(t, from_obj);
- if (!from_note) {
- error("Missing notes on source object %s. Cannot copy.",
- sha1_to_hex(from_obj));
- retval = 1;
- goto end;
- }
- hashcpy(new_note, from_note);
- } else
- create_note(object, &msg, append, note, new_note);
+ if (msg.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");
+
+ object_ref = 1 < argc ? argv[1] : "HEAD";
+
+ if (get_sha1(object_ref, object))
+ die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+ t = init_notes_check(argv[0]);
+ note = get_note(t, object);
+
+ create_note(object, &msg, !edit, note, new_note);
if (is_null_sha1(new_note))
remove_note(t, object);
else
add_note(t, object, new_note, combine_notes_overwrite);
-commit:
snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
is_null_sha1(new_note) ? "removed" : "added", argv[0]);
commit_notes(t, logmsg);
-
-end:
free_notes(t);
strbuf_release(&(msg.buf));
+ return 0;
+}
+
+static int show(int argc, const char **argv, const char *prefix)
+{
+ const char *object_ref;
+ struct notes_tree *t;
+ unsigned char object[20];
+ const unsigned char *note;
+ int retval;
+ struct option options[] = {
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options, git_notes_show_usage,
+ 0);
+
+ if (1 < argc) {
+ error("too many parameters");
+ usage_with_options(git_notes_show_usage, options);
+ }
+
+ object_ref = argc ? argv[0] : "HEAD";
+
+ if (get_sha1(object_ref, object))
+ die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+ t = init_notes_check("show");
+ note = get_note(t, object);
+
+ if (!note)
+ retval = error("No note found for object %s.",
+ sha1_to_hex(object));
+ else {
+ const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
+ retval = execv_git_cmd(show_args);
+ }
+ free_notes(t);
return retval;
}
+
+static int remove_cmd(int argc, const char **argv, const char *prefix)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ const char *object_ref;
+ struct notes_tree *t;
+ unsigned char object[20];
+
+ argc = parse_options(argc, argv, prefix, options,
+ git_notes_remove_usage, 0);
+
+ if (1 < argc) {
+ error("too many parameters");
+ usage_with_options(git_notes_remove_usage, options);
+ }
+
+ object_ref = argc ? argv[0] : "HEAD";
+
+ if (get_sha1(object_ref, object))
+ die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+ t = init_notes_check("remove");
+
+ fprintf(stderr, "Removing note for object %s\n", sha1_to_hex(object));
+ remove_note(t, object);
+
+ commit_notes(t, "Notes removed by 'git notes remove'");
+ free_notes(t);
+ return 0;
+}
+
+static int prune(int argc, const char **argv, const char *prefix)
+{
+ struct notes_tree *t;
+ struct option options[] = {
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options, git_notes_prune_usage,
+ 0);
+
+ if (argc) {
+ error("too many parameters");
+ usage_with_options(git_notes_prune_usage, options);
+ }
+
+ t = init_notes_check("prune");
+
+ prune_notes(t);
+ commit_notes(t, "Notes removed by 'git notes prune'");
+ free_notes(t);
+ return 0;
+}
+
+int cmd_notes(int argc, const char **argv, const char *prefix)
+{
+ int result;
+ const char *override_notes_ref = NULL;
+ struct option options[] = {
+ OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
+ "use notes from <notes_ref>"),
+ OPT_END()
+ };
+
+ git_config(git_default_config, NULL);
+ argc = parse_options(argc, argv, prefix, options, git_notes_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (override_notes_ref) {
+ struct strbuf sb = STRBUF_INIT;
+ if (!prefixcmp(override_notes_ref, "refs/notes/"))
+ /* we're happy */;
+ else if (!prefixcmp(override_notes_ref, "notes/"))
+ strbuf_addstr(&sb, "refs/");
+ else
+ strbuf_addstr(&sb, "refs/notes/");
+ strbuf_addstr(&sb, override_notes_ref);
+ setenv("GIT_NOTES_REF", sb.buf, 1);
+ strbuf_release(&sb);
+ }
+
+ if (argc < 1 || !strcmp(argv[0], "list"))
+ result = list(argc, argv, prefix);
+ else if (!strcmp(argv[0], "add"))
+ result = add(argc, argv, prefix);
+ else if (!strcmp(argv[0], "copy"))
+ result = copy(argc, argv, prefix);
+ else if (!strcmp(argv[0], "append") || !strcmp(argv[0], "edit"))
+ result = append_edit(argc, argv, prefix);
+ else if (!strcmp(argv[0], "show"))
+ result = show(argc, argv, prefix);
+ else if (!strcmp(argv[0], "remove"))
+ result = remove_cmd(argc, argv, prefix);
+ else if (!strcmp(argv[0], "prune"))
+ result = prune(argc, argv, prefix);
+ else {
+ result = error("Unknown subcommand: %s", argv[0]);
+ usage_with_options(git_notes_usage, options);
+ }
+
+ return result ? 1 : 0;
+}
diff --git a/builtin/push.c b/builtin/push.c
index 62957ededd..f4358b9d23 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -10,7 +10,7 @@
#include "parse-options.h"
static const char * const push_usage[] = {
- "git push [<options>] [<repository> <refspec>...]",
+ "git push [<options>] [<repository> [<refspec>...]]",
NULL,
};
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 64e45bd813..f73215686d 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -13,7 +13,7 @@
*/
static const char reflog_expire_usage[] =
-"git reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+"git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
static const char reflog_delete_usage[] =
"git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
@@ -36,6 +36,8 @@ struct expire_reflog_cb {
FILE *newlog;
const char *ref;
struct commit *ref_commit;
+ struct commit_list *mark_list;
+ unsigned long mark_limit;
struct cmd_reflog_expire_cb *cmd;
unsigned char last_kept_sha1[20];
};
@@ -210,46 +212,23 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
return 1;
}
-static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1)
+/*
+ * Starting from commits in the cb->mark_list, mark commits that are
+ * reachable from them. Stop the traversal at commits older than
+ * the expire_limit and queue them back, so that the caller can call
+ * us again to restart the traversal with longer expire_limit.
+ */
+static void mark_reachable(struct expire_reflog_cb *cb)
{
- /*
- * We may or may not have the commit yet - if not, look it
- * up using the supplied sha1.
- */
- if (!commit) {
- if (is_null_sha1(sha1))
- return 0;
-
- commit = lookup_commit_reference_gently(sha1, 1);
-
- /* Not a commit -- keep it */
- if (!commit)
- return 0;
- }
-
- /* Reachable from the current ref? Don't prune. */
- if (commit->object.flags & REACHABLE)
- return 0;
- if (in_merge_bases(commit, &cb->ref_commit, 1))
- return 0;
-
- /* We can't reach it - prune it. */
- return 1;
-}
+ struct commit *commit;
+ struct commit_list *pending;
+ unsigned long expire_limit = cb->mark_limit;
+ struct commit_list *leftover = NULL;
-static void mark_reachable(struct commit *commit, unsigned long expire_limit)
-{
- /*
- * We need to compute whether the commit on either side of a reflog
- * entry is reachable from the tip of the ref for all entries.
- * Mark commits that are reachable from the tip down to the
- * time threshold first; we know a commit marked thusly is
- * reachable from the tip without running in_merge_bases()
- * at all.
- */
- struct commit_list *pending = NULL;
+ for (pending = cb->mark_list; pending; pending = pending->next)
+ pending->item->object.flags &= ~REACHABLE;
- commit_list_insert(commit, &pending);
+ pending = cb->mark_list;
while (pending) {
struct commit_list *entry = pending;
struct commit_list *parent;
@@ -261,8 +240,11 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit)
if (parse_commit(commit))
continue;
commit->object.flags |= REACHABLE;
- if (commit->date < expire_limit)
+ if (commit->date < expire_limit) {
+ commit_list_insert(commit, &leftover);
continue;
+ }
+ commit->object.flags |= REACHABLE;
parent = commit->parents;
while (parent) {
commit = parent->item;
@@ -272,6 +254,36 @@ static void mark_reachable(struct commit *commit, unsigned long expire_limit)
commit_list_insert(commit, &pending);
}
}
+ cb->mark_list = leftover;
+}
+
+static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1)
+{
+ /*
+ * We may or may not have the commit yet - if not, look it
+ * up using the supplied sha1.
+ */
+ if (!commit) {
+ if (is_null_sha1(sha1))
+ return 0;
+
+ commit = lookup_commit_reference_gently(sha1, 1);
+
+ /* Not a commit -- keep it */
+ if (!commit)
+ return 0;
+ }
+
+ /* Reachable from the current ref? Don't prune. */
+ if (commit->object.flags & REACHABLE)
+ return 0;
+
+ if (cb->mark_list && cb->mark_limit) {
+ cb->mark_limit = 0; /* dig down to the root */
+ mark_reachable(cb);
+ }
+
+ return !(commit->object.flags & REACHABLE);
}
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
@@ -348,8 +360,12 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
cb.ref = ref;
cb.cmd = cmd;
- if (cb.ref_commit)
- mark_reachable(cb.ref_commit, cmd->expire_total);
+ if (cb.ref_commit) {
+ cb.mark_list = NULL;
+ commit_list_insert(cb.ref_commit, &cb.mark_list);
+ cb.mark_limit = cmd->expire_total;
+ mark_reachable(&cb);
+ }
for_each_reflog_ent(ref, expire_reflog_ent, &cb);
if (cb.ref_commit)
clear_commit_marks(cb.ref_commit, REACHABLE);
diff --git a/builtin/reset.c b/builtin/reset.c
index 2c3a69adc6..1283068fd2 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -23,7 +23,8 @@
static const char * const git_reset_usage[] = {
"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]",
- "git reset [--mixed] <commit> [--] <paths>...",
+ "git reset [-q] <commit> [--] <paths>...",
+ "git reset --patch [<commit>] [--] [<paths>...]",
NULL
};
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 5679170e82..51ceb19d88 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -133,9 +133,12 @@ static void show_commit(struct commit *commit, void *data)
*/
if (graph_show_remainder(revs->graph))
putchar('\n');
+ if (revs->commit_format == CMIT_FMT_ONELINE)
+ putchar('\n');
}
} else {
- if (buf.len)
+ if (revs->commit_format != CMIT_FMT_USERFORMAT ||
+ buf.len)
printf("%s%c", buf.buf, info->hdr_termination);
}
strbuf_release(&buf);
@@ -313,7 +316,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
init_revisions(&revs, prefix);
- revs.abbrev = 0;
+ revs.abbrev = DEFAULT_ABBREV;
revs.commit_format = CMIT_FMT_UNSPECIFIED;
argc = setup_revisions(argc, argv, &revs, NULL);
diff --git a/builtin/revert.c b/builtin/revert.c
index eff52687a8..7976b5a329 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -13,6 +13,7 @@
#include "revision.h"
#include "rerere.h"
#include "merge-recursive.h"
+#include "refs.h"
/*
* This implements the builtins revert and cherry-pick.
@@ -35,16 +36,19 @@ static const char * const cherry_pick_usage[] = {
NULL
};
-static int edit, no_replay, no_commit, mainline, signoff;
+static int edit, no_replay, no_commit, mainline, signoff, allow_ff;
static enum { REVERT, CHERRY_PICK } action;
static struct commit *commit;
static const char *commit_name;
static int allow_rerere_auto;
static const char *me;
+static const char *strategy;
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
+static char *get_encoding(const char *message);
+
static void parse_args(int argc, const char **argv)
{
const char * const * usage_str =
@@ -59,9 +63,21 @@ static void parse_args(int argc, const char **argv)
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
OPT_INTEGER('m', "mainline", &mainline, "parent number"),
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
+ OPT_STRING(0, "strategy", &strategy, "strategy", "merge strategy"),
+ OPT_END(),
+ OPT_END(),
OPT_END(),
};
+ if (action == CHERRY_PICK) {
+ struct option cp_extra[] = {
+ OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"),
+ OPT_END(),
+ };
+ if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
+ die("program error");
+ }
+
if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1)
usage_with_options(usage_str, options);
@@ -73,33 +89,69 @@ static void parse_args(int argc, const char **argv)
exit(1);
}
-static char *get_oneline(const char *message)
+struct commit_message {
+ char *parent_label;
+ const char *label;
+ const char *subject;
+ char *reencoded_message;
+ const char *message;
+};
+
+static int get_message(const char *raw_message, struct commit_message *out)
{
- char *result;
- const char *p = message, *abbrev, *eol;
+ const char *encoding;
+ const char *p, *abbrev, *eol;
+ char *q;
int abbrev_len, oneline_len;
- if (!p)
- die ("Could not read commit message of %s",
- sha1_to_hex(commit->object.sha1));
+ if (!raw_message)
+ return -1;
+ encoding = get_encoding(raw_message);
+ if (!encoding)
+ encoding = "UTF-8";
+ if (!git_commit_encoding)
+ git_commit_encoding = "UTF-8";
+
+ out->reencoded_message = NULL;
+ out->message = raw_message;
+ if (strcmp(encoding, git_commit_encoding))
+ out->reencoded_message = reencode_string(raw_message,
+ git_commit_encoding, encoding);
+ if (out->reencoded_message)
+ out->message = out->reencoded_message;
+
+ abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
+ abbrev_len = strlen(abbrev);
+
+ /* Find beginning and end of commit subject. */
+ p = out->message;
while (*p && (*p != '\n' || p[1] != '\n'))
p++;
-
if (*p) {
p += 2;
for (eol = p + 1; *eol && *eol != '\n'; eol++)
; /* do nothing */
} else
eol = p;
- abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
- abbrev_len = strlen(abbrev);
oneline_len = eol - p;
- result = xmalloc(abbrev_len + 5 + oneline_len);
- memcpy(result, abbrev, abbrev_len);
- memcpy(result + abbrev_len, "... ", 4);
- memcpy(result + abbrev_len + 4, p, oneline_len);
- result[abbrev_len + 4 + oneline_len] = '\0';
- return result;
+
+ out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
+ strlen("... ") + oneline_len + 1);
+ q = out->parent_label;
+ q = mempcpy(q, "parent of ", strlen("parent of "));
+ out->label = q;
+ q = mempcpy(q, abbrev, abbrev_len);
+ q = mempcpy(q, "... ", strlen("... "));
+ out->subject = q;
+ q = mempcpy(q, p, oneline_len);
+ *q = '\0';
+ return 0;
+}
+
+static void free_message(struct commit_message *msg)
+{
+ free(msg->parent_label);
+ free(msg->reencoded_message);
}
static char *get_encoding(const char *message)
@@ -124,28 +176,17 @@ static char *get_encoding(const char *message)
return NULL;
}
-static struct lock_file msg_file;
-static int msg_fd;
-
-static void add_to_msg(const char *string)
-{
- int len = strlen(string);
- if (write_in_full(msg_fd, string, len) < 0)
- die_errno ("Could not write to MERGE_MSG");
-}
-
-static void add_message_to_msg(const char *message)
+static void add_message_to_msg(struct strbuf *msgbuf, const char *message)
{
const char *p = message;
while (*p && (*p != '\n' || p[1] != '\n'))
p++;
if (!*p)
- add_to_msg(sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(msgbuf, sha1_to_hex(commit->object.sha1));
p += 2;
- add_to_msg(p);
- return;
+ strbuf_addstr(msgbuf, p);
}
static void set_author_ident_env(const char *message)
@@ -221,6 +262,19 @@ static char *help_msg(const char *name)
return strbuf_detach(&helpbuf, NULL);
}
+static void write_message(struct strbuf *msgbuf, const char *filename)
+{
+ static struct lock_file msg_file;
+
+ int msg_fd = hold_lock_file_for_update(&msg_file, filename,
+ LOCK_DIE_ON_ERROR);
+ if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
+ die_errno("Could not write to %s.", filename);
+ strbuf_release(msgbuf);
+ if (commit_lock_file(&msg_file) < 0)
+ die("Error wrapping up %s", filename);
+}
+
static struct tree *empty_tree(void)
{
struct tree *tree = xcalloc(1, sizeof(struct tree));
@@ -244,18 +298,82 @@ static NORETURN void die_dirty_index(const char *me)
}
}
-static int revert_or_cherry_pick(int argc, const char **argv)
+static int fast_forward_to(const unsigned char *to, const unsigned char *from)
+{
+ struct ref_lock *ref_lock;
+
+ read_cache();
+ if (checkout_fast_forward(from, to))
+ exit(1); /* the callee should have complained already */
+ ref_lock = lock_any_ref_for_update("HEAD", from, 0);
+ return write_ref_sha1(ref_lock, to, "cherry-pick");
+}
+
+static void do_recursive_merge(struct commit *base, struct commit *next,
+ const char *base_label, const char *next_label,
+ unsigned char *head, struct strbuf *msgbuf,
+ char *defmsg)
{
- unsigned char head[20];
- struct commit *base, *next, *parent;
- int i, index_fd, clean;
- char *oneline, *reencoded_message = NULL;
- const char *message, *encoding;
- char *defmsg = git_pathdup("MERGE_MSG");
struct merge_options o;
struct tree *result, *next_tree, *base_tree, *head_tree;
+ int clean, index_fd;
static struct lock_file index_lock;
+ index_fd = hold_locked_index(&index_lock, 1);
+
+ read_cache();
+ init_merge_options(&o);
+ o.ancestor = base ? base_label : "(empty tree)";
+ o.branch1 = "HEAD";
+ o.branch2 = next ? next_label : "(empty tree)";
+
+ head_tree = parse_tree_indirect(head);
+ next_tree = next ? next->tree : empty_tree();
+ base_tree = base ? base->tree : empty_tree();
+
+ clean = merge_trees(&o,
+ head_tree,
+ next_tree, base_tree, &result);
+
+ if (active_cache_changed &&
+ (write_cache(index_fd, active_cache, active_nr) ||
+ commit_locked_index(&index_lock)))
+ die("%s: Unable to write new index file", me);
+ rollback_lock_file(&index_lock);
+
+ if (!clean) {
+ int i;
+ strbuf_addstr(msgbuf, "\nConflicts:\n\n");
+ for (i = 0; i < active_nr;) {
+ struct cache_entry *ce = active_cache[i++];
+ if (ce_stage(ce)) {
+ strbuf_addch(msgbuf, '\t');
+ strbuf_addstr(msgbuf, ce->name);
+ strbuf_addch(msgbuf, '\n');
+ while (i < active_nr && !strcmp(ce->name,
+ active_cache[i]->name))
+ i++;
+ }
+ }
+ write_message(msgbuf, defmsg);
+ fprintf(stderr, "Automatic %s failed.%s\n",
+ me, help_msg(commit_name));
+ rerere(allow_rerere_auto);
+ exit(1);
+ }
+ write_message(msgbuf, defmsg);
+ fprintf(stderr, "Finished one %s.\n", me);
+}
+
+static int revert_or_cherry_pick(int argc, const char **argv)
+{
+ unsigned char head[20];
+ struct commit *base, *next, *parent;
+ const char *base_label, *next_label;
+ struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
+ char *defmsg = NULL;
+ struct strbuf msgbuf = STRBUF_INIT;
+
git_config(git_default_config, NULL);
me = action == REVERT ? "revert" : "cherry-pick";
setenv(GIT_REFLOG_ACTION, me, 0);
@@ -265,6 +383,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
if (action == REVERT && !no_replay)
die("revert is incompatible with replay");
+ if (allow_ff) {
+ if (signoff)
+ die("cherry-pick --ff cannot be used with --signoff");
+ if (no_commit)
+ die("cherry-pick --ff cannot be used with --no-commit");
+ if (no_replay)
+ die("cherry-pick --ff cannot be used with -x");
+ if (edit)
+ die("cherry-pick --ff cannot be used with --edit");
+ }
+
if (read_cache() < 0)
die("git %s: failed to read the index", me);
if (no_commit) {
@@ -284,8 +413,6 @@ static int revert_or_cherry_pick(int argc, const char **argv)
}
discard_cache();
- index_fd = hold_locked_index(&index_lock, 1);
-
if (!commit->parents) {
if (action == REVERT)
die ("Cannot revert a root commit");
@@ -314,14 +441,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
else
parent = commit->parents->item;
- if (!(message = commit->buffer))
- die ("Cannot get commit message for %s",
- sha1_to_hex(commit->object.sha1));
+ if (allow_ff && !hashcmp(parent->object.sha1, head))
+ return fast_forward_to(commit->object.sha1, head);
if (parent && parse_commit(parent) < 0)
die("%s: cannot parse parent commit %s",
me, sha1_to_hex(parent->object.sha1));
+ if (get_message(commit->buffer, &msg) != 0)
+ die("Cannot get commit message for %s",
+ sha1_to_hex(commit->object.sha1));
+
/*
* "commit" is an existing commit. We would want to apply
* the difference it introduces since its first parent "prev"
@@ -329,89 +459,58 @@ static int revert_or_cherry_pick(int argc, const char **argv)
* reverse of it if we are revert.
*/
- msg_fd = hold_lock_file_for_update(&msg_file, defmsg,
- LOCK_DIE_ON_ERROR);
-
- encoding = get_encoding(message);
- if (!encoding)
- encoding = "UTF-8";
- if (!git_commit_encoding)
- git_commit_encoding = "UTF-8";
- if ((reencoded_message = reencode_string(message,
- git_commit_encoding, encoding)))
- message = reencoded_message;
-
- oneline = get_oneline(message);
+ defmsg = git_pathdup("MERGE_MSG");
if (action == REVERT) {
- char *oneline_body = strchr(oneline, ' ');
-
base = commit;
+ base_label = msg.label;
next = parent;
- add_to_msg("Revert \"");
- add_to_msg(oneline_body + 1);
- add_to_msg("\"\n\nThis reverts commit ");
- add_to_msg(sha1_to_hex(commit->object.sha1));
+ next_label = msg.parent_label;
+ strbuf_addstr(&msgbuf, "Revert \"");
+ strbuf_addstr(&msgbuf, msg.subject);
+ strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
+ strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
if (commit->parents->next) {
- add_to_msg(", reversing\nchanges made to ");
- add_to_msg(sha1_to_hex(parent->object.sha1));
+ strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
+ strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
}
- add_to_msg(".\n");
+ strbuf_addstr(&msgbuf, ".\n");
} else {
base = parent;
+ base_label = msg.parent_label;
next = commit;
- set_author_ident_env(message);
- add_message_to_msg(message);
+ next_label = msg.label;
+ set_author_ident_env(msg.message);
+ add_message_to_msg(&msgbuf, msg.message);
if (no_replay) {
- add_to_msg("(cherry picked from commit ");
- add_to_msg(sha1_to_hex(commit->object.sha1));
- add_to_msg(")\n");
+ strbuf_addstr(&msgbuf, "(cherry picked from commit ");
+ strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(&msgbuf, ")\n");
}
}
- read_cache();
- init_merge_options(&o);
- o.branch1 = "HEAD";
- o.branch2 = oneline;
-
- head_tree = parse_tree_indirect(head);
- next_tree = next ? next->tree : empty_tree();
- base_tree = base ? base->tree : empty_tree();
-
- clean = merge_trees(&o,
- head_tree,
- next_tree, base_tree, &result);
-
- if (active_cache_changed &&
- (write_cache(index_fd, active_cache, active_nr) ||
- commit_locked_index(&index_lock)))
- die("%s: Unable to write new index file", me);
- rollback_lock_file(&index_lock);
-
- if (!clean) {
- add_to_msg("\nConflicts:\n\n");
- for (i = 0; i < active_nr;) {
- struct cache_entry *ce = active_cache[i++];
- if (ce_stage(ce)) {
- add_to_msg("\t");
- add_to_msg(ce->name);
- add_to_msg("\n");
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
- i++;
- }
+ if (!strategy || !strcmp(strategy, "recursive") || action == REVERT)
+ do_recursive_merge(base, next, base_label, next_label,
+ head, &msgbuf, defmsg);
+ else {
+ int res;
+ struct commit_list *common = NULL;
+ struct commit_list *remotes = NULL;
+ write_message(&msgbuf, defmsg);
+ commit_list_insert(base, &common);
+ commit_list_insert(next, &remotes);
+ res = try_merge_command(strategy, common,
+ sha1_to_hex(head), remotes);
+ free_commit_list(common);
+ free_commit_list(remotes);
+ if (res) {
+ fprintf(stderr, "Automatic %s with strategy %s failed.%s\n",
+ me, strategy, help_msg(commit_name));
+ rerere(allow_rerere_auto);
+ exit(1);
}
- if (commit_lock_file(&msg_file) < 0)
- die ("Error wrapping up %s", defmsg);
- fprintf(stderr, "Automatic %s failed.%s\n",
- me, help_msg(commit_name));
- rerere(allow_rerere_auto);
- exit(1);
}
- if (commit_lock_file(&msg_file) < 0)
- die ("Error wrapping up %s", defmsg);
- fprintf(stderr, "Finished one %s.\n", me);
/*
*
@@ -437,7 +536,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
args[i] = NULL;
return execv_git_cmd(args);
}
- free(reencoded_message);
+ free_message(&msg);
free(defmsg);
return 0;
diff --git a/builtin/tag.c b/builtin/tag.c
index 4ef1c4f508..d311491e49 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -147,11 +147,11 @@ static int delete_tag(const char *name, const char *ref,
static int verify_tag(const char *name, const char *ref,
const unsigned char *sha1)
{
- const char *argv_verify_tag[] = {"git-verify-tag",
+ const char *argv_verify_tag[] = {"verify-tag",
"-v", "SHA1_HEX", NULL};
argv_verify_tag[2] = sha1_to_hex(sha1);
- if (run_command_v_opt(argv_verify_tag, 0))
+ if (run_command_v_opt(argv_verify_tag, RUN_GIT_CMD))
return error("could not verify the tag '%s'", name);
return 0;
}