summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c2
-rw-r--r--builtin/apply.c23
-rw-r--r--builtin/blame.c194
-rw-r--r--builtin/branch.c2
-rw-r--r--builtin/clone.c6
-rw-r--r--builtin/commit.c37
-rw-r--r--builtin/config.c108
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff-index.c8
-rw-r--r--builtin/diff.c28
-rw-r--r--builtin/fast-export.c27
-rw-r--r--builtin/fetch-pack.c950
-rw-r--r--builtin/fmt-merge-msg.c21
-rw-r--r--builtin/log.c91
-rw-r--r--builtin/ls-files.c4
-rw-r--r--builtin/ls-tree.c2
-rw-r--r--builtin/merge-index.c4
-rw-r--r--builtin/merge-tree.c92
-rw-r--r--builtin/merge.c112
-rw-r--r--builtin/pack-objects.c1
-rw-r--r--builtin/push.c32
-rw-r--r--builtin/replace.c15
-rw-r--r--builtin/rev-list.c49
-rw-r--r--builtin/rm.c140
-rw-r--r--builtin/send-pack.c342
-rw-r--r--builtin/shortlog.c59
-rw-r--r--builtin/show-ref.c23
-rw-r--r--builtin/symbolic-ref.c33
-rw-r--r--builtin/update-index.c1
29 files changed, 582 insertions, 1826 deletions
diff --git a/builtin/add.c b/builtin/add.c
index e664100c71..075312afcd 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -454,7 +454,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
&& !file_exists(pathspec[i])) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
- if (path_excluded(&check, pathspec[i], -1, &dtype))
+ if (is_path_excluded(&check, pathspec[i], -1, &dtype))
dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
} else
die(_("pathspec '%s' did not match any files"),
diff --git a/builtin/apply.c b/builtin/apply.c
index 156b3ce3b7..6c11e8bc73 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -2095,7 +2095,7 @@ static void update_pre_post_images(struct image *preimage,
char *buf,
size_t len, size_t postlen)
{
- int i, ctx;
+ int i, ctx, reduced;
char *new, *old, *fixed;
struct image fixed_preimage;
@@ -2105,8 +2105,10 @@ static void update_pre_post_images(struct image *preimage,
* free "oldlines".
*/
prepare_image(&fixed_preimage, buf, len, 1);
- assert(fixed_preimage.nr == preimage->nr);
- for (i = 0; i < preimage->nr; i++)
+ assert(postlen
+ ? fixed_preimage.nr == preimage->nr
+ : fixed_preimage.nr <= preimage->nr);
+ for (i = 0; i < fixed_preimage.nr; i++)
fixed_preimage.line[i].flag = preimage->line[i].flag;
free(preimage->line_allocated);
*preimage = fixed_preimage;
@@ -2126,7 +2128,8 @@ static void update_pre_post_images(struct image *preimage,
else
new = old;
fixed = preimage->buf;
- for (i = ctx = 0; i < postimage->nr; i++) {
+
+ for (i = reduced = ctx = 0; i < postimage->nr; i++) {
size_t len = postimage->line[i].len;
if (!(postimage->line[i].flag & LINE_COMMON)) {
/* an added line -- no counterparts in preimage */
@@ -2145,8 +2148,15 @@ static void update_pre_post_images(struct image *preimage,
fixed += preimage->line[ctx].len;
ctx++;
}
- if (preimage->nr <= ctx)
- die(_("oops"));
+
+ /*
+ * preimage is expected to run out, if the caller
+ * fixed addition of trailing blank lines.
+ */
+ if (preimage->nr <= ctx) {
+ reduced++;
+ continue;
+ }
/* and copy it in, while fixing the line length */
len = preimage->line[ctx].len;
@@ -2159,6 +2169,7 @@ static void update_pre_post_images(struct image *preimage,
/* Fix the length of the whole thing */
postimage->len = new - postimage->buf;
+ postimage->nr -= reduced;
}
static int match_fragment(struct image *img,
diff --git a/builtin/blame.c b/builtin/blame.c
index c27ef21c23..b431ba3209 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -42,6 +42,7 @@ static int blank_boundary;
static int incremental;
static int xdl_opts;
static int abbrev = -1;
+static int no_whole_file_rename;
static enum date_mode blame_date_mode = DATE_ISO8601;
static size_t blame_date_width;
@@ -1226,7 +1227,7 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
* The first pass looks for unrenamed path to optimize for
* common cases, then we look for renames in the second pass.
*/
- for (pass = 0; pass < 2; pass++) {
+ for (pass = 0; pass < 2 - no_whole_file_rename; pass++) {
struct origin *(*find)(struct scoreboard *,
struct commit *, struct origin *);
find = pass ? find_rename : find_origin;
@@ -1321,30 +1322,31 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
* Information on commits, used for output.
*/
struct commit_info {
- const char *author;
- const char *author_mail;
+ struct strbuf author;
+ struct strbuf author_mail;
unsigned long author_time;
- const char *author_tz;
+ struct strbuf author_tz;
/* filled only when asked for details */
- const char *committer;
- const char *committer_mail;
+ struct strbuf committer;
+ struct strbuf committer_mail;
unsigned long committer_time;
- const char *committer_tz;
+ struct strbuf committer_tz;
- const char *summary;
+ struct strbuf summary;
};
/*
* Parse author/committer line in the commit object buffer
*/
static void get_ac_line(const char *inbuf, const char *what,
- int person_len, char *person,
- int mail_len, char *mail,
- unsigned long *time, const char **tz)
+ struct strbuf *name, struct strbuf *mail,
+ unsigned long *time, struct strbuf *tz)
{
- int len, tzlen, maillen;
- char *tmp, *endp, *timepos, *mailpos;
+ struct ident_split ident;
+ size_t len, maillen, namelen;
+ char *tmp, *endp;
+ const char *namebuf, *mailbuf;
tmp = strstr(inbuf, what);
if (!tmp)
@@ -1355,69 +1357,61 @@ static void get_ac_line(const char *inbuf, const char *what,
len = strlen(tmp);
else
len = endp - tmp;
- if (person_len <= len) {
+
+ if (split_ident_line(&ident, tmp, len)) {
error_out:
/* Ugh */
- *tz = "(unknown)";
- strcpy(person, *tz);
- strcpy(mail, *tz);
+ tmp = "(unknown)";
+ strbuf_addstr(name, tmp);
+ strbuf_addstr(mail, tmp);
+ strbuf_addstr(tz, tmp);
*time = 0;
return;
}
- memcpy(person, tmp, len);
- tmp = person;
- tmp += len;
- *tmp = 0;
- while (person < tmp && *tmp != ' ')
- tmp--;
- if (tmp <= person)
- goto error_out;
- *tz = tmp+1;
- tzlen = (person+len)-(tmp+1);
+ namelen = ident.name_end - ident.name_begin;
+ namebuf = ident.name_begin;
- *tmp = 0;
- while (person < tmp && *tmp != ' ')
- tmp--;
- if (tmp <= person)
- goto error_out;
- *time = strtoul(tmp, NULL, 10);
- timepos = tmp;
+ maillen = ident.mail_end - ident.mail_begin;
+ mailbuf = ident.mail_begin;
- *tmp = 0;
- while (person < tmp && !(*tmp == ' ' && tmp[1] == '<'))
- tmp--;
- if (tmp <= person)
- return;
- mailpos = tmp + 1;
- *tmp = 0;
- maillen = timepos - tmp;
- memcpy(mail, mailpos, maillen);
+ *time = strtoul(ident.date_begin, NULL, 10);
- if (!mailmap.nr)
- return;
-
- /*
- * mailmap expansion may make the name longer.
- * make room by pushing stuff down.
- */
- tmp = person + person_len - (tzlen + 1);
- memmove(tmp, *tz, tzlen);
- tmp[tzlen] = 0;
- *tz = tmp;
+ len = ident.tz_end - ident.tz_begin;
+ strbuf_add(tz, ident.tz_begin, len);
/*
* Now, convert both name and e-mail using mailmap
*/
- if (map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) {
- /* Add a trailing '>' to email, since map_user returns plain emails
- Note: It already has '<', since we replace from mail+1 */
- mailpos = memchr(mail, '\0', mail_len);
- if (mailpos && mailpos-mail < mail_len - 1) {
- *mailpos = '>';
- *(mailpos+1) = '\0';
- }
- }
+ map_user(&mailmap, &mailbuf, &maillen,
+ &namebuf, &namelen);
+
+ strbuf_addf(mail, "<%.*s>", (int)maillen, mailbuf);
+ strbuf_add(name, namebuf, namelen);
+}
+
+static void commit_info_init(struct commit_info *ci)
+{
+
+ strbuf_init(&ci->author, 0);
+ strbuf_init(&ci->author_mail, 0);
+ strbuf_init(&ci->author_tz, 0);
+ strbuf_init(&ci->committer, 0);
+ strbuf_init(&ci->committer_mail, 0);
+ strbuf_init(&ci->committer_tz, 0);
+ strbuf_init(&ci->summary, 0);
+}
+
+static void commit_info_destroy(struct commit_info *ci)
+{
+
+ strbuf_release(&ci->author);
+ strbuf_release(&ci->author_mail);
+ strbuf_release(&ci->author_tz);
+ strbuf_release(&ci->committer);
+ strbuf_release(&ci->committer_mail);
+ strbuf_release(&ci->committer_tz);
+ strbuf_release(&ci->summary);
}
static void get_commit_info(struct commit *commit,
@@ -1425,13 +1419,10 @@ static void get_commit_info(struct commit *commit,
int detailed)
{
int len;
- const char *subject;
+ const char *subject, *encoding;
char *reencoded, *message;
- static char author_name[1024];
- static char author_mail[1024];
- static char committer_name[1024];
- static char committer_mail[1024];
- static char summary_buf[1024];
+
+ commit_info_init(ret);
/*
* We've operated without save_commit_buffer, so
@@ -1446,13 +1437,11 @@ static void get_commit_info(struct commit *commit,
die("Cannot read commit %s",
sha1_to_hex(commit->object.sha1));
}
- reencoded = reencode_commit_message(commit, NULL);
+ encoding = get_log_output_encoding();
+ reencoded = logmsg_reencode(commit, encoding);
message = reencoded ? reencoded : commit->buffer;
- ret->author = author_name;
- ret->author_mail = author_mail;
get_ac_line(message, "\nauthor ",
- sizeof(author_name), author_name,
- sizeof(author_mail), author_mail,
+ &ret->author, &ret->author_mail,
&ret->author_time, &ret->author_tz);
if (!detailed) {
@@ -1460,21 +1449,16 @@ static void get_commit_info(struct commit *commit,
return;
}
- ret->committer = committer_name;
- ret->committer_mail = committer_mail;
get_ac_line(message, "\ncommitter ",
- sizeof(committer_name), committer_name,
- sizeof(committer_mail), committer_mail,
+ &ret->committer, &ret->committer_mail,
&ret->committer_time, &ret->committer_tz);
- ret->summary = summary_buf;
len = find_commit_subject(message, &subject);
- if (len && len < sizeof(summary_buf)) {
- memcpy(summary_buf, subject, len);
- summary_buf[len] = 0;
- } else {
- sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1));
- }
+ if (len)
+ strbuf_add(&ret->summary, subject, len);
+ else
+ strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1));
+
free(reencoded);
}
@@ -1503,15 +1487,15 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1);
- printf("author %s\n", ci.author);
- printf("author-mail %s\n", ci.author_mail);
+ printf("author %s\n", ci.author.buf);
+ printf("author-mail %s\n", ci.author_mail.buf);
printf("author-time %lu\n", ci.author_time);
- printf("author-tz %s\n", ci.author_tz);
- printf("committer %s\n", ci.committer);
- printf("committer-mail %s\n", ci.committer_mail);
+ printf("author-tz %s\n", ci.author_tz.buf);
+ printf("committer %s\n", ci.committer.buf);
+ printf("committer-mail %s\n", ci.committer_mail.buf);
printf("committer-time %lu\n", ci.committer_time);
- printf("committer-tz %s\n", ci.committer_tz);
- printf("summary %s\n", ci.summary);
+ printf("committer-tz %s\n", ci.committer_tz.buf);
+ printf("summary %s\n", ci.summary.buf);
if (suspect->commit->object.flags & UNINTERESTING)
printf("boundary\n");
if (suspect->previous) {
@@ -1519,6 +1503,9 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
write_name_quoted(prev->path, stdout, '\n');
}
+
+ commit_info_destroy(&ci);
+
return 1;
}
@@ -1705,11 +1692,11 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
if (opt & OUTPUT_ANNOTATE_COMPAT) {
const char *name;
if (opt & OUTPUT_SHOW_EMAIL)
- name = ci.author_mail;
+ name = ci.author_mail.buf;
else
- name = ci.author;
+ name = ci.author.buf;
printf("\t(%10s\t%10s\t%d)", name,
- format_time(ci.author_time, ci.author_tz,
+ format_time(ci.author_time, ci.author_tz.buf,
show_raw_time),
ent->lno + 1 + cnt);
} else {
@@ -1728,14 +1715,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
const char *name;
int pad;
if (opt & OUTPUT_SHOW_EMAIL)
- name = ci.author_mail;
+ name = ci.author_mail.buf;
else
- name = ci.author;
+ name = ci.author.buf;
pad = longest_author - utf8_strwidth(name);
printf(" (%s%*s %10s",
name, pad, "",
format_time(ci.author_time,
- ci.author_tz,
+ ci.author_tz.buf,
show_raw_time));
}
printf(" %*d) ",
@@ -1750,6 +1737,8 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
if (sb->final_buf_size && cp[-1] != '\n')
putchar('\n');
+
+ commit_info_destroy(&ci);
}
static void output(struct scoreboard *sb, int option)
@@ -1874,9 +1863,9 @@ static void find_alignment(struct scoreboard *sb, int *option)
suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1);
if (*option & OUTPUT_SHOW_EMAIL)
- num = utf8_strwidth(ci.author_mail);
+ num = utf8_strwidth(ci.author_mail.buf);
else
- num = utf8_strwidth(ci.author);
+ num = utf8_strwidth(ci.author.buf);
if (longest_author < num)
longest_author = num;
}
@@ -1888,6 +1877,8 @@ static void find_alignment(struct scoreboard *sb, int *option)
longest_dst_lines = num;
if (largest_score < ent_score(sb, e))
largest_score = ent_score(sb, e);
+
+ commit_info_destroy(&ci);
}
max_orig_digits = decimal_width(longest_src_lines);
max_digits = decimal_width(longest_dst_lines);
@@ -2402,6 +2393,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
+ DIFF_OPT_SET(&revs.diffopt, FOLLOW_RENAMES);
save_commit_buffer = 0;
dashdash_pos = 0;
@@ -2425,6 +2417,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
}
parse_done:
+ no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES);
+ DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
argc = parse_options_end(&ctx);
if (0 < abbrev)
diff --git a/builtin/branch.c b/builtin/branch.c
index 1ec9c02612..873f624d1c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -725,7 +725,7 @@ static int edit_branch_description(const char *branch_name)
stripspace(&buf, 1);
strbuf_addf(&name, "branch.%s.description", branch_name);
- status = git_config_set(name.buf, buf.buf);
+ status = git_config_set(name.buf, buf.len ? buf.buf : NULL);
strbuf_release(&name);
strbuf_release(&buf);
diff --git a/builtin/clone.c b/builtin/clone.c
index ec2f75b4f3..36ec99db3f 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -704,6 +704,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_origin)
die(_("--bare and --origin %s options are incompatible."),
option_origin);
+ if (real_git_dir)
+ die(_("--bare and --separate-git-dir are incompatible."));
option_no_checkout = 1;
}
@@ -771,8 +773,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("could not create leading directories of '%s'"), git_dir);
set_git_dir_init(git_dir, real_git_dir, 0);
- if (real_git_dir)
+ if (real_git_dir) {
git_dir = real_git_dir;
+ junk_git_dir = real_git_dir;
+ }
if (0 <= option_verbosity) {
if (option_bare)
diff --git a/builtin/commit.c b/builtin/commit.c
index a17a5df449..7c2a3d48b4 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -103,7 +103,7 @@ static enum {
CLEANUP_NONE,
CLEANUP_ALL
} cleanup_mode;
-static char *cleanup_arg;
+static const char *cleanup_arg;
static enum commit_whence whence;
static int use_editor = 1, include_status = 1;
@@ -112,10 +112,11 @@ static const char *only_include_assumed;
static struct strbuf message = STRBUF_INIT;
static enum {
+ STATUS_FORMAT_NONE = 0,
STATUS_FORMAT_LONG,
STATUS_FORMAT_SHORT,
STATUS_FORMAT_PORCELAIN
-} status_format = STATUS_FORMAT_LONG;
+} status_format;
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
{
@@ -454,6 +455,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(s);
break;
+ case STATUS_FORMAT_NONE:
case STATUS_FORMAT_LONG:
wt_status_print(s);
break;
@@ -753,7 +755,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
ident_shown++ ? "" : "\n",
author_ident->buf);
- if (!user_ident_sufficiently_given())
+ if (!committer_ident_sufficiently_given())
status_printf_ln(s, GIT_COLOR_NORMAL,
_("%s"
"Committer: %s"),
@@ -1058,9 +1060,13 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (all && argc > 0)
die(_("Paths with -a does not make sense."));
- if (s->null_termination && status_format == STATUS_FORMAT_LONG)
- status_format = STATUS_FORMAT_PORCELAIN;
- if (status_format != STATUS_FORMAT_LONG)
+ if (s->null_termination) {
+ if (status_format == STATUS_FORMAT_NONE)
+ status_format = STATUS_FORMAT_PORCELAIN;
+ else if (status_format == STATUS_FORMAT_LONG)
+ die(_("--long and -z are incompatible"));
+ }
+ if (status_format != STATUS_FORMAT_NONE)
dry_run = 1;
return argc;
@@ -1159,6 +1165,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
OPT_SET_INT(0, "porcelain", &status_format,
N_("machine-readable output"),
STATUS_FORMAT_PORCELAIN),
+ OPT_SET_INT(0, "long", &status_format,
+ N_("show status in long format (default)"),
+ STATUS_FORMAT_LONG),
OPT_BOOLEAN('z', "null", &s.null_termination,
N_("terminate entries with NUL")),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
@@ -1186,8 +1195,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
builtin_status_usage, 0);
finalize_colopts(&s.colopts, -1);
- if (s.null_termination && status_format == STATUS_FORMAT_LONG)
- status_format = STATUS_FORMAT_PORCELAIN;
+ if (s.null_termination) {
+ if (status_format == STATUS_FORMAT_NONE)
+ status_format = STATUS_FORMAT_PORCELAIN;
+ else if (status_format == STATUS_FORMAT_LONG)
+ die(_("--long and -z are incompatible"));
+ }
handle_untracked_files_arg(&s);
if (show_ignored_in_status)
@@ -1216,6 +1229,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(&s);
break;
+ case STATUS_FORMAT_NONE:
case STATUS_FORMAT_LONG:
s.verbose = verbose;
s.ignore_submodule_arg = ignore_submodule_arg;
@@ -1251,7 +1265,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
strbuf_addstr(&format, "\n Author: ");
strbuf_addbuf_percentquote(&format, &author_ident);
}
- if (!user_ident_sufficiently_given()) {
+ if (!committer_ident_sufficiently_given()) {
strbuf_addstr(&format, "\n Committer: ");
strbuf_addbuf_percentquote(&format, &committer_ident);
if (advice_implicit_identity) {
@@ -1306,6 +1320,8 @@ static int git_commit_config(const char *k, const char *v, void *cb)
include_status = git_config_bool(k, v);
return 0;
}
+ if (!strcmp(k, "commit.cleanup"))
+ return git_config_string(&cleanup_arg, k, v);
status = git_gpg_config(k, v, NULL);
if (status)
@@ -1386,6 +1402,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")),
OPT_SET_INT(0, "porcelain", &status_format,
N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
+ OPT_SET_INT(0, "long", &status_format,
+ N_("show status in long format (default)"),
+ STATUS_FORMAT_LONG),
OPT_BOOLEAN('z', "null", &s.null_termination,
N_("terminate entries with NUL")),
OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
diff --git a/builtin/config.c b/builtin/config.c
index 505bbc7ddd..33c9bf9d84 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -15,7 +15,6 @@ static int show_keys;
static int use_key_regexp;
static int do_all;
static int do_not_match;
-static int seen;
static char delim = '=';
static char key_delim = ' ';
static char term = '\n';
@@ -95,12 +94,19 @@ static int show_all_config(const char *key_, const char *value_, void *cb)
return 0;
}
-static int show_config(const char *key_, const char *value_, void *cb)
+struct strbuf_list {
+ struct strbuf *items;
+ int nr;
+ int alloc;
+};
+
+static int collect_config(const char *key_, const char *value_, void *cb)
{
+ struct strbuf_list *values = cb;
+ struct strbuf *buf;
char value[256];
const char *vptr = value;
int must_free_vptr = 0;
- int dup_error = 0;
int must_print_delim = 0;
if (!use_key_regexp && strcmp(key_, key))
@@ -111,12 +117,14 @@ static int show_config(const char *key_, const char *value_, void *cb)
(do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
return 0;
+ ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+ buf = &values->items[values->nr++];
+ strbuf_init(buf, 0);
+
if (show_keys) {
- printf("%s", key_);
+ strbuf_addstr(buf, key_);
must_print_delim = 1;
}
- if (seen && !do_all)
- dup_error = 1;
if (types == TYPE_INT)
sprintf(value, "%d", git_config_int(key_, value_?value_:""));
else if (types == TYPE_BOOL)
@@ -139,16 +147,12 @@ static int show_config(const char *key_, const char *value_, void *cb)
vptr = "";
must_print_delim = 0;
}
- seen++;
- if (dup_error) {
- error("More than one value for the key %s: %s",
- key_, vptr);
- }
- else {
- if (must_print_delim)
- printf("%c", key_delim);
- printf("%s%c", vptr, term);
- }
+
+ if (must_print_delim)
+ strbuf_addch(buf, key_delim);
+ strbuf_addstr(buf, vptr);
+ strbuf_addch(buf, term);
+
if (must_free_vptr)
/* If vptr must be freed, it's a pointer to a
* dynamically allocated buffer, it's safe to cast to
@@ -162,19 +166,8 @@ static int show_config(const char *key_, const char *value_, void *cb)
static int get_value(const char *key_, const char *regex_)
{
int ret = CONFIG_GENERIC_ERROR;
- char *global = NULL, *xdg = NULL, *repo_config = NULL;
- const char *system_wide = NULL, *local;
- struct config_include_data inc = CONFIG_INCLUDE_INIT;
- config_fn_t fn;
- void *data;
-
- local = given_config_file;
- if (!local) {
- local = repo_config = git_pathdup("config");
- if (git_config_system())
- system_wide = git_etc_gitconfig();
- home_config_paths(&global, &xdg, "config");
- }
+ struct strbuf_list values = {NULL};
+ int i;
if (use_key_regexp) {
char *tl;
@@ -196,7 +189,8 @@ static int get_value(const char *key_, const char *regex_)
key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
if (regcomp(key_regexp, key, REG_EXTENDED)) {
fprintf(stderr, "Invalid key pattern: %s\n", key_);
- free(key);
+ free(key_regexp);
+ key_regexp = NULL;
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
@@ -216,53 +210,37 @@ static int get_value(const char *key_, const char *regex_)
regexp = (regex_t*)xmalloc(sizeof(regex_t));
if (regcomp(regexp, regex_, REG_EXTENDED)) {
fprintf(stderr, "Invalid pattern: %s\n", regex_);
+ free(regexp);
+ regexp = NULL;
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
}
- fn = show_config;
- data = NULL;
- if (respect_includes) {
- inc.fn = fn;
- inc.data = data;
- fn = git_config_include;
- data = &inc;
- }
-
- if (do_all && system_wide)
- git_config_from_file(fn, system_wide, data);
- if (do_all && xdg)
- git_config_from_file(fn, xdg, data);
- if (do_all && global)
- git_config_from_file(fn, global, data);
- if (do_all)
- git_config_from_file(fn, local, data);
- git_config_from_parameters(fn, data);
- if (!do_all && !seen)
- git_config_from_file(fn, local, data);
- if (!do_all && !seen && global)
- git_config_from_file(fn, global, data);
- if (!do_all && !seen && xdg)
- git_config_from_file(fn, xdg, data);
- if (!do_all && !seen && system_wide)
- git_config_from_file(fn, system_wide, data);
+ git_config_with_options(collect_config, &values,
+ given_config_file, respect_includes);
+
+ ret = !values.nr;
+ for (i = 0; i < values.nr; i++) {
+ struct strbuf *buf = values.items + i;
+ if (do_all || i == values.nr - 1)
+ fwrite(buf->buf, 1, buf->len, stdout);
+ strbuf_release(buf);
+ }
+ free(values.items);
+
+free_strings:
free(key);
+ if (key_regexp) {
+ regfree(key_regexp);
+ free(key_regexp);
+ }
if (regexp) {
regfree(regexp);
free(regexp);
}
- if (do_all)
- ret = !seen;
- else
- ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
-
-free_strings:
- free(repo_config);
- free(global);
- free(xdg);
return ret;
}
diff --git a/builtin/describe.c b/builtin/describe.c
index 9fe11ed9de..04c185b1fb 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -144,7 +144,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
if (!all && !might_be_tag)
return 0;
- if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) {
+ if (!peel_ref(path, peeled)) {
is_tag = !!hashcmp(sha1, peeled);
} else {
hashcpy(peeled, sha1);
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 2eb32bd9da..1c737f7921 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -41,9 +41,13 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
if (rev.pending.nr != 1 ||
rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
usage(diff_cache_usage);
- if (!cached)
+ if (!cached) {
setup_work_tree();
- if (read_cache() < 0) {
+ if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
+ perror("read_cache_preload");
+ return -1;
+ }
+ } else if (read_cache() < 0) {
perror("read_cache");
return -1;
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 9650be2c50..8c2af6cb43 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -130,8 +130,6 @@ static int builtin_diff_index(struct rev_info *revs,
usage(builtin_diff_usage);
argv++; argc--;
}
- if (!cached)
- setup_work_tree();
/*
* Make sure there is one revision (i.e. pending object),
* and there is no revision filtering parameters.
@@ -140,8 +138,14 @@ static int builtin_diff_index(struct rev_info *revs,
revs->max_count != -1 || revs->min_age != -1 ||
revs->max_age != -1)
usage(builtin_diff_usage);
- if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
- perror("read_cache_preload");
+ if (!cached) {
+ setup_work_tree();
+ if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+ perror("read_cache_preload");
+ return -1;
+ }
+ } else if (read_cache() < 0) {
+ perror("read_cache");
return -1;
}
return run_diff_index(revs, cached);
@@ -418,19 +422,3 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
refresh_index_quietly();
return result;
}
-
-void setup_diff_pager(struct diff_options *opt)
-{
- /*
- * If the user asked for our exit code, then either they want --quiet
- * or --exit-code. We should definitely not bother with a pager in the
- * former case, as we will generate no output. Since we still properly
- * report our exit code even when a pager is run, we _could_ run a
- * pager with --exit-code. But since we have not done so historically,
- * and because it is easy to find people oneline advising "git diff
- * --exit-code" in hooks and other scripts, we do not do so.
- */
- if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
- check_pager_config("diff") != 0)
- setup_pager();
-}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 12220ad8da..77dffd1ce3 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -474,18 +474,21 @@ static void handle_tag(const char *name, struct tag *tag)
(int)message_size, (int)message_size, message ? message : "");
}
-static void get_tags_and_duplicates(struct object_array *pending,
+static void get_tags_and_duplicates(struct rev_cmdline_info *info,
struct string_list *extra_refs)
{
struct tag *tag;
int i;
- for (i = 0; i < pending->nr; i++) {
- struct object_array_entry *e = pending->objects + i;
+ for (i = 0; i < info->nr; i++) {
+ struct rev_cmdline_entry *e = info->rev + i;
unsigned char sha1[20];
- struct commit *commit = commit;
+ struct commit *commit;
char *full_name;
+ if (e->flags & UNINTERESTING)
+ continue;
+
if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
continue;
@@ -523,10 +526,14 @@ static void get_tags_and_duplicates(struct object_array *pending,
typename(e->item->type));
continue;
}
- if (commit->util)
- /* more than one name for the same object */
+
+ /*
+ * This ref will not be updated through a commit, lets make
+ * sure it gets properly updated eventually.
+ */
+ if (commit->util || commit->object.flags & SHOWN)
string_list_append(extra_refs, full_name)->util = commit;
- else
+ if (!commit->util)
commit->util = full_name;
}
}
@@ -614,6 +621,10 @@ static void import_marks(char *input_file)
if (object->flags & SHOWN)
error("Object %s already has a mark", sha1_to_hex(sha1));
+ if (object->type != OBJ_COMMIT)
+ /* only commits */
+ continue;
+
mark_object(object, mark);
if (last_idnum < mark)
last_idnum = mark;
@@ -677,7 +688,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (import_filename && revs.prune_data.nr)
full_tree = 1;
- get_tags_and_duplicates(&revs.pending, &extra_refs);
+ get_tags_and_duplicates(&revs.cmdline, &extra_refs);
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index e6443986b8..940ae35dc2 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -1,895 +1,12 @@
#include "builtin.h"
-#include "refs.h"
#include "pkt-line.h"
-#include "commit.h"
-#include "tag.h"
-#include "exec_cmd.h"
-#include "pack.h"
-#include "sideband.h"
#include "fetch-pack.h"
-#include "remote.h"
-#include "run-command.h"
-#include "transport.h"
-#include "version.h"
-
-static int transfer_unpack_limit = -1;
-static int fetch_unpack_limit = -1;
-static int unpack_limit = 100;
-static int prefer_ofs_delta = 1;
-static int no_done;
-static int fetch_fsck_objects = -1;
-static int transfer_fsck_objects = -1;
-static int agent_supported;
-static struct fetch_pack_args args = {
- /* .uploadpack = */ "git-upload-pack",
-};
static const char fetch_pack_usage[] =
"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
-#define COMPLETE (1U << 0)
-#define COMMON (1U << 1)
-#define COMMON_REF (1U << 2)
-#define SEEN (1U << 3)
-#define POPPED (1U << 4)
-
-static int marked;
-
-/*
- * After sending this many "have"s if we do not get any new ACK , we
- * give up traversing our history.
- */
-#define MAX_IN_VAIN 256
-
-static struct commit_list *rev_list;
-static int non_common_revs, multi_ack, use_sideband;
-
-static void rev_list_push(struct commit *commit, int mark)
-{
- if (!(commit->object.flags & mark)) {
- commit->object.flags |= mark;
-
- if (!(commit->object.parsed))
- if (parse_commit(commit))
- return;
-
- commit_list_insert_by_date(commit, &rev_list);
-
- if (!(commit->object.flags & COMMON))
- non_common_revs++;
- }
-}
-
-static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
- struct object *o = deref_tag(parse_object(sha1), refname, 0);
-
- if (o && o->type == OBJ_COMMIT)
- rev_list_push((struct commit *)o, SEEN);
-
- return 0;
-}
-
-static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
- struct object *o = deref_tag(parse_object(sha1), refname, 0);
-
- if (o && o->type == OBJ_COMMIT)
- clear_commit_marks((struct commit *)o,
- COMMON | COMMON_REF | SEEN | POPPED);
- return 0;
-}
-
-/*
- This function marks a rev and its ancestors as common.
- In some cases, it is desirable to mark only the ancestors (for example
- when only the server does not yet know that they are common).
-*/
-
-static void mark_common(struct commit *commit,
- int ancestors_only, int dont_parse)
-{
- if (commit != NULL && !(commit->object.flags & COMMON)) {
- struct object *o = (struct object *)commit;
-
- if (!ancestors_only)
- o->flags |= COMMON;
-
- if (!(o->flags & SEEN))
- rev_list_push(commit, SEEN);
- else {
- struct commit_list *parents;
-
- if (!ancestors_only && !(o->flags & POPPED))
- non_common_revs--;
- if (!o->parsed && !dont_parse)
- if (parse_commit(commit))
- return;
-
- for (parents = commit->parents;
- parents;
- parents = parents->next)
- mark_common(parents->item, 0, dont_parse);
- }
- }
-}
-
-/*
- Get the next rev to send, ignoring the common.
-*/
-
-static const unsigned char *get_rev(void)
-{
- struct commit *commit = NULL;
-
- while (commit == NULL) {
- unsigned int mark;
- struct commit_list *parents;
-
- if (rev_list == NULL || non_common_revs == 0)
- return NULL;
-
- commit = rev_list->item;
- if (!commit->object.parsed)
- parse_commit(commit);
- parents = commit->parents;
-
- commit->object.flags |= POPPED;
- if (!(commit->object.flags & COMMON))
- non_common_revs--;
-
- if (commit->object.flags & COMMON) {
- /* do not send "have", and ignore ancestors */
- commit = NULL;
- mark = COMMON | SEEN;
- } else if (commit->object.flags & COMMON_REF)
- /* send "have", and ignore ancestors */
- mark = COMMON | SEEN;
- else
- /* send "have", also for its ancestors */
- mark = SEEN;
-
- while (parents) {
- if (!(parents->item->object.flags & SEEN))
- rev_list_push(parents->item, mark);
- if (mark & COMMON)
- mark_common(parents->item, 1, 0);
- parents = parents->next;
- }
-
- rev_list = rev_list->next;
- }
-
- return commit->object.sha1;
-}
-
-enum ack_type {
- NAK = 0,
- ACK,
- ACK_continue,
- ACK_common,
- ACK_ready
-};
-
-static void consume_shallow_list(int fd)
-{
- if (args.stateless_rpc && args.depth > 0) {
- /* If we sent a depth we will get back "duplicate"
- * shallow and unshallow commands every time there
- * is a block of have lines exchanged.
- */
- char line[1000];
- while (packet_read_line(fd, line, sizeof(line))) {
- if (!prefixcmp(line, "shallow "))
- continue;
- if (!prefixcmp(line, "unshallow "))
- continue;
- die("git fetch-pack: expected shallow list");
- }
- }
-}
-
-struct write_shallow_data {
- struct strbuf *out;
- int use_pack_protocol;
- int count;
-};
-
-static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
-{
- struct write_shallow_data *data = cb_data;
- const char *hex = sha1_to_hex(graft->sha1);
- data->count++;
- if (data->use_pack_protocol)
- packet_buf_write(data->out, "shallow %s", hex);
- else {
- strbuf_addstr(data->out, hex);
- strbuf_addch(data->out, '\n');
- }
- return 0;
-}
-
-static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
-{
- struct write_shallow_data data;
- data.out = out;
- data.use_pack_protocol = use_pack_protocol;
- data.count = 0;
- for_each_commit_graft(write_one_shallow, &data);
- return data.count;
-}
-
-static enum ack_type get_ack(int fd, unsigned char *result_sha1)
-{
- static char line[1000];
- int len = packet_read_line(fd, line, sizeof(line));
-
- if (!len)
- die("git fetch-pack: expected ACK/NAK, got EOF");
- if (line[len-1] == '\n')
- line[--len] = 0;
- if (!strcmp(line, "NAK"))
- return NAK;
- if (!prefixcmp(line, "ACK ")) {
- if (!get_sha1_hex(line+4, result_sha1)) {
- if (strstr(line+45, "continue"))
- return ACK_continue;
- if (strstr(line+45, "common"))
- return ACK_common;
- if (strstr(line+45, "ready"))
- return ACK_ready;
- return ACK;
- }
- }
- die("git fetch_pack: expected ACK/NAK, got '%s'", line);
-}
-
-static void send_request(int fd, struct strbuf *buf)
-{
- if (args.stateless_rpc) {
- send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
- packet_flush(fd);
- } else
- safe_write(fd, buf->buf, buf->len);
-}
-
-static void insert_one_alternate_ref(const struct ref *ref, void *unused)
-{
- rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
-}
-
-#define INITIAL_FLUSH 16
-#define PIPESAFE_FLUSH 32
-#define LARGE_FLUSH 1024
-
-static int next_flush(int count)
-{
- int flush_limit = args.stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH;
-
- if (count < flush_limit)
- count <<= 1;
- else
- count += flush_limit;
- return count;
-}
-
-static int find_common(int fd[2], unsigned char *result_sha1,
- struct ref *refs)
-{
- int fetching;
- int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
- const unsigned char *sha1;
- unsigned in_vain = 0;
- int got_continue = 0;
- int got_ready = 0;
- struct strbuf req_buf = STRBUF_INIT;
- size_t state_len = 0;
-
- if (args.stateless_rpc && multi_ack == 1)
- die("--stateless-rpc requires multi_ack_detailed");
- if (marked)
- for_each_ref(clear_marks, NULL);
- marked = 1;
-
- for_each_ref(rev_list_insert_ref, NULL);
- for_each_alternate_ref(insert_one_alternate_ref, NULL);
-
- fetching = 0;
- for ( ; refs ; refs = refs->next) {
- unsigned char *remote = refs->old_sha1;
- const char *remote_hex;
- struct object *o;
-
- /*
- * If that object is complete (i.e. it is an ancestor of a
- * local ref), we tell them we have it but do not have to
- * tell them about its ancestors, which they already know
- * about.
- *
- * We use lookup_object here because we are only
- * interested in the case we *know* the object is
- * reachable and we have already scanned it.
- */
- if (((o = lookup_object(remote)) != NULL) &&
- (o->flags & COMPLETE)) {
- continue;
- }
-
- remote_hex = sha1_to_hex(remote);
- if (!fetching) {
- struct strbuf c = STRBUF_INIT;
- if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed");
- if (multi_ack == 1) strbuf_addstr(&c, " multi_ack");
- if (no_done) strbuf_addstr(&c, " no-done");
- if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k");
- if (use_sideband == 1) strbuf_addstr(&c, " side-band");
- if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack");
- if (args.no_progress) strbuf_addstr(&c, " no-progress");
- if (args.include_tag) strbuf_addstr(&c, " include-tag");
- if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta");
- if (agent_supported) strbuf_addf(&c, " agent=%s",
- git_user_agent_sanitized());
- packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
- strbuf_release(&c);
- } else
- packet_buf_write(&req_buf, "want %s\n", remote_hex);
- fetching++;
- }
-
- if (!fetching) {
- strbuf_release(&req_buf);
- packet_flush(fd[1]);
- return 1;
- }
-
- if (is_repository_shallow())
- write_shallow_commits(&req_buf, 1);
- if (args.depth > 0)
- packet_buf_write(&req_buf, "deepen %d", args.depth);
- packet_buf_flush(&req_buf);
- state_len = req_buf.len;
-
- if (args.depth > 0) {
- char line[1024];
- unsigned char sha1[20];
-
- send_request(fd[1], &req_buf);
- while (packet_read_line(fd[0], line, sizeof(line))) {
- if (!prefixcmp(line, "shallow ")) {
- if (get_sha1_hex(line + 8, sha1))
- die("invalid shallow line: %s", line);
- register_shallow(sha1);
- continue;
- }
- if (!prefixcmp(line, "unshallow ")) {
- if (get_sha1_hex(line + 10, sha1))
- die("invalid unshallow line: %s", line);
- if (!lookup_object(sha1))
- die("object not found: %s", line);
- /* make sure that it is parsed as shallow */
- if (!parse_object(sha1))
- die("error in object: %s", line);
- if (unregister_shallow(sha1))
- die("no shallow found: %s", line);
- continue;
- }
- die("expected shallow/unshallow, got %s", line);
- }
- } else if (!args.stateless_rpc)
- send_request(fd[1], &req_buf);
-
- if (!args.stateless_rpc) {
- /* If we aren't using the stateless-rpc interface
- * we don't need to retain the headers.
- */
- strbuf_setlen(&req_buf, 0);
- state_len = 0;
- }
-
- flushes = 0;
- retval = -1;
- while ((sha1 = get_rev())) {
- packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1));
- if (args.verbose)
- fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
- in_vain++;
- if (flush_at <= ++count) {
- int ack;
-
- packet_buf_flush(&req_buf);
- send_request(fd[1], &req_buf);
- strbuf_setlen(&req_buf, state_len);
- flushes++;
- flush_at = next_flush(count);
-
- /*
- * We keep one window "ahead" of the other side, and
- * will wait for an ACK only on the next one
- */
- if (!args.stateless_rpc && count == INITIAL_FLUSH)
- continue;
-
- consume_shallow_list(fd[0]);
- do {
- ack = get_ack(fd[0], result_sha1);
- if (args.verbose && ack)
- fprintf(stderr, "got ack %d %s\n", ack,
- sha1_to_hex(result_sha1));
- switch (ack) {
- case ACK:
- flushes = 0;
- multi_ack = 0;
- retval = 0;
- goto done;
- case ACK_common:
- case ACK_ready:
- case ACK_continue: {
- struct commit *commit =
- lookup_commit(result_sha1);
- if (!commit)
- die("invalid commit %s", sha1_to_hex(result_sha1));
- if (args.stateless_rpc
- && ack == ACK_common
- && !(commit->object.flags & COMMON)) {
- /* We need to replay the have for this object
- * on the next RPC request so the peer knows
- * it is in common with us.
- */
- const char *hex = sha1_to_hex(result_sha1);
- packet_buf_write(&req_buf, "have %s\n", hex);
- state_len = req_buf.len;
- }
- mark_common(commit, 0, 1);
- retval = 0;
- in_vain = 0;
- got_continue = 1;
- if (ack == ACK_ready) {
- rev_list = NULL;
- got_ready = 1;
- }
- break;
- }
- }
- } while (ack);
- flushes--;
- if (got_continue && MAX_IN_VAIN < in_vain) {
- if (args.verbose)
- fprintf(stderr, "giving up\n");
- break; /* give up */
- }
- }
- }
-done:
- if (!got_ready || !no_done) {
- packet_buf_write(&req_buf, "done\n");
- send_request(fd[1], &req_buf);
- }
- if (args.verbose)
- fprintf(stderr, "done\n");
- if (retval != 0) {
- multi_ack = 0;
- flushes++;
- }
- strbuf_release(&req_buf);
-
- consume_shallow_list(fd[0]);
- while (flushes || multi_ack) {
- int ack = get_ack(fd[0], result_sha1);
- if (ack) {
- if (args.verbose)
- fprintf(stderr, "got ack (%d) %s\n", ack,
- sha1_to_hex(result_sha1));
- if (ack == ACK)
- return 0;
- multi_ack = 1;
- continue;
- }
- flushes--;
- }
- /* it is no error to fetch into a completely empty repo */
- return count ? retval : 0;
-}
-
-static struct commit_list *complete;
-
-static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
- struct object *o = parse_object(sha1);
-
- while (o && o->type == OBJ_TAG) {
- struct tag *t = (struct tag *) o;
- if (!t->tagged)
- break; /* broken repository */
- o->flags |= COMPLETE;
- o = parse_object(t->tagged->sha1);
- }
- if (o && o->type == OBJ_COMMIT) {
- struct commit *commit = (struct commit *)o;
- if (!(commit->object.flags & COMPLETE)) {
- commit->object.flags |= COMPLETE;
- commit_list_insert_by_date(commit, &complete);
- }
- }
- return 0;
-}
-
-static void mark_recent_complete_commits(unsigned long cutoff)
-{
- while (complete && cutoff <= complete->item->date) {
- if (args.verbose)
- fprintf(stderr, "Marking %s as complete\n",
- sha1_to_hex(complete->item->object.sha1));
- pop_most_recent_commit(&complete, COMPLETE);
- }
-}
-
-static int non_matching_ref(struct string_list_item *item, void *unused)
-{
- if (item->util) {
- item->util = NULL;
- return 0;
- }
- else
- return 1;
-}
-
-static void filter_refs(struct ref **refs, struct string_list *sought)
-{
- struct ref *newlist = NULL;
- struct ref **newtail = &newlist;
- struct ref *ref, *next;
- int sought_pos;
-
- sought_pos = 0;
- for (ref = *refs; ref; ref = next) {
- int keep = 0;
- next = ref->next;
- if (!memcmp(ref->name, "refs/", 5) &&
- check_refname_format(ref->name + 5, 0))
- ; /* trash */
- else {
- while (sought_pos < sought->nr) {
- int cmp = strcmp(ref->name, sought->items[sought_pos].string);
- if (cmp < 0)
- break; /* definitely do not have it */
- else if (cmp == 0) {
- keep = 1; /* definitely have it */
- sought->items[sought_pos++].util = "matched";
- break;
- }
- else
- sought_pos++; /* might have it; keep looking */
- }
- }
-
- if (! keep && args.fetch_all &&
- (!args.depth || prefixcmp(ref->name, "refs/tags/")))
- keep = 1;
-
- if (keep) {
- *newtail = ref;
- ref->next = NULL;
- newtail = &ref->next;
- } else {
- free(ref);
- }
- }
-
- filter_string_list(sought, 0, non_matching_ref, NULL);
- *refs = newlist;
-}
-
-static void mark_alternate_complete(const struct ref *ref, void *unused)
-{
- mark_complete(NULL, ref->old_sha1, 0, NULL);
-}
-
-static int everything_local(struct ref **refs, struct string_list *sought)
-{
- struct ref *ref;
- int retval;
- unsigned long cutoff = 0;
-
- save_commit_buffer = 0;
-
- for (ref = *refs; ref; ref = ref->next) {
- struct object *o;
-
- o = parse_object(ref->old_sha1);
- if (!o)
- continue;
-
- /* We already have it -- which may mean that we were
- * in sync with the other side at some time after
- * that (it is OK if we guess wrong here).
- */
- if (o->type == OBJ_COMMIT) {
- struct commit *commit = (struct commit *)o;
- if (!cutoff || cutoff < commit->date)
- cutoff = commit->date;
- }
- }
-
- if (!args.depth) {
- for_each_ref(mark_complete, NULL);
- for_each_alternate_ref(mark_alternate_complete, NULL);
- if (cutoff)
- mark_recent_complete_commits(cutoff);
- }
-
- /*
- * Mark all complete remote refs as common refs.
- * Don't mark them common yet; the server has to be told so first.
- */
- for (ref = *refs; ref; ref = ref->next) {
- struct object *o = deref_tag(lookup_object(ref->old_sha1),
- NULL, 0);
-
- if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
- continue;
-
- if (!(o->flags & SEEN)) {
- rev_list_push((struct commit *)o, COMMON_REF | SEEN);
-
- mark_common((struct commit *)o, 1, 1);
- }
- }
-
- filter_refs(refs, sought);
-
- for (retval = 1, ref = *refs; ref ; ref = ref->next) {
- const unsigned char *remote = ref->old_sha1;
- unsigned char local[20];
- struct object *o;
-
- o = lookup_object(remote);
- if (!o || !(o->flags & COMPLETE)) {
- retval = 0;
- if (!args.verbose)
- continue;
- fprintf(stderr,
- "want %s (%s)\n", sha1_to_hex(remote),
- ref->name);
- continue;
- }
-
- hashcpy(ref->new_sha1, local);
- if (!args.verbose)
- continue;
- fprintf(stderr,
- "already have %s (%s)\n", sha1_to_hex(remote),
- ref->name);
- }
- return retval;
-}
-
-static int sideband_demux(int in, int out, void *data)
-{
- int *xd = data;
-
- int ret = recv_sideband("fetch-pack", xd[0], out);
- close(out);
- return ret;
-}
-
-static int get_pack(int xd[2], char **pack_lockfile)
-{
- struct async demux;
- const char *argv[20];
- char keep_arg[256];
- char hdr_arg[256];
- const char **av;
- int do_keep = args.keep_pack;
- struct child_process cmd;
-
- memset(&demux, 0, sizeof(demux));
- if (use_sideband) {
- /* xd[] is talking with upload-pack; subprocess reads from
- * xd[0], spits out band#2 to stderr, and feeds us band#1
- * through demux->out.
- */
- demux.proc = sideband_demux;
- demux.data = xd;
- demux.out = -1;
- if (start_async(&demux))
- die("fetch-pack: unable to fork off sideband"
- " demultiplexer");
- }
- else
- demux.out = xd[0];
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.argv = argv;
- av = argv;
- *hdr_arg = 0;
- if (!args.keep_pack && unpack_limit) {
- struct pack_header header;
-
- if (read_pack_header(demux.out, &header))
- die("protocol error: bad pack header");
- snprintf(hdr_arg, sizeof(hdr_arg),
- "--pack_header=%"PRIu32",%"PRIu32,
- ntohl(header.hdr_version), ntohl(header.hdr_entries));
- if (ntohl(header.hdr_entries) < unpack_limit)
- do_keep = 0;
- else
- do_keep = 1;
- }
-
- if (do_keep) {
- if (pack_lockfile)
- cmd.out = -1;
- *av++ = "index-pack";
- *av++ = "--stdin";
- if (!args.quiet && !args.no_progress)
- *av++ = "-v";
- if (args.use_thin_pack)
- *av++ = "--fix-thin";
- if (args.lock_pack || unpack_limit) {
- int s = sprintf(keep_arg,
- "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid());
- if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
- strcpy(keep_arg + s, "localhost");
- *av++ = keep_arg;
- }
- }
- else {
- *av++ = "unpack-objects";
- if (args.quiet || args.no_progress)
- *av++ = "-q";
- }
- if (*hdr_arg)
- *av++ = hdr_arg;
- if (fetch_fsck_objects >= 0
- ? fetch_fsck_objects
- : transfer_fsck_objects >= 0
- ? transfer_fsck_objects
- : 0)
- *av++ = "--strict";
- *av++ = NULL;
-
- cmd.in = demux.out;
- cmd.git_cmd = 1;
- if (start_command(&cmd))
- die("fetch-pack: unable to fork off %s", argv[0]);
- if (do_keep && pack_lockfile) {
- *pack_lockfile = index_pack_lockfile(cmd.out);
- close(cmd.out);
- }
-
- if (finish_command(&cmd))
- die("%s failed", argv[0]);
- if (use_sideband && finish_async(&demux))
- die("error in sideband demultiplexer");
- return 0;
-}
-
-static struct ref *do_fetch_pack(int fd[2],
- const struct ref *orig_ref,
- struct string_list *sought,
- char **pack_lockfile)
-{
- struct ref *ref = copy_ref_list(orig_ref);
- unsigned char sha1[20];
- const char *agent_feature;
- int agent_len;
-
- sort_ref_list(&ref, ref_compare_name);
-
- if (is_repository_shallow() && !server_supports("shallow"))
- die("Server does not support shallow clients");
- if (server_supports("multi_ack_detailed")) {
- if (args.verbose)
- fprintf(stderr, "Server supports multi_ack_detailed\n");
- multi_ack = 2;
- if (server_supports("no-done")) {
- if (args.verbose)
- fprintf(stderr, "Server supports no-done\n");
- if (args.stateless_rpc)
- no_done = 1;
- }
- }
- else if (server_supports("multi_ack")) {
- if (args.verbose)
- fprintf(stderr, "Server supports multi_ack\n");
- multi_ack = 1;
- }
- if (server_supports("side-band-64k")) {
- if (args.verbose)
- fprintf(stderr, "Server supports side-band-64k\n");
- use_sideband = 2;
- }
- else if (server_supports("side-band")) {
- if (args.verbose)
- fprintf(stderr, "Server supports side-band\n");
- use_sideband = 1;
- }
- if (!server_supports("thin-pack"))
- args.use_thin_pack = 0;
- if (!server_supports("no-progress"))
- args.no_progress = 0;
- if (!server_supports("include-tag"))
- args.include_tag = 0;
- if (server_supports("ofs-delta")) {
- if (args.verbose)
- fprintf(stderr, "Server supports ofs-delta\n");
- } else
- prefer_ofs_delta = 0;
-
- if ((agent_feature = server_feature_value("agent", &agent_len))) {
- agent_supported = 1;
- if (args.verbose && agent_len)
- fprintf(stderr, "Server version is %.*s\n",
- agent_len, agent_feature);
- }
-
- if (everything_local(&ref, sought)) {
- packet_flush(fd[1]);
- goto all_done;
- }
- if (find_common(fd, sha1, ref) < 0)
- if (!args.keep_pack)
- /* When cloning, it is not unusual to have
- * no common commit.
- */
- warning("no common commits");
-
- if (args.stateless_rpc)
- packet_flush(fd[1]);
- if (get_pack(fd, pack_lockfile))
- die("git fetch-pack: fetch failed.");
-
- all_done:
- return ref;
-}
-
-static int fetch_pack_config(const char *var, const char *value, void *cb)
-{
- if (strcmp(var, "fetch.unpacklimit") == 0) {
- fetch_unpack_limit = git_config_int(var, value);
- return 0;
- }
-
- if (strcmp(var, "transfer.unpacklimit") == 0) {
- transfer_unpack_limit = git_config_int(var, value);
- return 0;
- }
-
- if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
- prefer_ofs_delta = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "fetch.fsckobjects")) {
- fetch_fsck_objects = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "transfer.fsckobjects")) {
- transfer_fsck_objects = git_config_bool(var, value);
- return 0;
- }
-
- return git_default_config(var, value, cb);
-}
-
-static struct lock_file lock;
-
-static void fetch_pack_setup(void)
-{
- static int did_setup;
- if (did_setup)
- return;
- git_config(fetch_pack_config, NULL);
- if (0 <= transfer_unpack_limit)
- unpack_limit = transfer_unpack_limit;
- else if (0 <= fetch_unpack_limit)
- unpack_limit = fetch_unpack_limit;
- did_setup = 1;
-}
-
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
{
int i, ret;
@@ -900,9 +17,13 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
char *pack_lockfile = NULL;
char **pack_lockfile_ptr = NULL;
struct child_process *conn;
+ struct fetch_pack_args args;
packet_trace_identity("fetch-pack");
+ memset(&args, 0, sizeof(args));
+ args.uploadpack = "git-upload-pack";
+
for (i = 1; i < argc && *argv[i] == '-'; i++) {
const char *arg = argv[i];
@@ -1038,66 +159,3 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
return ret;
}
-
-struct ref *fetch_pack(struct fetch_pack_args *my_args,
- int fd[], struct child_process *conn,
- const struct ref *ref,
- const char *dest,
- struct string_list *sought,
- char **pack_lockfile)
-{
- struct stat st;
- struct ref *ref_cpy;
-
- fetch_pack_setup();
- if (&args != my_args)
- memcpy(&args, my_args, sizeof(args));
- if (args.depth > 0) {
- if (stat(git_path("shallow"), &st))
- st.st_mtime = 0;
- }
-
- if (sought->nr) {
- sort_string_list(sought);
- string_list_remove_duplicates(sought, 0);
- }
-
- if (!ref) {
- packet_flush(fd[1]);
- die("no matching remote head");
- }
- ref_cpy = do_fetch_pack(fd, ref, sought, pack_lockfile);
-
- if (args.depth > 0) {
- struct cache_time mtime;
- struct strbuf sb = STRBUF_INIT;
- char *shallow = git_path("shallow");
- int fd;
-
- mtime.sec = st.st_mtime;
- mtime.nsec = ST_MTIME_NSEC(st);
- if (stat(shallow, &st)) {
- if (mtime.sec)
- die("shallow file was removed during fetch");
- } else if (st.st_mtime != mtime.sec
-#ifdef USE_NSEC
- || ST_MTIME_NSEC(st) != mtime.nsec
-#endif
- )
- die("shallow file was changed during fetch");
-
- fd = hold_lock_file_for_update(&lock, shallow,
- LOCK_DIE_ON_ERROR);
- if (!write_shallow_commits(&sb, 0)
- || write_in_full(fd, sb.buf, sb.len) != sb.len) {
- unlink_or_warn(shallow);
- rollback_lock_file(&lock);
- } else {
- commit_lock_file(&lock);
- }
- strbuf_release(&sb);
- }
-
- reprepare_packed_git();
- return ref_cpy;
-}
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index e2e27b2c40..d9af43c257 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -232,8 +232,9 @@ static void record_person(int which, struct string_list *people,
{
char *name_buf, *name, *name_end;
struct string_list_item *elem;
- const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
+ const char *field;
+ field = (which == 'a') ? "\nauthor " : "\ncommitter ";
name = strstr(commit->buffer, field);
if (!name)
return;
@@ -323,7 +324,8 @@ static void add_people_info(struct strbuf *out,
static void shortlog(const char *name,
struct origin_data *origin_data,
struct commit *head,
- struct rev_info *rev, int limit,
+ struct rev_info *rev,
+ struct fmt_merge_msg_opts *opts,
struct strbuf *out)
{
int i, count = 0;
@@ -335,6 +337,7 @@ static void shortlog(const char *name,
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
struct strbuf sb = STRBUF_INIT;
const unsigned char *sha1 = origin_data->sha1;
+ int limit = opts->shortlog_len;
branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
if (!branch || branch->type != OBJ_COMMIT)
@@ -351,13 +354,15 @@ static void shortlog(const char *name,
if (commit->parents && commit->parents->next) {
/* do not list a merge but count committer */
- record_person('c', &committers, commit);
+ if (opts->credit_people)
+ record_person('c', &committers, commit);
continue;
}
- if (!count)
+ if (!count && opts->credit_people)
/* the 'tip' committer */
record_person('c', &committers, commit);
- record_person('a', &authors, commit);
+ if (opts->credit_people)
+ record_person('a', &authors, commit);
count++;
if (subjects.nr > limit)
continue;
@@ -372,7 +377,8 @@ static void shortlog(const char *name,
string_list_append(&subjects, strbuf_detach(&sb, NULL));
}
- add_people_info(out, &authors, &committers);
+ if (opts->credit_people)
+ add_people_info(out, &authors, &committers);
if (count > limit)
strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
else
@@ -635,7 +641,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
for (i = 0; i < origins.nr; i++)
shortlog(origins.items[i].string,
origins.items[i].util,
- head, &rev, opts->shortlog_len, out);
+ head, &rev, opts, out);
}
strbuf_complete_line(out);
@@ -690,6 +696,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
opts.add_title = !message;
+ opts.credit_people = 1;
opts.shortlog_len = shortlog_len;
ret = fmt_merge_msg(&input, &output, &opts);
diff --git a/builtin/log.c b/builtin/log.c
index 09cf43e6d4..8f0b2e84fe 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -22,6 +22,7 @@
#include "branch.h"
#include "streaming.h"
#include "version.h"
+#include "mailmap.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@@ -30,6 +31,7 @@ static int default_abbrev_commit;
static int default_show_root = 1;
static int decoration_style;
static int decoration_given;
+static int use_mailmap_config;
static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
@@ -94,16 +96,18 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
struct rev_info *rev, struct setup_revision_opt *opt)
{
struct userformat_want w;
- int quiet = 0, source = 0;
+ int quiet = 0, source = 0, mailmap = 0;
const struct option builtin_log_options[] = {
OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
OPT_BOOLEAN(0, "source", &source, N_("show source")),
+ OPT_BOOLEAN(0, "use-mailmap", &mailmap, N_("Use mail map file")),
{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback},
OPT_END()
};
+ mailmap = use_mailmap_config;
argc = parse_options(argc, argv, prefix,
builtin_log_options, builtin_log_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
@@ -136,6 +140,11 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
if (source)
rev->show_source = 1;
+ if (mailmap) {
+ rev->mailmap = xcalloc(1, sizeof(struct string_list));
+ read_mailmap(rev->mailmap, NULL);
+ }
+
if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
/*
* "log --pretty=raw" is special; ignore UI oriented
@@ -351,7 +360,13 @@ static int git_log_config(const char *var, const char *value, void *cb)
}
if (!prefixcmp(var, "color.decorate."))
return parse_decorate_color_config(var, 15, value);
+ if (!strcmp(var, "log.mailmap")) {
+ use_mailmap_config = git_config_bool(var, value);
+ return 0;
+ }
+ if (grep_config(var, value, cb) < 0)
+ return -1;
return git_diff_ui_config(var, value, cb);
}
@@ -360,6 +375,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
struct rev_info rev;
struct setup_revision_opt opt;
+ init_grep_defaults();
git_config(git_log_config, NULL);
init_revisions(&rev, prefix);
@@ -450,6 +466,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
struct pathspec match_all;
int i, count, ret = 0;
+ init_grep_defaults();
git_config(git_log_config, NULL);
init_pathspec(&match_all, NULL);
@@ -530,6 +547,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
struct rev_info rev;
struct setup_revision_opt opt;
+ init_grep_defaults();
git_config(git_log_config, NULL);
init_revisions(&rev, prefix);
@@ -552,6 +570,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
struct rev_info rev;
struct setup_revision_opt opt;
+ init_grep_defaults();
git_config(git_log_config, NULL);
init_revisions(&rev, prefix);
@@ -673,7 +692,7 @@ static int reopen_stdout(struct commit *commit, const char *subject,
struct rev_info *rev, int quiet)
{
struct strbuf filename = STRBUF_INIT;
- int suffix_len = strlen(fmt_patch_suffix) + 1;
+ int suffix_len = strlen(rev->patch_suffix) + 1;
if (output_directory) {
strbuf_addstr(&filename, output_directory);
@@ -684,7 +703,12 @@ static int reopen_stdout(struct commit *commit, const char *subject,
strbuf_addch(&filename, '/');
}
- get_patch_filename(commit, subject, rev->nr, fmt_patch_suffix, &filename);
+ if (rev->numbered_files)
+ strbuf_addf(&filename, "%d", rev->nr);
+ else if (commit)
+ fmt_output_commit(&filename, commit, rev);
+ else
+ fmt_output_subject(&filename, subject, rev);
if (!quiet)
fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
@@ -768,7 +792,6 @@ static void add_branch_description(struct strbuf *buf, const char *branch_name)
}
static void make_cover_letter(struct rev_info *rev, int use_stdout,
- int numbered, int numbered_files,
struct commit *origin,
int nr, struct commit **list, struct commit *head,
const char *branch_name,
@@ -791,7 +814,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
committer = git_committer_info(0);
if (!use_stdout &&
- reopen_stdout(NULL, numbered_files ? NULL : "cover-letter", rev, quiet))
+ reopen_stdout(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
return;
log_write_email_headers(rev, head, &pp.subject, &pp.after_subject,
@@ -1011,8 +1034,9 @@ static char *find_branch_name(struct rev_info *rev)
{
int i, positive = -1;
unsigned char branch_sha1[20];
- struct strbuf buf = STRBUF_INIT;
- const char *branch;
+ const unsigned char *tip_sha1;
+ const char *ref;
+ char *full_ref, *branch = NULL;
for (i = 0; i < rev->cmdline.nr; i++) {
if (rev->cmdline.rev[i].flags & UNINTERESTING)
@@ -1022,18 +1046,27 @@ static char *find_branch_name(struct rev_info *rev)
else
return NULL;
}
- if (positive < 0)
+ if (0 <= positive) {
+ ref = rev->cmdline.rev[positive].name;
+ tip_sha1 = rev->cmdline.rev[positive].item->sha1;
+ } else if (!rev->cmdline.nr && rev->pending.nr == 1 &&
+ !strcmp(rev->pending.objects[0].name, "HEAD")) {
+ /*
+ * No actual ref from command line, but "HEAD" from
+ * rev->def was added in setup_revisions()
+ * e.g. format-patch --cover-letter -12
+ */
+ ref = "HEAD";
+ tip_sha1 = rev->pending.objects[0].item->sha1;
+ } else {
return NULL;
- strbuf_addf(&buf, "refs/heads/%s", rev->cmdline.rev[positive].name);
- branch = resolve_ref_unsafe(buf.buf, branch_sha1, 1, NULL);
- if (!branch ||
- prefixcmp(branch, "refs/heads/") ||
- hashcmp(rev->cmdline.rev[positive].item->sha1, branch_sha1))
- branch = NULL;
- strbuf_release(&buf);
- if (branch)
- return xstrdup(rev->cmdline.rev[positive].name);
- return NULL;
+ }
+ if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
+ !prefixcmp(full_ref, "refs/heads/") &&
+ !hashcmp(tip_sha1, branch_sha1))
+ branch = xstrdup(full_ref + strlen("refs/heads/"));
+ free(full_ref);
+ return branch;
}
int cmd_format_patch(int argc, const char **argv, const char *prefix)
@@ -1045,7 +1078,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int nr = 0, total, i;
int use_stdout = 0;
int start_number = -1;
- int numbered_files = 0; /* _just_ numbers */
+ int just_numbers = 0;
int ignore_if_in_upstream = 0;
int cover_letter = 0;
int boundary_count = 0;
@@ -1057,6 +1090,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
int use_patch_format = 0;
int quiet = 0;
+ int reroll_count = -1;
char *branch_name = NULL;
const struct option builtin_format_patch_options[] = {
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
@@ -1070,12 +1104,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("print patches to standard out")),
OPT_BOOLEAN(0, "cover-letter", &cover_letter,
N_("generate a cover letter")),
- OPT_BOOLEAN(0, "numbered-files", &numbered_files,
+ OPT_BOOLEAN(0, "numbered-files", &just_numbers,
N_("use simple number sequence for output file names")),
OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
N_("use <sfx> instead of '.patch'")),
OPT_INTEGER(0, "start-number", &start_number,
N_("start numbering patches at <n> instead of 1")),
+ OPT_INTEGER('v', "reroll-count", &reroll_count,
+ N_("mark the series as Nth re-roll")),
{ OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
N_("Use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback },
@@ -1121,6 +1157,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
extra_hdr.strdup_strings = 1;
extra_to.strdup_strings = 1;
extra_cc.strdup_strings = 1;
+ init_grep_defaults();
git_config(git_format_config, NULL);
init_revisions(&rev, prefix);
rev.commit_format = CMIT_FMT_EMAIL;
@@ -1148,6 +1185,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
PARSE_OPT_KEEP_DASHDASH);
+ if (0 < reroll_count) {
+ struct strbuf sprefix = STRBUF_INIT;
+ strbuf_addf(&sprefix, "%s v%d",
+ rev.subject_prefix, reroll_count);
+ rev.reroll_count = reroll_count;
+ rev.subject_prefix = strbuf_detach(&sprefix, NULL);
+ }
+
if (do_signoff) {
const char *committer;
const char *endpos;
@@ -1338,12 +1383,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
const char *msgid = clean_message_id(in_reply_to);
string_list_append(rev.ref_message_ids, msgid);
}
- rev.numbered_files = numbered_files;
+ rev.numbered_files = just_numbers;
rev.patch_suffix = fmt_patch_suffix;
if (cover_letter) {
if (thread)
gen_message_id(&rev, "cover");
- make_cover_letter(&rev, use_stdout, numbered, numbered_files,
+ make_cover_letter(&rev, use_stdout,
origin, nr, list, head, branch_name, quiet);
total++;
start_number--;
@@ -1390,7 +1435,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
if (!use_stdout &&
- reopen_stdout(numbered_files ? NULL : commit, NULL, &rev, quiet))
+ reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
die(_("Failed to create output files"));
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index b5434af0c8..373c573449 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -203,7 +203,7 @@ static void show_ru_info(void)
static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce)
{
int dtype = ce_to_dtype(ce);
- return path_excluded(check, ce->name, ce_namelen(ce), &dtype);
+ return is_path_excluded(check, ce->name, ce_namelen(ce), &dtype);
}
static void show_files(struct dir_struct *dir)
@@ -337,7 +337,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
matchbuf[0] = prefix;
matchbuf[1] = NULL;
init_pathspec(&pathspec, matchbuf);
- pathspec.items[0].use_wildcard = 0;
+ pathspec.items[0].nowildcard_len = pathspec.items[0].len;
} else
init_pathspec(&pathspec, NULL);
if (read_tree(tree, 1, &pathspec))
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 235c17cc01..fb76e38d84 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -168,7 +168,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
init_pathspec(&pathspec, get_pathspec(prefix, argv + 1));
for (i = 0; i < pathspec.nr; i++)
- pathspec.items[i].use_wildcard = 0;
+ pathspec.items[i].nowildcard_len = pathspec.items[i].len;
pathspec.has_wildcard = 0;
tree = parse_tree_indirect(sha1);
if (!tree)
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 2338832587..be5e514324 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -42,7 +42,7 @@ static int merge_entry(int pos, const char *path)
return found;
}
-static void merge_file(const char *path)
+static void merge_one_path(const char *path)
{
int pos = cache_name_pos(path, strlen(path));
@@ -102,7 +102,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
}
die("git merge-index: unknown option %s", arg);
}
- merge_file(arg);
+ merge_one_path(arg);
}
if (err && !quiet)
die("merge program failed");
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 897a563bc6..e0d0b7d28b 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -3,17 +3,15 @@
#include "xdiff-interface.h"
#include "blob.h"
#include "exec_cmd.h"
-#include "merge-file.h"
+#include "merge-blobs.h"
static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
-static int resolve_directories = 1;
struct merge_list {
struct merge_list *next;
struct merge_list *link; /* other stages for this object */
- unsigned int stage : 2,
- flags : 30;
+ unsigned int stage : 2;
unsigned int mode;
const char *path;
struct blob *blob;
@@ -27,7 +25,7 @@ static void add_merge_entry(struct merge_list *entry)
merge_result_end = &entry->next;
}
-static void merge_trees(struct tree_desc t[3], const char *base);
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict);
static const char *explanation(struct merge_list *entry)
{
@@ -76,7 +74,7 @@ static void *result(struct merge_list *entry, unsigned long *size)
their = NULL;
if (entry)
their = entry->blob;
- return merge_file(path, base, our, their, size);
+ return merge_blobs(path, base, our, their, size);
}
static void *origin(struct merge_list *entry, unsigned long *size)
@@ -174,17 +172,17 @@ static char *traverse_path(const struct traverse_info *info, const struct name_e
return make_traverse_path(path, info, n);
}
-static void resolve(const struct traverse_info *info, struct name_entry *branch1, struct name_entry *result)
+static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
{
struct merge_list *orig, *final;
const char *path;
- /* If it's already branch1, don't bother showing it */
- if (!branch1)
+ /* If it's already ours, don't bother showing it */
+ if (!ours)
return;
path = traverse_path(info, result);
- orig = create_entry(2, branch1->mode, branch1->sha1, path);
+ orig = create_entry(2, ours->mode, ours->sha1, path);
final = create_entry(0, result->mode, result->sha1, path);
final->link = orig;
@@ -192,34 +190,35 @@ static void resolve(const struct traverse_info *info, struct name_entry *branch1
add_merge_entry(final);
}
-static int unresolved_directory(const struct traverse_info *info, struct name_entry n[3])
+static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3],
+ int df_conflict)
{
char *newbase;
struct name_entry *p;
struct tree_desc t[3];
void *buf0, *buf1, *buf2;
- if (!resolve_directories)
- return 0;
- p = n;
- if (!p->mode) {
- p++;
- if (!p->mode)
- p++;
+ for (p = n; p < n + 3; p++) {
+ if (p->mode && S_ISDIR(p->mode))
+ break;
}
- if (!S_ISDIR(p->mode))
- return 0;
+ if (n + 3 <= p)
+ return; /* there is no tree here */
+
newbase = traverse_path(info, p);
- buf0 = fill_tree_descriptor(t+0, n[0].sha1);
- buf1 = fill_tree_descriptor(t+1, n[1].sha1);
- buf2 = fill_tree_descriptor(t+2, n[2].sha1);
- merge_trees(t, newbase);
+
+#define ENTRY_SHA1(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->sha1 : NULL)
+ buf0 = fill_tree_descriptor(t+0, ENTRY_SHA1(n + 0));
+ buf1 = fill_tree_descriptor(t+1, ENTRY_SHA1(n + 1));
+ buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
+#undef ENTRY_SHA1
+
+ merge_trees_recursive(t, newbase, df_conflict);
free(buf0);
free(buf1);
free(buf2);
free(newbase);
- return 1;
}
@@ -242,18 +241,26 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
static void unresolved(const struct traverse_info *info, struct name_entry n[3])
{
struct merge_list *entry = NULL;
+ int i;
+ unsigned dirmask = 0, mask = 0;
+
+ for (i = 0; i < 3; i++) {
+ mask |= (1 << 1);
+ if (n[i].mode && S_ISDIR(n[i].mode))
+ dirmask |= (1 << i);
+ }
- if (unresolved_directory(info, n))
+ unresolved_directory(info, n, dirmask && (dirmask != mask));
+
+ if (dirmask == mask)
return;
- /*
- * Do them in reverse order so that the resulting link
- * list has the stages in order - link_entry adds new
- * links at the front.
- */
- entry = link_entry(3, info, n + 2, entry);
- entry = link_entry(2, info, n + 1, entry);
- entry = link_entry(1, info, n + 0, entry);
+ if (n[2].mode && !S_ISDIR(n[2].mode))
+ entry = link_entry(3, info, n + 2, entry);
+ if (n[1].mode && !S_ISDIR(n[1].mode))
+ entry = link_entry(2, info, n + 1, entry);
+ if (n[0].mode && !S_ISDIR(n[0].mode))
+ entry = link_entry(1, info, n + 0, entry);
add_merge_entry(entry);
}
@@ -292,20 +299,29 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
/* Same in both? */
if (same_entry(entry+1, entry+2)) {
if (entry[0].sha1) {
+ /* Modified identically */
resolve(info, NULL, entry+1);
return mask;
}
+ /* "Both added the same" is left unresolved */
}
if (same_entry(entry+0, entry+1)) {
if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
+ /* We did not touch, they modified -- take theirs */
resolve(info, entry+1, entry+2);
return mask;
}
+ /*
+ * If we did not touch a directory but they made it
+ * into a file, we fall through and unresolved()
+ * recurses down. Likewise for the opposite case.
+ */
}
if (same_entry(entry+0, entry+2)) {
if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
+ /* We modified, they did not touch -- take ours */
resolve(info, NULL, entry+1);
return mask;
}
@@ -315,15 +331,21 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
return mask;
}
-static void merge_trees(struct tree_desc t[3], const char *base)
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict)
{
struct traverse_info info;
setup_traverse_info(&info, base);
+ info.data = &df_conflict;
info.fn = threeway_callback;
traverse_trees(3, t, &info);
}
+static void merge_trees(struct tree_desc t[3], const char *base)
+{
+ merge_trees_recursive(t, base, 0);
+}
+
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
{
unsigned char sha1[20];
diff --git a/builtin/merge.c b/builtin/merge.c
index 0ec8f0d449..9307e9c726 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -628,59 +628,6 @@ static void write_tree_trivial(unsigned char *sha1)
die(_("git write-tree failed to write a tree"));
}
-static const char *merge_argument(struct commit *commit)
-{
- if (commit)
- return sha1_to_hex(commit->object.sha1);
- else
- return EMPTY_TREE_SHA1_HEX;
-}
-
-int try_merge_command(const char *strategy, size_t xopts_nr,
- const char **xopts, 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(merge_argument(j->item));
- args[i++] = "--";
- args[i++] = head_arg;
- for (j = remotes; j; j = j->next)
- args[i++] = xstrdup(merge_argument(j->item));
- 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,
struct commit_list *remoteheads,
struct commit *head, const char *head_arg)
@@ -762,56 +709,6 @@ static int count_unmerged_entries(void)
return ret;
}
-int checkout_fast_forward(const unsigned char *head, const unsigned char *remote)
-{
- struct tree *trees[MAX_UNPACK_TREES];
- struct unpack_trees_options opts;
- struct tree_desc t[MAX_UNPACK_TREES];
- int i, fd, nr_trees = 0;
- struct dir_struct dir;
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
-
- refresh_cache(REFRESH_QUIET);
-
- fd = hold_locked_index(lock_file, 1);
-
- memset(&trees, 0, sizeof(trees));
- memset(&opts, 0, sizeof(opts));
- memset(&t, 0, sizeof(t));
- if (overwrite_ignore) {
- memset(&dir, 0, sizeof(dir));
- dir.flags |= DIR_SHOW_IGNORED;
- setup_standard_excludes(&dir);
- opts.dir = &dir;
- }
-
- opts.head_idx = 1;
- opts.src_index = &the_index;
- opts.dst_index = &the_index;
- opts.update = 1;
- opts.verbose_update = 1;
- opts.merge = 1;
- opts.fn = twoway_merge;
- setup_unpack_trees_porcelain(&opts, "merge");
-
- trees[nr_trees] = parse_tree_indirect(head);
- if (!trees[nr_trees++])
- return -1;
- trees[nr_trees] = parse_tree_indirect(remote);
- if (!trees[nr_trees++])
- return -1;
- for (i = 0; i < nr_trees; i++) {
- parse_tree(trees[i]);
- init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
- }
- if (unpack_trees(nr_trees, t, &opts))
- return -1;
- if (write_cache(fd, active_cache, active_nr) ||
- commit_locked_index(lock_file))
- die(_("unable to write new index file"));
- return 0;
-}
-
static void split_merge_strategies(const char *string, struct strategy **list,
int *nr, int *alloc)
{
@@ -903,8 +800,9 @@ static void prepare_to_commit(struct commit_list *remoteheads)
if (0 < option_edit)
strbuf_add_lines(&msg, "# ", comment, strlen(comment));
write_merge_msg(&msg);
- run_hook(get_index_file(), "prepare-commit-msg",
- git_path("MERGE_MSG"), "merge", NULL, NULL);
+ if (run_hook(get_index_file(), "prepare-commit-msg",
+ git_path("MERGE_MSG"), "merge", NULL, NULL))
+ abort_commit(remoteheads, NULL);
if (0 < option_edit) {
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
abort_commit(remoteheads, NULL);
@@ -1324,6 +1222,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
opts.add_title = !have_message;
opts.shortlog_len = shortlog_len;
+ opts.credit_people = (0 < option_edit);
fmt_merge_msg(&merge_names, &merge_msg, &opts);
if (merge_msg.len)
@@ -1424,7 +1323,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
if (checkout_fast_forward(head_commit->object.sha1,
- commit->object.sha1)) {
+ commit->object.sha1,
+ overwrite_ignore)) {
ret = 1;
goto done;
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 5e14064094..f069462cb0 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2033,7 +2033,6 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo
if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
!peel_ref(path, peeled) && /* peelable? */
- !is_null_sha1(peeled) && /* annotated tag? */
locate_object_entry(peeled)) /* object packed? */
add_object_entry(sha1, OBJ_TAG, NULL, 0);
return 0;
diff --git a/builtin/push.c b/builtin/push.c
index db9ba30b08..8491e431e4 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -220,31 +220,42 @@ static const char message_advice_checkout_pull_push[] =
"(e.g. 'git pull') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details.");
+static const char message_advice_ref_already_exists[] =
+ N_("Updates were rejected because the destination reference already exists\n"
+ "in the remote.");
+
static void advise_pull_before_push(void)
{
- if (!advice_push_non_ff_current || !advice_push_nonfastforward)
+ if (!advice_push_non_ff_current || !advice_push_update_rejected)
return;
advise(_(message_advice_pull_before_push));
}
static void advise_use_upstream(void)
{
- if (!advice_push_non_ff_default || !advice_push_nonfastforward)
+ if (!advice_push_non_ff_default || !advice_push_update_rejected)
return;
advise(_(message_advice_use_upstream));
}
static void advise_checkout_pull_push(void)
{
- if (!advice_push_non_ff_matching || !advice_push_nonfastforward)
+ if (!advice_push_non_ff_matching || !advice_push_update_rejected)
return;
advise(_(message_advice_checkout_pull_push));
}
+static void advise_ref_already_exists(void)
+{
+ if (!advice_push_already_exists || !advice_push_update_rejected)
+ return;
+ advise(_(message_advice_ref_already_exists));
+}
+
static int push_with_options(struct transport *transport, int flags)
{
int err;
- int nonfastforward;
+ unsigned int reject_reasons;
transport_set_verbosity(transport, verbosity, progress);
@@ -257,7 +268,7 @@ static int push_with_options(struct transport *transport, int flags)
if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url);
err = transport_push(transport, refspec_nr, refspec, flags,
- &nonfastforward);
+ &reject_reasons);
if (err != 0)
error(_("failed to push some refs to '%s'"), transport->url);
@@ -265,18 +276,15 @@ static int push_with_options(struct transport *transport, int flags)
if (!err)
return 0;
- switch (nonfastforward) {
- default:
- break;
- case NON_FF_HEAD:
+ if (reject_reasons & REJECT_NON_FF_HEAD) {
advise_pull_before_push();
- break;
- case NON_FF_OTHER:
+ } else if (reject_reasons & REJECT_NON_FF_OTHER) {
if (default_matching_used)
advise_use_upstream();
else
advise_checkout_pull_push();
- break;
+ } else if (reject_reasons & REJECT_ALREADY_EXISTS) {
+ advise_ref_already_exists();
}
return 1;
diff --git a/builtin/replace.c b/builtin/replace.c
index e3aaf70203..398ccd5eaa 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -46,24 +46,27 @@ typedef int (*each_replace_name_fn)(const char *name, const char *ref,
static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
{
- const char **p;
+ const char **p, *full_hex;
char ref[PATH_MAX];
int had_error = 0;
unsigned char sha1[20];
for (p = argv; *p; p++) {
- if (snprintf(ref, sizeof(ref), "refs/replace/%s", *p)
- >= sizeof(ref)) {
- error("replace ref name too long: %.*s...", 50, *p);
+ if (get_sha1(*p, sha1)) {
+ error("Failed to resolve '%s' as a valid ref.", *p);
had_error = 1;
continue;
}
+ full_hex = sha1_to_hex(sha1);
+ snprintf(ref, sizeof(ref), "refs/replace/%s", full_hex);
+ /* read_ref() may reuse the buffer */
+ full_hex = ref + strlen("refs/replace/");
if (read_ref(ref, sha1)) {
- error("replace ref '%s' not found.", *p);
+ error("replace ref '%s' not found.", full_hex);
had_error = 1;
continue;
}
- if (fn(*p, ref, sha1))
+ if (fn(full_hex, ref, sha1))
had_error = 1;
}
return had_error;
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index ff5a38372d..67701be551 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -201,55 +201,6 @@ static void show_edge(struct commit *commit)
printf("-%s\n", sha1_to_hex(commit->object.sha1));
}
-static inline int log2i(int n)
-{
- int log2 = 0;
-
- for (; n > 1; n >>= 1)
- log2++;
-
- return log2;
-}
-
-static inline int exp2i(int n)
-{
- return 1 << n;
-}
-
-/*
- * Estimate the number of bisect steps left (after the current step)
- *
- * For any x between 0 included and 2^n excluded, the probability for
- * n - 1 steps left looks like:
- *
- * P(2^n + x) == (2^n - x) / (2^n + x)
- *
- * and P(2^n + x) < 0.5 means 2^n < 3x
- */
-int estimate_bisect_steps(int all)
-{
- int n, x, e;
-
- if (all < 3)
- return 0;
-
- n = log2i(all);
- e = exp2i(n);
- x = all - e;
-
- return (e < 3 * x) ? n : n - 1;
-}
-
-void print_commit_list(struct commit_list *list,
- const char *format_cur,
- const char *format_last)
-{
- for ( ; list; list = list->next) {
- const char *format = list->next ? format_cur : format_last;
- printf(format, sha1_to_hex(list->item->object.sha1));
- }
-}
-
static void print_var_str(const char *var, const char *val)
{
printf("%s='%s'\n", var, val);
diff --git a/builtin/rm.c b/builtin/rm.c
index b384c4c3cf..dabfcf6890 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -9,6 +9,7 @@
#include "cache-tree.h"
#include "tree-walk.h"
#include "parse-options.h"
+#include "submodule.h"
static const char * const builtin_rm_usage[] = {
N_("git rm [options] [--] <file>..."),
@@ -17,9 +18,58 @@ static const char * const builtin_rm_usage[] = {
static struct {
int nr, alloc;
- const char **name;
+ struct {
+ const char *name;
+ char is_submodule;
+ } *entry;
} list;
+static int get_ours_cache_pos(const char *path, int pos)
+{
+ int i = -pos - 1;
+
+ while ((i < active_nr) && !strcmp(active_cache[i]->name, path)) {
+ if (ce_stage(active_cache[i]) == 2)
+ return i;
+ i++;
+ }
+ return -1;
+}
+
+static int check_submodules_use_gitfiles(void)
+{
+ int i;
+ int errs = 0;
+
+ for (i = 0; i < list.nr; i++) {
+ const char *name = list.entry[i].name;
+ int pos;
+ struct cache_entry *ce;
+ struct stat st;
+
+ pos = cache_name_pos(name, strlen(name));
+ if (pos < 0) {
+ pos = get_ours_cache_pos(name, pos);
+ if (pos < 0)
+ continue;
+ }
+ ce = active_cache[pos];
+
+ if (!S_ISGITLINK(ce->ce_mode) ||
+ (lstat(ce->name, &st) < 0) ||
+ is_empty_dir(name))
+ continue;
+
+ if (!submodule_uses_gitfile(name))
+ errs = error(_("submodule '%s' (or one of its nested "
+ "submodules) uses a .git directory\n"
+ "(use 'rm -rf' if you really want to remove "
+ "it including all of its history)"), name);
+ }
+
+ return errs;
+}
+
static int check_local_mod(unsigned char *head, int index_only)
{
/*
@@ -37,15 +87,26 @@ static int check_local_mod(unsigned char *head, int index_only)
struct stat st;
int pos;
struct cache_entry *ce;
- const char *name = list.name[i];
+ const char *name = list.entry[i].name;
unsigned char sha1[20];
unsigned mode;
int local_changes = 0;
int staged_changes = 0;
pos = cache_name_pos(name, strlen(name));
- if (pos < 0)
- continue; /* removing unmerged entry */
+ if (pos < 0) {
+ /*
+ * Skip unmerged entries except for populated submodules
+ * that could lose history when removed.
+ */
+ pos = get_ours_cache_pos(name, pos);
+ if (pos < 0)
+ continue;
+
+ if (!S_ISGITLINK(active_cache[pos]->ce_mode) ||
+ is_empty_dir(name))
+ continue;
+ }
ce = active_cache[pos];
if (lstat(ce->name, &st) < 0) {
@@ -58,9 +119,10 @@ static int check_local_mod(unsigned char *head, int index_only)
/* if a file was removed and it is now a
* directory, that is the same as ENOENT as
* far as git is concerned; we do not track
- * directories.
+ * directories unless they are submodules.
*/
- continue;
+ if (!S_ISGITLINK(ce->ce_mode))
+ continue;
}
/*
@@ -80,8 +142,11 @@ static int check_local_mod(unsigned char *head, int index_only)
/*
* Is the index different from the file in the work tree?
+ * If it's a submodule, is its work tree modified?
*/
- if (ce_match_stat(ce, &st, 0))
+ if (ce_match_stat(ce, &st, 0) ||
+ (S_ISGITLINK(ce->ce_mode) &&
+ !ok_to_remove_submodule(ce->name)))
local_changes = 1;
/*
@@ -115,10 +180,18 @@ static int check_local_mod(unsigned char *head, int index_only)
errs = error(_("'%s' has changes staged in the index\n"
"(use --cached to keep the file, "
"or -f to force removal)"), name);
- if (local_changes)
- errs = error(_("'%s' has local modifications\n"
- "(use --cached to keep the file, "
- "or -f to force removal)"), name);
+ if (local_changes) {
+ if (S_ISGITLINK(ce->ce_mode) &&
+ !submodule_uses_gitfile(name)) {
+ errs = error(_("submodule '%s' (or one of its nested "
+ "submodules) uses a .git directory\n"
+ "(use 'rm -rf' if you really want to remove "
+ "it including all of its history)"), name);
+ } else
+ errs = error(_("'%s' has local modifications\n"
+ "(use --cached to keep the file, "
+ "or -f to force removal)"), name);
+ }
}
}
return errs;
@@ -161,6 +234,21 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die(_("index file corrupt"));
+ /*
+ * Drop trailing directory separators from directories so we'll find
+ * submodules in the index.
+ */
+ for (i = 0; i < argc; i++) {
+ size_t pathlen = strlen(argv[i]);
+ if (pathlen && is_dir_sep(argv[i][pathlen - 1]) &&
+ is_directory(argv[i])) {
+ do {
+ pathlen--;
+ } while (pathlen && is_dir_sep(argv[i][pathlen - 1]));
+ argv[i] = xmemdupz(argv[i], pathlen);
+ }
+ }
+
pathspec = get_pathspec(prefix, argv);
refresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL);
@@ -173,8 +261,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
struct cache_entry *ce = active_cache[i];
if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
continue;
- ALLOC_GROW(list.name, list.nr + 1, list.alloc);
- list.name[list.nr++] = ce->name;
+ ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
+ list.entry[list.nr].name = ce->name;
+ list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode);
}
if (pathspec) {
@@ -215,6 +304,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
hashclr(sha1);
if (check_local_mod(sha1, index_only))
exit(1);
+ } else if (!index_only) {
+ if (check_submodules_use_gitfiles())
+ exit(1);
}
/*
@@ -222,7 +314,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
* the index unless all of them succeed.
*/
for (i = 0; i < list.nr; i++) {
- const char *path = list.name[i];
+ const char *path = list.entry[i].name;
if (!quiet)
printf("rm '%s'\n", path);
@@ -244,7 +336,25 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (!index_only) {
int removed = 0;
for (i = 0; i < list.nr; i++) {
- const char *path = list.name[i];
+ const char *path = list.entry[i].name;
+ if (list.entry[i].is_submodule) {
+ if (is_empty_dir(path)) {
+ if (!rmdir(path)) {
+ removed = 1;
+ continue;
+ }
+ } else {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addstr(&buf, path);
+ if (!remove_dir_recursively(&buf, 0)) {
+ removed = 1;
+ strbuf_release(&buf);
+ continue;
+ }
+ strbuf_release(&buf);
+ /* Fallthrough and let remove_path() fail. */
+ }
+ }
if (!remove_path(path)) {
removed = 1;
continue;
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 7d05064218..f849e0a4a0 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -16,164 +16,6 @@ static const char send_pack_usage[] =
static struct send_pack_args args;
-static int feed_object(const unsigned char *sha1, int fd, int negative)
-{
- char buf[42];
-
- if (negative && !has_sha1_file(sha1))
- return 1;
-
- memcpy(buf + negative, sha1_to_hex(sha1), 40);
- if (negative)
- buf[0] = '^';
- buf[40 + negative] = '\n';
- return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
-}
-
-/*
- * Make a pack stream and spit it out into file descriptor fd
- */
-static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
-{
- /*
- * The child becomes pack-objects --revs; we feed
- * the revision parameters to it via its stdin and
- * let its stdout go back to the other end.
- */
- const char *argv[] = {
- "pack-objects",
- "--all-progress-implied",
- "--revs",
- "--stdout",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- };
- struct child_process po;
- int i;
-
- i = 4;
- if (args->use_thin_pack)
- argv[i++] = "--thin";
- if (args->use_ofs_delta)
- argv[i++] = "--delta-base-offset";
- if (args->quiet || !args->progress)
- argv[i++] = "-q";
- if (args->progress)
- argv[i++] = "--progress";
- memset(&po, 0, sizeof(po));
- po.argv = argv;
- po.in = -1;
- po.out = args->stateless_rpc ? -1 : fd;
- po.git_cmd = 1;
- if (start_command(&po))
- die_errno("git pack-objects failed");
-
- /*
- * We feed the pack-objects we just spawned with revision
- * parameters by writing to the pipe.
- */
- for (i = 0; i < extra->nr; i++)
- if (!feed_object(extra->array[i], po.in, 1))
- break;
-
- while (refs) {
- if (!is_null_sha1(refs->old_sha1) &&
- !feed_object(refs->old_sha1, po.in, 1))
- break;
- if (!is_null_sha1(refs->new_sha1) &&
- !feed_object(refs->new_sha1, po.in, 0))
- break;
- refs = refs->next;
- }
-
- close(po.in);
-
- if (args->stateless_rpc) {
- char *buf = xmalloc(LARGE_PACKET_MAX);
- while (1) {
- ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
- if (n <= 0)
- break;
- send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
- }
- free(buf);
- close(po.out);
- po.out = -1;
- }
-
- if (finish_command(&po))
- return -1;
- return 0;
-}
-
-static int receive_status(int in, struct ref *refs)
-{
- struct ref *hint;
- char line[1000];
- int ret = 0;
- int len = packet_read_line(in, line, sizeof(line));
- if (len < 10 || memcmp(line, "unpack ", 7))
- return error("did not receive remote status");
- if (memcmp(line, "unpack ok\n", 10)) {
- char *p = line + strlen(line) - 1;
- if (*p == '\n')
- *p = '\0';
- error("unpack failed: %s", line + 7);
- ret = -1;
- }
- hint = NULL;
- while (1) {
- char *refname;
- char *msg;
- len = packet_read_line(in, line, sizeof(line));
- if (!len)
- break;
- if (len < 3 ||
- (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
- fprintf(stderr, "protocol error: %s\n", line);
- ret = -1;
- break;
- }
-
- line[strlen(line)-1] = '\0';
- refname = line + 3;
- msg = strchr(refname, ' ');
- if (msg)
- *msg++ = '\0';
-
- /* first try searching at our hint, falling back to all refs */
- if (hint)
- hint = find_ref_by_name(hint, refname);
- if (!hint)
- hint = find_ref_by_name(refs, refname);
- if (!hint) {
- warning("remote reported status on unknown ref: %s",
- refname);
- continue;
- }
- if (hint->status != REF_STATUS_EXPECTING_REPORT) {
- warning("remote reported status on unexpected ref: %s",
- refname);
- continue;
- }
-
- if (line[0] == 'o' && line[1] == 'k')
- hint->status = REF_STATUS_OK;
- else {
- hint->status = REF_STATUS_REMOTE_REJECT;
- ret = -1;
- }
- if (msg)
- hint->remote_status = xstrdup(msg);
- /* start our next search from the next ref */
- hint = hint->next;
- }
- return ret;
-}
-
static void print_helper_status(struct ref *ref)
{
struct strbuf buf = STRBUF_INIT;
@@ -202,6 +44,11 @@ static void print_helper_status(struct ref *ref)
msg = "non-fast forward";
break;
+ case REF_STATUS_REJECT_ALREADY_EXISTS:
+ res = "error";
+ msg = "already exists";
+ break;
+
case REF_STATUS_REJECT_NODELETE:
case REF_STATUS_REMOTE_REJECT:
res = "error";
@@ -227,181 +74,6 @@ static void print_helper_status(struct ref *ref)
strbuf_release(&buf);
}
-static int sideband_demux(int in, int out, void *data)
-{
- int *fd = data, ret;
-#ifdef NO_PTHREADS
- close(fd[1]);
-#endif
- ret = recv_sideband("send-pack", fd[0], out);
- close(out);
- return ret;
-}
-
-int send_pack(struct send_pack_args *args,
- int fd[], struct child_process *conn,
- struct ref *remote_refs,
- struct extra_have_objects *extra_have)
-{
- int in = fd[0];
- int out = fd[1];
- struct strbuf req_buf = STRBUF_INIT;
- struct ref *ref;
- int new_refs;
- int allow_deleting_refs = 0;
- int status_report = 0;
- int use_sideband = 0;
- int quiet_supported = 0;
- int agent_supported = 0;
- unsigned cmds_sent = 0;
- int ret;
- struct async demux;
-
- /* Does the other end support the reporting? */
- if (server_supports("report-status"))
- status_report = 1;
- if (server_supports("delete-refs"))
- allow_deleting_refs = 1;
- if (server_supports("ofs-delta"))
- args->use_ofs_delta = 1;
- if (server_supports("side-band-64k"))
- use_sideband = 1;
- if (server_supports("quiet"))
- quiet_supported = 1;
- if (server_supports("agent"))
- agent_supported = 1;
-
- if (!remote_refs) {
- fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
- "Perhaps you should specify a branch such as 'master'.\n");
- return 0;
- }
-
- /*
- * Finally, tell the other end!
- */
- new_refs = 0;
- for (ref = remote_refs; ref; ref = ref->next) {
- if (!ref->peer_ref && !args->send_mirror)
- continue;
-
- /* Check for statuses set by set_ref_status_for_push() */
- switch (ref->status) {
- case REF_STATUS_REJECT_NONFASTFORWARD:
- case REF_STATUS_UPTODATE:
- continue;
- default:
- ; /* do nothing */
- }
-
- if (ref->deletion && !allow_deleting_refs) {
- ref->status = REF_STATUS_REJECT_NODELETE;
- continue;
- }
-
- if (!ref->deletion)
- new_refs++;
-
- if (args->dry_run) {
- ref->status = REF_STATUS_OK;
- } else {
- char *old_hex = sha1_to_hex(ref->old_sha1);
- char *new_hex = sha1_to_hex(ref->new_sha1);
- int quiet = quiet_supported && (args->quiet || !args->progress);
-
- if (!cmds_sent && (status_report || use_sideband ||
- quiet || agent_supported)) {
- packet_buf_write(&req_buf,
- "%s %s %s%c%s%s%s%s%s",
- old_hex, new_hex, ref->name, 0,
- status_report ? " report-status" : "",
- use_sideband ? " side-band-64k" : "",
- quiet ? " quiet" : "",
- agent_supported ? " agent=" : "",
- agent_supported ? git_user_agent_sanitized() : ""
- );
- }
- else
- packet_buf_write(&req_buf, "%s %s %s",
- old_hex, new_hex, ref->name);
- ref->status = status_report ?
- REF_STATUS_EXPECTING_REPORT :
- REF_STATUS_OK;
- cmds_sent++;
- }
- }
-
- if (args->stateless_rpc) {
- if (!args->dry_run && cmds_sent) {
- packet_buf_flush(&req_buf);
- send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
- }
- } else {
- safe_write(out, req_buf.buf, req_buf.len);
- packet_flush(out);
- }
- strbuf_release(&req_buf);
-
- if (use_sideband && cmds_sent) {
- memset(&demux, 0, sizeof(demux));
- demux.proc = sideband_demux;
- demux.data = fd;
- demux.out = -1;
- if (start_async(&demux))
- die("send-pack: unable to fork off sideband demultiplexer");
- in = demux.out;
- }
-
- if (new_refs && cmds_sent) {
- if (pack_objects(out, remote_refs, extra_have, args) < 0) {
- for (ref = remote_refs; ref; ref = ref->next)
- ref->status = REF_STATUS_NONE;
- if (args->stateless_rpc)
- close(out);
- if (git_connection_is_socket(conn))
- shutdown(fd[0], SHUT_WR);
- if (use_sideband)
- finish_async(&demux);
- return -1;
- }
- }
- if (args->stateless_rpc && cmds_sent)
- packet_flush(out);
-
- if (status_report && cmds_sent)
- ret = receive_status(in, remote_refs);
- else
- ret = 0;
- if (args->stateless_rpc)
- packet_flush(out);
-
- if (use_sideband && cmds_sent) {
- if (finish_async(&demux)) {
- error("error in sideband demultiplexer");
- ret = -1;
- }
- close(demux.out);
- }
-
- if (ret < 0)
- return ret;
-
- if (args->porcelain)
- return 0;
-
- for (ref = remote_refs; ref; ref = ref->next) {
- switch (ref->status) {
- case REF_STATUS_NONE:
- case REF_STATUS_UPTODATE:
- case REF_STATUS_OK:
- break;
- default:
- return -1;
- }
- }
- return 0;
-}
-
int cmd_send_pack(int argc, const char **argv, const char *prefix)
{
int i, nr_refspecs = 0;
@@ -418,7 +90,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
int send_all = 0;
const char *receivepack = "git-receive-pack";
int flags;
- int nonfastforward = 0;
+ unsigned int reject_reasons;
int progress = -1;
argv++;
@@ -556,7 +228,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
ret |= finish_connect(conn);
if (!helper_status)
- transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward);
+ transport_print_push_status(dest, remote_refs, args.verbose, 0, &reject_reasons);
if (!args.dry_run && remote) {
struct ref *ref;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index b316cf37ca..240bff3efa 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -36,52 +36,28 @@ static void insert_one_record(struct shortlog *log,
const char *dot3 = log->common_repo_prefix;
char *buffer, *p;
struct string_list_item *item;
- char namebuf[1024];
- char emailbuf[1024];
- size_t len;
+ const char *mailbuf, *namebuf;
+ size_t namelen, maillen;
const char *eol;
- const char *boemail, *eoemail;
struct strbuf subject = STRBUF_INIT;
+ struct strbuf namemailbuf = STRBUF_INIT;
+ struct ident_split ident;
- boemail = strchr(author, '<');
- if (!boemail)
- return;
- eoemail = strchr(boemail, '>');
- if (!eoemail)
+ if (split_ident_line(&ident, author, strlen(author)))
return;
- /* copy author name to namebuf, to support matching on both name and email */
- memcpy(namebuf, author, boemail - author);
- len = boemail - author;
- while (len > 0 && isspace(namebuf[len-1]))
- len--;
- namebuf[len] = 0;
-
- /* copy email name to emailbuf, to allow email replacement as well */
- memcpy(emailbuf, boemail+1, eoemail - boemail);
- emailbuf[eoemail - boemail - 1] = 0;
-
- if (!map_user(&log->mailmap, emailbuf, sizeof(emailbuf), namebuf, sizeof(namebuf))) {
- while (author < boemail && isspace(*author))
- author++;
- for (len = 0;
- len < sizeof(namebuf) - 1 && author + len < boemail;
- len++)
- namebuf[len] = author[len];
- while (0 < len && isspace(namebuf[len-1]))
- len--;
- namebuf[len] = '\0';
- }
- else
- len = strlen(namebuf);
+ namebuf = ident.name_begin;
+ mailbuf = ident.mail_begin;
+ namelen = ident.name_end - ident.name_begin;
+ maillen = ident.mail_end - ident.mail_begin;
- if (log->email) {
- size_t room = sizeof(namebuf) - len - 1;
- int maillen = strlen(emailbuf);
- snprintf(namebuf + len, room, " <%.*s>", maillen, emailbuf);
- }
+ map_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
+ strbuf_add(&namemailbuf, namebuf, namelen);
+
+ if (log->email)
+ strbuf_addf(&namemailbuf, " <%.*s>", (int)maillen, mailbuf);
- item = string_list_insert(&log->list, namebuf);
+ item = string_list_insert(&log->list, namemailbuf.buf);
if (item->util == NULL)
item->util = xcalloc(1, sizeof(struct string_list));
@@ -306,9 +282,8 @@ parse_done:
static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
const struct shortlog *log)
{
- int col = strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
- if (col != log->wrap)
- strbuf_addch(sb, '\n');
+ strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
+ strbuf_addch(sb, '\n');
}
void shortlog_output(struct shortlog *log)
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 4eb016d6e5..8d9b76a02f 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -28,7 +28,6 @@ static void show_one(const char *refname, const unsigned char *sha1)
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
{
- struct object *obj;
const char *hex;
unsigned char peeled[20];
@@ -79,25 +78,9 @@ match:
if (!deref_tags)
return 0;
- if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) {
- if (!is_null_sha1(peeled)) {
- hex = find_unique_abbrev(peeled, abbrev);
- printf("%s %s^{}\n", hex, refname);
- }
- }
- else {
- obj = parse_object(sha1);
- if (!obj)
- die("git show-ref: bad ref %s (%s)", refname,
- sha1_to_hex(sha1));
- if (obj->type == OBJ_TAG) {
- obj = deref_tag(obj, refname, 0);
- if (!obj)
- die("git show-ref: bad tag at ref %s (%s)", refname,
- sha1_to_hex(sha1));
- hex = find_unique_abbrev(obj->sha1, abbrev);
- printf("%s %s^{}\n", hex, refname);
- }
+ if (!peel_ref(refname, peeled)) {
+ hex = find_unique_abbrev(peeled, abbrev);
+ printf("%s %s^{}\n", hex, refname);
}
return 0;
}
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 9e92828b3a..f481959421 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -5,12 +5,11 @@
static const char * const git_symbolic_ref_usage[] = {
N_("git symbolic-ref [options] name [ref]"),
+ N_("git symbolic-ref -d [-q] name"),
NULL
};
-static int shorten;
-
-static void check_symref(const char *HEAD, int quiet)
+static int check_symref(const char *HEAD, int quiet, int shorten, int print)
{
unsigned char sha1[20];
int flag;
@@ -22,20 +21,24 @@ static void check_symref(const char *HEAD, int quiet)
if (!quiet)
die("ref %s is not a symbolic ref", HEAD);
else
- exit(1);
+ return 1;
+ }
+ if (print) {
+ if (shorten)
+ refname = shorten_unambiguous_ref(refname, 0);
+ puts(refname);
}
- if (shorten)
- refname = shorten_unambiguous_ref(refname, 0);
- puts(refname);
+ return 0;
}
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
{
- int quiet = 0;
+ int quiet = 0, delete = 0, shorten = 0, ret = 0;
const char *msg = NULL;
struct option options[] = {
OPT__QUIET(&quiet,
N_("suppress error message for non-symbolic (detached) refs")),
+ OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
OPT_END(),
@@ -46,9 +49,19 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
git_symbolic_ref_usage, 0);
if (msg &&!*msg)
die("Refusing to perform update with empty message");
+
+ if (delete) {
+ if (argc != 1)
+ usage_with_options(git_symbolic_ref_usage, options);
+ ret = check_symref(argv[0], 1, 0, 0);
+ if (ret)
+ die("Cannot delete %s, not a symbolic ref", argv[0]);
+ return delete_ref(argv[0], NULL, REF_NODEREF);
+ }
+
switch (argc) {
case 1:
- check_symref(argv[0], quiet);
+ ret = check_symref(argv[0], quiet, shorten, 1);
break;
case 2:
if (!strcmp(argv[0], "HEAD") &&
@@ -59,5 +72,5 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
default:
usage_with_options(git_symbolic_ref_usage, options);
}
- return 0;
+ return ret;
}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 74986bf163..ada1dff846 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -593,6 +593,7 @@ struct refresh_params {
static int refresh(struct refresh_params *o, unsigned int flag)
{
setup_work_tree();
+ read_cache_preload(NULL);
*o->has_errors |= refresh_cache(o->flags | flag);
return 0;
}