summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/am.c120
-rw-r--r--builtin/blame.c19
-rw-r--r--builtin/branch.c341
-rw-r--r--builtin/bundle.c8
-rw-r--r--builtin/cat-file.c19
-rw-r--r--builtin/check-attr.c66
-rw-r--r--builtin/checkout.c59
-rw-r--r--builtin/clean.c16
-rw-r--r--builtin/clone.c64
-rw-r--r--builtin/commit.c56
-rw-r--r--builtin/config.c32
-rw-r--r--builtin/count-objects.c4
-rw-r--r--builtin/describe.c163
-rw-r--r--builtin/diff-tree.c63
-rw-r--r--builtin/diff.c40
-rw-r--r--builtin/difftool.c118
-rw-r--r--builtin/fast-export.c60
-rw-r--r--builtin/fetch-pack.c2
-rw-r--r--builtin/fetch.c12
-rw-r--r--builtin/fmt-merge-msg.c70
-rw-r--r--builtin/for-each-ref.c5
-rw-r--r--builtin/fsck.c41
-rw-r--r--builtin/gc.c37
-rw-r--r--builtin/grep.c89
-rw-r--r--builtin/hash-object.c10
-rw-r--r--builtin/index-pack.c24
-rw-r--r--builtin/log.c17
-rw-r--r--builtin/ls-files.c50
-rw-r--r--builtin/ls-remote.c10
-rw-r--r--builtin/mailinfo.c11
-rw-r--r--builtin/mailsplit.c10
-rw-r--r--builtin/merge-base.c30
-rw-r--r--builtin/merge-file.c18
-rw-r--r--builtin/merge-index.c2
-rw-r--r--builtin/merge.c183
-rw-r--r--builtin/mktree.c5
-rw-r--r--builtin/name-rev.c86
-rw-r--r--builtin/notes.c37
-rw-r--r--builtin/pack-objects.c67
-rw-r--r--builtin/pack-redundant.c1
-rw-r--r--builtin/pack-refs.c2
-rw-r--r--builtin/patch-id.c2
-rw-r--r--builtin/prune-packed.c4
-rw-r--r--builtin/prune.c8
-rw-r--r--builtin/pull.c102
-rw-r--r--builtin/push.c5
-rw-r--r--builtin/read-tree.c36
-rw-r--r--builtin/rebase--helper.c40
-rw-r--r--builtin/receive-pack.c256
-rw-r--r--builtin/reflog.c2
-rw-r--r--builtin/remote.c11
-rw-r--r--builtin/replace.c147
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/rev-list.c2
-rw-r--r--builtin/rev-parse.c63
-rw-r--r--builtin/revert.c21
-rw-r--r--builtin/send-pack.c9
-rw-r--r--builtin/shortlog.c2
-rw-r--r--builtin/submodule--helper.c149
-rw-r--r--builtin/symbolic-ref.c2
-rw-r--r--builtin/tag.c131
-rw-r--r--builtin/update-index.c31
-rw-r--r--builtin/update-ref.c2
-rw-r--r--builtin/worktree.c34
64 files changed, 1796 insertions, 1332 deletions
diff --git a/builtin/am.c b/builtin/am.c
index 31fb60578f..593c1b5dda 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -134,17 +134,15 @@ struct am_state {
};
/**
- * Initializes am_state with the default values. The state directory is set to
- * dir.
+ * Initializes am_state with the default values.
*/
-static void am_state_init(struct am_state *state, const char *dir)
+static void am_state_init(struct am_state *state)
{
int gpgsign;
memset(state, 0, sizeof(*state));
- assert(dir);
- state->dir = xstrdup(dir);
+ state->dir = git_pathdup("rebase-apply");
state->prec = 4;
@@ -762,14 +760,18 @@ static int split_mail_conv(mail_conv_fn fn, struct am_state *state,
mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1);
out = fopen(mail, "w");
- if (!out)
+ if (!out) {
+ if (in != stdin)
+ fclose(in);
return error_errno(_("could not open '%s' for writing"),
mail);
+ }
ret = fn(out, in, keep_cr);
fclose(out);
- fclose(in);
+ if (in != stdin)
+ fclose(in);
if (ret)
return error(_("could not parse patch '%s'"), *paths);
@@ -1049,7 +1051,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
} else {
write_state_text(state, "abort-safety", "");
if (!state->rebasing)
- delete_ref("ORIG_HEAD", NULL, 0);
+ delete_ref(NULL, "ORIG_HEAD", NULL, 0);
}
/*
@@ -1181,42 +1183,39 @@ static void NORETURN die_user_resolve(const struct am_state *state)
exit(128);
}
-static void am_signoff(struct strbuf *sb)
+/**
+ * Appends signoff to the "msg" field of the am_state.
+ */
+static void am_append_signoff(struct am_state *state)
{
char *cp;
struct strbuf mine = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT;
+
+ strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);
- /* Does it end with our own sign-off? */
+ /* our sign-off */
strbuf_addf(&mine, "\n%s%s\n",
sign_off_header,
fmt_name(getenv("GIT_COMMITTER_NAME"),
getenv("GIT_COMMITTER_EMAIL")));
- if (mine.len < sb->len &&
- !strcmp(mine.buf, sb->buf + sb->len - mine.len))
+
+ /* Does sb end with it already? */
+ if (mine.len < sb.len &&
+ !strcmp(mine.buf, sb.buf + sb.len - mine.len))
goto exit; /* no need to duplicate */
/* Does it have any Signed-off-by: in the text */
- for (cp = sb->buf;
+ for (cp = sb.buf;
cp && *cp && (cp = strstr(cp, sign_off_header)) != NULL;
cp = strchr(cp, '\n')) {
- if (sb->buf == cp || cp[-1] == '\n')
+ if (sb.buf == cp || cp[-1] == '\n')
break;
}
- strbuf_addstr(sb, mine.buf + !!cp);
+ strbuf_addstr(&sb, mine.buf + !!cp);
exit:
strbuf_release(&mine);
-}
-
-/**
- * Appends signoff to the "msg" field of the am_state.
- */
-static void am_append_signoff(struct am_state *state)
-{
- struct strbuf sb = STRBUF_INIT;
-
- strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);
- am_signoff(&sb);
state->msg = strbuf_detach(&sb, &state->msg_len);
}
@@ -1313,7 +1312,7 @@ static int parse_mail(struct am_state *state, const char *mail)
}
if (is_empty_file(am_path(state, "patch"))) {
- printf_ln(_("Patch is empty. Was it split wrong?"));
+ printf_ln(_("Patch is empty."));
die_user_resolve(state);
}
@@ -1321,9 +1320,6 @@ static int parse_mail(struct am_state *state, const char *mail)
strbuf_addbuf(&msg, &mi.log_message);
strbuf_stripspace(&msg, 0);
- if (state->signoff)
- am_signoff(&msg);
-
assert(!state->author_name);
state->author_name = strbuf_detach(&author_name, NULL);
@@ -1355,19 +1351,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
struct strbuf sb = STRBUF_INIT;
FILE *fp = xfopen(mail, "r");
const char *x;
+ int ret = 0;
- if (strbuf_getline_lf(&sb, fp))
- return -1;
-
- if (!skip_prefix(sb.buf, "From ", &x))
- return -1;
-
- if (get_oid_hex(x, commit_id) < 0)
- return -1;
+ if (strbuf_getline_lf(&sb, fp) ||
+ !skip_prefix(sb.buf, "From ", &x) ||
+ get_oid_hex(x, commit_id) < 0)
+ ret = -1;
strbuf_release(&sb);
fclose(fp);
- return 0;
+ return ret;
}
/**
@@ -1376,40 +1369,33 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
*/
static void get_commit_info(struct am_state *state, struct commit *commit)
{
- const char *buffer, *ident_line, *author_date, *msg;
+ const char *buffer, *ident_line, *msg;
size_t ident_len;
- struct ident_split ident_split;
- struct strbuf sb = STRBUF_INIT;
+ struct ident_split id;
buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
ident_line = find_commit_header(buffer, "author", &ident_len);
- if (split_ident_line(&ident_split, ident_line, ident_len) < 0) {
- strbuf_add(&sb, ident_line, ident_len);
- die(_("invalid ident line: %s"), sb.buf);
- }
+ if (split_ident_line(&id, ident_line, ident_len) < 0)
+ die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);
assert(!state->author_name);
- if (ident_split.name_begin) {
- strbuf_add(&sb, ident_split.name_begin,
- ident_split.name_end - ident_split.name_begin);
- state->author_name = strbuf_detach(&sb, NULL);
- } else
+ if (id.name_begin)
+ state->author_name =
+ xmemdupz(id.name_begin, id.name_end - id.name_begin);
+ else
state->author_name = xstrdup("");
assert(!state->author_email);
- if (ident_split.mail_begin) {
- strbuf_add(&sb, ident_split.mail_begin,
- ident_split.mail_end - ident_split.mail_begin);
- state->author_email = strbuf_detach(&sb, NULL);
- } else
+ if (id.mail_begin)
+ state->author_email =
+ xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
+ else
state->author_email = xstrdup("");
- author_date = show_ident_date(&ident_split, DATE_MODE(NORMAL));
- strbuf_addstr(&sb, author_date);
assert(!state->author_date);
- state->author_date = strbuf_detach(&sb, NULL);
+ state->author_date = xstrdup(show_ident_date(&id, DATE_MODE(NORMAL)));
assert(!state->msg);
msg = strstr(buffer, "\n\n");
@@ -1417,6 +1403,7 @@ static void get_commit_info(struct am_state *state, struct commit *commit)
die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
state->msg = xstrdup(msg + 2);
state->msg_len = strlen(state->msg);
+ unuse_commit_buffer(commit, buffer);
}
/**
@@ -1848,6 +1835,9 @@ static void am_run(struct am_state *state, int resume)
if (skip)
goto next; /* mail should be skipped */
+ if (state->signoff)
+ am_append_signoff(state);
+
write_author_script(state);
write_commit_msg(state);
}
@@ -1941,7 +1931,8 @@ static void am_resolve(struct am_state *state)
if (unmerged_cache()) {
printf_ln(_("You still have unmerged paths in your index.\n"
- "Did you forget to use 'git add'?"));
+ "You should 'git add' each file with resolved conflicts to mark them as such.\n"
+ "You might run `git rm` on a file to accept \"deleted by them\" for it."));
die_user_resolve(state);
}
@@ -2157,7 +2148,7 @@ static void am_abort(struct am_state *state)
am_rerere_clear();
curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
- has_curr_head = !is_null_oid(&curr_head);
+ has_curr_head = curr_branch && !is_null_oid(&curr_head);
if (!has_curr_head)
hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
@@ -2172,7 +2163,7 @@ static void am_abort(struct am_state *state)
has_curr_head ? &curr_head : NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
else if (curr_branch)
- delete_ref(curr_branch, NULL, REF_NODEREF);
+ delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
free(curr_branch);
am_destroy(state);
@@ -2320,9 +2311,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
OPT_END()
};
+ if (argc == 2 && !strcmp(argv[1], "-h"))
+ usage_with_options(usage, options);
+
git_config(git_am_config, NULL);
- am_state_init(&state, git_path("rebase-apply"));
+ am_state_init(&state);
in_progress = am_in_progress(&state);
if (in_progress)
diff --git a/builtin/blame.c b/builtin/blame.c
index f7aa95f4ba..ca9ebe40e7 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1890,7 +1890,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
int cnt;
const char *cp;
struct origin *suspect = ent->suspect;
- char hex[GIT_SHA1_HEXSZ + 1];
+ char hex[GIT_MAX_HEXSZ + 1];
oid_to_hex_r(hex, &suspect->commit->object.oid);
printf("%s %d %d %d\n",
@@ -1928,7 +1928,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
const char *cp;
struct origin *suspect = ent->suspect;
struct commit_info ci;
- char hex[GIT_SHA1_HEXSZ + 1];
+ char hex[GIT_MAX_HEXSZ + 1];
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
get_commit_info(suspect->commit, &ci, 1);
@@ -2688,12 +2688,15 @@ parse_done:
blame_date_width = sizeof("2006-10-19");
break;
case DATE_RELATIVE:
- /* TRANSLATORS: This string is used to tell us the maximum
- display width for a relative timestamp in "git blame"
- output. For C locale, "4 years, 11 months ago", which
- takes 22 places, is the longest among various forms of
- relative timestamps, but your language may need more or
- fewer display columns. */
+ /*
+ * TRANSLATORS: This string is used to tell us the
+ * maximum display width for a relative timestamp in
+ * "git blame" output. For C locale, "4 years, 11
+ * months ago", which takes 22 places, is the longest
+ * among various forms of relative timestamps, but
+ * your language may need more or fewer display
+ * columns.
+ */
blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
break;
case DATE_NORMAL:
diff --git a/builtin/branch.c b/builtin/branch.c
index babfd0f730..48a513a84d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -28,20 +28,21 @@ static const char * const builtin_branch_usage[] = {
N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
N_("git branch [<options>] [-r | -a] [--points-at]"),
+ N_("git branch [<options>] [-r | -a] [--format]"),
NULL
};
static const char *head;
-static unsigned char head_sha1[20];
+static struct object_id head_oid;
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
GIT_COLOR_RESET,
- GIT_COLOR_NORMAL, /* PLAIN */
- GIT_COLOR_RED, /* REMOTE */
- GIT_COLOR_NORMAL, /* LOCAL */
- GIT_COLOR_GREEN, /* CURRENT */
- GIT_COLOR_BLUE, /* UPSTREAM */
+ GIT_COLOR_NORMAL, /* PLAIN */
+ GIT_COLOR_RED, /* REMOTE */
+ GIT_COLOR_NORMAL, /* LOCAL */
+ GIT_COLOR_GREEN, /* CURRENT */
+ GIT_COLOR_BLUE, /* UPSTREAM */
};
enum color_branch {
BRANCH_COLOR_RESET = 0,
@@ -117,13 +118,13 @@ static int branch_merged(int kind, const char *name,
if (kind == FILTER_REFS_BRANCHES) {
struct branch *branch = branch_get(name);
const char *upstream = branch_get_upstream(branch, NULL);
- unsigned char sha1[20];
+ struct object_id oid;
if (upstream &&
(reference_name = reference_name_to_free =
resolve_refdup(upstream, RESOLVE_REF_READING,
- sha1, NULL)) != NULL)
- reference_rev = lookup_commit_reference(sha1);
+ oid.hash, NULL)) != NULL)
+ reference_rev = lookup_commit_reference(oid.hash);
}
if (!reference_rev)
reference_rev = head_rev;
@@ -153,10 +154,10 @@ static int branch_merged(int kind, const char *name,
}
static int check_branch_commit(const char *branchname, const char *refname,
- const unsigned char *sha1, struct commit *head_rev,
+ const struct object_id *oid, struct commit *head_rev,
int kinds, int force)
{
- struct commit *rev = lookup_commit_reference(sha1);
+ struct commit *rev = lookup_commit_reference(oid->hash);
if (!rev) {
error(_("Couldn't look up commit object for '%s'"), refname);
return -1;
@@ -183,7 +184,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
int quiet)
{
struct commit *head_rev = NULL;
- unsigned char sha1[20];
+ struct object_id oid;
char *name = NULL;
const char *fmt;
int i;
@@ -210,7 +211,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
}
if (!force) {
- head_rev = lookup_commit_reference(head_sha1);
+ head_rev = lookup_commit_reference(head_oid.hash);
if (!head_rev)
die(_("Couldn't look up commit object for HEAD"));
}
@@ -238,7 +239,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
RESOLVE_REF_READING
| RESOLVE_REF_NO_RECURSE
| RESOLVE_REF_ALLOW_BAD_NAME,
- sha1, &flags);
+ oid.hash, &flags);
if (!target) {
error(remote_branch
? _("remote-tracking branch '%s' not found.")
@@ -248,13 +249,13 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
}
if (!(flags & (REF_ISSYMREF|REF_ISBROKEN)) &&
- check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
+ check_branch_commit(bname.buf, name, &oid, head_rev, kinds,
force)) {
ret = 1;
goto next;
}
- if (delete_ref(name, is_null_sha1(sha1) ? NULL : sha1,
+ if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : oid.hash,
REF_NODEREF)) {
error(remote_branch
? _("Error deleting remote-tracking branch '%s'")
@@ -270,7 +271,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
bname.buf,
(flags & REF_ISBROKEN) ? "broken"
: (flags & REF_ISSYMREF) ? target
- : find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ : find_unique_abbrev(oid.hash, DEFAULT_ABBREV));
}
delete_branch_config(bname.buf);
@@ -283,221 +284,109 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
return(ret);
}
-static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
- int show_upstream_ref)
+static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
{
- int ours, theirs;
- char *ref = NULL;
- struct branch *branch = branch_get(branch_name);
- const char *upstream;
- struct strbuf fancy = STRBUF_INIT;
- int upstream_is_gone = 0;
- int added_decoration = 1;
-
- if (stat_tracking_info(branch, &ours, &theirs, &upstream) < 0) {
- if (!upstream)
- return;
- upstream_is_gone = 1;
- }
-
- if (show_upstream_ref) {
- ref = shorten_unambiguous_ref(upstream, 0);
- if (want_color(branch_use_color))
- strbuf_addf(&fancy, "%s%s%s",
- branch_get_color(BRANCH_COLOR_UPSTREAM),
- ref, branch_get_color(BRANCH_COLOR_RESET));
- else
- strbuf_addstr(&fancy, ref);
- }
+ int i, max = 0;
+ for (i = 0; i < refs->nr; i++) {
+ struct ref_array_item *it = refs->items[i];
+ const char *desc = it->refname;
+ int w;
- if (upstream_is_gone) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
- else
- added_decoration = 0;
- } else if (!ours && !theirs) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s]"), fancy.buf);
- else
- added_decoration = 0;
- } else if (!ours) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
- else
- strbuf_addf(stat, _("[behind %d]"), theirs);
+ skip_prefix(it->refname, "refs/heads/", &desc);
+ skip_prefix(it->refname, "refs/remotes/", &desc);
+ if (it->kind == FILTER_REFS_DETACHED_HEAD) {
+ char *head_desc = get_head_description();
+ w = utf8_strwidth(head_desc);
+ free(head_desc);
+ } else
+ w = utf8_strwidth(desc);
- } else if (!theirs) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
- else
- strbuf_addf(stat, _("[ahead %d]"), ours);
- } else {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
- fancy.buf, ours, theirs);
- else
- strbuf_addf(stat, _("[ahead %d, behind %d]"),
- ours, theirs);
+ if (it->kind == FILTER_REFS_REMOTES)
+ w += remote_bonus;
+ if (w > max)
+ max = w;
}
- strbuf_release(&fancy);
- if (added_decoration)
- strbuf_addch(stat, ' ');
- free(ref);
+ return max;
}
-static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
- struct ref_filter *filter, const char *refname)
+static const char *quote_literal_for_format(const char *s)
{
- struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
- const char *sub = _(" **** invalid ref ****");
- struct commit *commit = item->commit;
+ static struct strbuf buf = STRBUF_INIT;
- if (!parse_commit(commit)) {
- pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);
- sub = subject.buf;
+ strbuf_reset(&buf);
+ while (*s) {
+ const char *ep = strchrnul(s, '%');
+ if (s < ep)
+ strbuf_add(&buf, s, ep - s);
+ if (*ep == '%') {
+ strbuf_addstr(&buf, "%%");
+ s = ep + 1;
+ } else {
+ s = ep;
+ }
}
-
- if (item->kind == FILTER_REFS_BRANCHES)
- fill_tracking_info(&stat, refname, filter->verbose > 1);
-
- strbuf_addf(out, " %s %s%s",
- find_unique_abbrev(item->commit->object.oid.hash, filter->abbrev),
- stat.buf, sub);
- strbuf_release(&stat);
- strbuf_release(&subject);
+ return buf.buf;
}
-static char *get_head_description(void)
+static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
{
- struct strbuf desc = STRBUF_INIT;
- struct wt_status_state state;
- memset(&state, 0, sizeof(state));
- wt_status_get_state(&state, 1);
- if (state.rebase_in_progress ||
- state.rebase_interactive_in_progress)
- strbuf_addf(&desc, _("(no branch, rebasing %s)"),
- state.branch);
- else if (state.bisect_in_progress)
- strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
- state.branch);
- else if (state.detached_from) {
- if (state.detached_at)
- /* TRANSLATORS: make sure this matches
- "HEAD detached at " in wt-status.c */
- strbuf_addf(&desc, _("(HEAD detached at %s)"),
- state.detached_from);
- else
- /* TRANSLATORS: make sure this matches
- "HEAD detached from " in wt-status.c */
- strbuf_addf(&desc, _("(HEAD detached from %s)"),
- state.detached_from);
- }
- else
- strbuf_addstr(&desc, _("(no branch)"));
- free(state.branch);
- free(state.onto);
- free(state.detached_from);
- return strbuf_detach(&desc, NULL);
-}
+ struct strbuf fmt = STRBUF_INIT;
+ struct strbuf local = STRBUF_INIT;
+ struct strbuf remote = STRBUF_INIT;
-static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
- struct ref_filter *filter, const char *remote_prefix)
-{
- char c;
- int current = 0;
- int color;
- struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
- const char *prefix_to_show = "";
- const char *prefix_to_skip = NULL;
- const char *desc = item->refname;
- char *to_free = NULL;
+ strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)",
+ branch_get_color(BRANCH_COLOR_CURRENT));
- switch (item->kind) {
- case FILTER_REFS_BRANCHES:
- prefix_to_skip = "refs/heads/";
- skip_prefix(desc, prefix_to_skip, &desc);
- if (!filter->detached && !strcmp(desc, head))
- current = 1;
+ if (filter->verbose) {
+ struct strbuf obname = STRBUF_INIT;
+
+ if (filter->abbrev < 0)
+ strbuf_addf(&obname, "%%(objectname:short)");
+ else if (!filter->abbrev)
+ strbuf_addf(&obname, "%%(objectname)");
else
- color = BRANCH_COLOR_LOCAL;
- break;
- case FILTER_REFS_REMOTES:
- prefix_to_skip = "refs/remotes/";
- skip_prefix(desc, prefix_to_skip, &desc);
- color = BRANCH_COLOR_REMOTE;
- prefix_to_show = remote_prefix;
- break;
- case FILTER_REFS_DETACHED_HEAD:
- desc = to_free = get_head_description();
- current = 1;
- break;
- default:
- color = BRANCH_COLOR_PLAIN;
- break;
- }
+ strbuf_addf(&obname, "%%(objectname:short=%d)", filter->abbrev);
- c = ' ';
- if (current) {
- c = '*';
- color = BRANCH_COLOR_CURRENT;
- }
+ strbuf_addf(&local, "%%(align:%d,left)%%(refname:lstrip=2)%%(end)", maxwidth);
+ strbuf_addf(&local, "%s", branch_get_color(BRANCH_COLOR_RESET));
+ strbuf_addf(&local, " %s ", obname.buf);
- strbuf_addf(&name, "%s%s", prefix_to_show, desc);
- if (filter->verbose) {
- int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
- strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
- maxwidth + utf8_compensation, name.buf,
- branch_get_color(BRANCH_COLOR_RESET));
- } else
- strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
- name.buf, branch_get_color(BRANCH_COLOR_RESET));
-
- if (item->symref) {
- const char *symref = item->symref;
- if (prefix_to_skip)
- skip_prefix(symref, prefix_to_skip, &symref);
- strbuf_addf(&out, " -> %s", symref);
- }
- else if (filter->verbose)
- /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
- add_verbose_info(&out, item, filter, desc);
- if (column_active(colopts)) {
- assert(!filter->verbose && "--column and --verbose are incompatible");
- string_list_append(&output, out.buf);
+ if (filter->verbose > 1)
+ strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
+ "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
+ branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+ else
+ strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
+
+ strbuf_addf(&remote, "%s%%(align:%d,left)%s%%(refname:lstrip=2)%%(end)%s"
+ "%%(if)%%(symref)%%(then) -> %%(symref:short)"
+ "%%(else) %s %%(contents:subject)%%(end)",
+ branch_get_color(BRANCH_COLOR_REMOTE), maxwidth, quote_literal_for_format(remote_prefix),
+ branch_get_color(BRANCH_COLOR_RESET), obname.buf);
+ strbuf_release(&obname);
} else {
- printf("%s\n", out.buf);
+ strbuf_addf(&local, "%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+ branch_get_color(BRANCH_COLOR_RESET));
+ strbuf_addf(&remote, "%s%s%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+ branch_get_color(BRANCH_COLOR_REMOTE), quote_literal_for_format(remote_prefix),
+ branch_get_color(BRANCH_COLOR_RESET));
}
- strbuf_release(&name);
- strbuf_release(&out);
- free(to_free);
-}
-static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
-{
- int i, max = 0;
- for (i = 0; i < refs->nr; i++) {
- struct ref_array_item *it = refs->items[i];
- const char *desc = it->refname;
- int w;
+ strbuf_addf(&fmt, "%%(if:notequals=refs/remotes)%%(refname:rstrip=-2)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
- skip_prefix(it->refname, "refs/heads/", &desc);
- skip_prefix(it->refname, "refs/remotes/", &desc);
- w = utf8_strwidth(desc);
-
- if (it->kind == FILTER_REFS_REMOTES)
- w += remote_bonus;
- if (w > max)
- max = w;
- }
- return max;
+ strbuf_release(&local);
+ strbuf_release(&remote);
+ return strbuf_detach(&fmt, NULL);
}
-static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
{
int i;
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
+ struct strbuf out = STRBUF_INIT;
+ char *to_free = NULL;
/*
* If we are listing more than just remote branches,
@@ -509,18 +398,32 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
memset(&array, 0, sizeof(array));
- verify_ref_format("%(refname)%(symref)");
filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
if (filter->verbose)
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
+ if (!format)
+ format = to_free = build_format(filter, maxwidth, remote_prefix);
+ verify_ref_format(format);
+
ref_array_sort(sorting, &array);
- for (i = 0; i < array.nr; i++)
- format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
+ for (i = 0; i < array.nr; i++) {
+ format_ref_array_item(array.items[i], format, 0, &out);
+ if (column_active(colopts)) {
+ assert(!filter->verbose && "--column and --verbose are incompatible");
+ /* format to a string_list to let print_columns() do its job */
+ string_list_append(&output, out.buf);
+ } else {
+ fwrite(out.buf, 1, out.len, stdout);
+ putchar('\n');
+ }
+ strbuf_release(&out);
+ }
ref_array_clear(&array);
+ free(to_free);
}
static void reject_rebase_or_bisect_branch(const char *target)
@@ -582,14 +485,15 @@ static void rename_branch(const char *oldname, const char *newname, int force)
if (rename_ref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch rename failed"));
- strbuf_release(&logmsg);
if (recovery)
warning(_("Renamed a misnamed branch '%s' away"), oldref.buf + 11);
- if (replace_each_worktree_head_symref(oldref.buf, newref.buf))
+ if (replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
+ strbuf_release(&logmsg);
+
strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11);
strbuf_release(&oldref);
strbuf_addf(&newsection, "branch.%s", newref.buf + 11);
@@ -600,7 +504,7 @@ static void rename_branch(const char *oldname, const char *newname, int force)
strbuf_release(&newsection);
}
-static const char edit_description[] = "BRANCH_DESCRIPTION";
+static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION")
static int edit_branch_description(const char *branch_name)
{
@@ -615,9 +519,9 @@ static int edit_branch_description(const char *branch_name)
" %s\n"
"Lines starting with '%c' will be stripped.\n"),
branch_name, comment_line_char);
- write_file_buf(git_path(edit_description), buf.buf, buf.len);
+ write_file_buf(edit_description(), buf.buf, buf.len);
strbuf_reset(&buf);
- if (launch_editor(git_path(edit_description), &buf, NULL)) {
+ if (launch_editor(edit_description(), &buf, NULL)) {
strbuf_release(&buf);
return -1;
}
@@ -641,6 +545,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
struct ref_filter filter;
int icase = 0;
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
+ const char *format = NULL;
struct option options[] = {
OPT_GROUP(N_("Generic options")),
@@ -657,7 +562,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_SET_INT('r', "remotes", &filter.kind, N_("act on remote-tracking branches"),
FILTER_REFS_REMOTES),
OPT_CONTAINS(&filter.with_commit, N_("print only branches that contain the commit")),
+ OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches that don't contain the commit")),
OPT_WITH(&filter.with_commit, N_("print only branches that contain the commit")),
+ OPT_WITHOUT(&filter.no_commit, N_("print only branches that don't contain the commit")),
OPT__ABBREV(&filter.abbrev),
OPT_GROUP(N_("Specific git-branch actions:")),
@@ -682,9 +589,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
N_("print only branches of the object"), 0, parse_opt_object_name
},
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+ OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
OPT_END(),
};
+ setup_ref_filter_porcelain_msg();
+
memset(&filter, 0, sizeof(filter));
filter.kind = FILTER_REFS_BRANCHES;
filter.abbrev = -1;
@@ -696,7 +606,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
track = git_branch_track;
- head = resolve_refdup("HEAD", 0, head_sha1, NULL);
+ head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
if (!strcmp(head, "HEAD"))
@@ -710,7 +620,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
list = 1;
- if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr)
+ if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr ||
+ filter.no_commit)
list = 1;
if (!!delete + !!rename + !!new_upstream +
@@ -752,7 +663,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!sorting)
sorting = ref_default_sorting();
sorting->ignore_case = icase;
- print_ref_list(&filter, sorting);
+ print_ref_list(&filter, sorting, format);
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
return 0;
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 4883a435a9..d0de59b94f 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -20,21 +20,15 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
struct bundle_header header;
const char *cmd, *bundle_file;
int bundle_fd = -1;
- char buffer[PATH_MAX];
if (argc < 3)
usage(builtin_bundle_usage);
cmd = argv[1];
- bundle_file = argv[2];
+ bundle_file = prefix_filename(prefix, argv[2]);
argc -= 2;
argv += 2;
- if (prefix && bundle_file[0] != '/') {
- snprintf(buffer, sizeof(buffer), "%s/%s", prefix, bundle_file);
- bundle_file = buffer;
- }
-
memset(&header, 0, sizeof(header));
if (strcmp(cmd, "create") && (bundle_fd =
read_bundle_header(bundle_file, &header)) < 0)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 30383e9eb4..9af863e791 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
die("git cat-file %s: bad file", obj_name);
write_or_die(1, buf, size);
+ free(buf);
return 0;
}
@@ -401,28 +402,28 @@ struct object_cb_data {
struct expand_data *expand;
};
-static int batch_object_cb(const unsigned char sha1[20], void *vdata)
+static int batch_object_cb(const struct object_id *oid, void *vdata)
{
struct object_cb_data *data = vdata;
- hashcpy(data->expand->oid.hash, sha1);
+ oidcpy(&data->expand->oid, oid);
batch_object_write(NULL, data->opt, data->expand);
return 0;
}
-static int batch_loose_object(const unsigned char *sha1,
+static int batch_loose_object(const struct object_id *oid,
const char *path,
void *data)
{
- sha1_array_append(data, sha1);
+ oid_array_append(data, oid);
return 0;
}
-static int batch_packed_object(const unsigned char *sha1,
+static int batch_packed_object(const struct object_id *oid,
struct packed_git *pack,
uint32_t pos,
void *data)
{
- sha1_array_append(data, sha1);
+ oid_array_append(data, oid);
return 0;
}
@@ -462,7 +463,7 @@ static int batch_objects(struct batch_options *opt)
data.info.typep = &data.type;
if (opt->all_objects) {
- struct sha1_array sa = SHA1_ARRAY_INIT;
+ struct oid_array sa = OID_ARRAY_INIT;
struct object_cb_data cb;
for_each_loose_object(batch_loose_object, &sa, 0);
@@ -470,9 +471,9 @@ static int batch_objects(struct batch_options *opt)
cb.opt = opt;
cb.expand = &data;
- sha1_array_for_each_unique(&sa, batch_object_cb, &cb);
+ oid_array_for_each_unique(&sa, batch_object_cb, &cb);
- sha1_array_clear(&sa);
+ oid_array_clear(&sa);
return 0;
}
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 53a5a18c16..4d01ca0c8b 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -24,12 +24,13 @@ static const struct option check_attr_options[] = {
OPT_END()
};
-static void output_attr(int cnt, struct git_attr_check *check,
- const char *file)
+static void output_attr(struct attr_check *check, const char *file)
{
int j;
+ int cnt = check->nr;
+
for (j = 0; j < cnt; j++) {
- const char *value = check[j].value;
+ const char *value = check->items[j].value;
if (ATTR_TRUE(value))
value = "set";
@@ -42,35 +43,38 @@ static void output_attr(int cnt, struct git_attr_check *check,
printf("%s%c" /* path */
"%s%c" /* attrname */
"%s%c" /* attrvalue */,
- file, 0, git_attr_name(check[j].attr), 0, value, 0);
+ file, 0,
+ git_attr_name(check->items[j].attr), 0, value, 0);
} else {
quote_c_style(file, NULL, stdout, 0);
- printf(": %s: %s\n", git_attr_name(check[j].attr), value);
+ printf(": %s: %s\n",
+ git_attr_name(check->items[j].attr), value);
}
-
}
}
-static void check_attr(const char *prefix, int cnt,
- struct git_attr_check *check, const char *file)
+static void check_attr(const char *prefix,
+ struct attr_check *check,
+ int collect_all,
+ const char *file)
{
char *full_path =
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
- if (check != NULL) {
- if (git_check_attr(full_path, cnt, check))
- die("git_check_attr died");
- output_attr(cnt, check, file);
+
+ if (collect_all) {
+ git_all_attrs(full_path, check);
} else {
- if (git_all_attrs(full_path, &cnt, &check))
- die("git_all_attrs died");
- output_attr(cnt, check, file);
- free(check);
+ if (git_check_attr(full_path, check))
+ die("git_check_attr died");
}
+ output_attr(check, file);
+
free(full_path);
}
-static void check_attr_stdin_paths(const char *prefix, int cnt,
- struct git_attr_check *check)
+static void check_attr_stdin_paths(const char *prefix,
+ struct attr_check *check,
+ int collect_all)
{
struct strbuf buf = STRBUF_INIT;
struct strbuf unquoted = STRBUF_INIT;
@@ -84,7 +88,7 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,
die("line is badly quoted");
strbuf_swap(&buf, &unquoted);
}
- check_attr(prefix, cnt, check, buf.buf);
+ check_attr(prefix, check, collect_all, buf.buf);
maybe_flush_or_die(stdout, "attribute to stdout");
}
strbuf_release(&buf);
@@ -99,7 +103,7 @@ static NORETURN void error_with_usage(const char *msg)
int cmd_check_attr(int argc, const char **argv, const char *prefix)
{
- struct git_attr_check *check;
+ struct attr_check *check;
int cnt, i, doubledash, filei;
if (!is_bare_repository())
@@ -159,28 +163,26 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
error_with_usage("No file specified");
}
- if (all_attrs) {
- check = NULL;
- } else {
- check = xcalloc(cnt, sizeof(*check));
+ check = attr_check_alloc();
+ if (!all_attrs) {
for (i = 0; i < cnt; i++) {
- const char *name;
- struct git_attr *a;
- name = argv[i];
- a = git_attr(name);
+ const struct git_attr *a = git_attr(argv[i]);
+
if (!a)
return error("%s: not a valid attribute name",
- name);
- check[i].attr = a;
+ argv[i]);
+ attr_check_append(check, a);
}
}
if (stdin_paths)
- check_attr_stdin_paths(prefix, cnt, check);
+ check_attr_stdin_paths(prefix, check, all_attrs);
else {
for (i = filei; i < argc; i++)
- check_attr(prefix, cnt, check, argv[i]);
+ check_attr(prefix, check, all_attrs, argv[i]);
maybe_flush_or_die(stdout, "attribute to stdout");
}
+
+ attr_check_free(check);
return 0;
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 81f07c3ef2..b360943455 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -21,12 +21,31 @@
#include "submodule-config.h"
#include "submodule.h"
+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
N_("git checkout [<options>] [<branch>] -- <file>..."),
NULL,
};
+static int option_parse_recurse_submodules(const struct option *opt,
+ const char *arg, int unset)
+{
+ if (unset) {
+ recurse_submodules = RECURSE_SUBMODULES_OFF;
+ return 0;
+ }
+ if (arg)
+ recurse_submodules =
+ parse_update_recurse_submodules_arg(opt->long_name,
+ arg);
+ else
+ recurse_submodules = RECURSE_SUBMODULES_ON;
+
+ return 0;
+}
+
struct checkout_opts {
int patch_mode;
int quiet;
@@ -216,22 +235,24 @@ static int checkout_merged(int pos, const struct checkout *state)
/*
* NEEDSWORK:
* There is absolutely no reason to write this as a blob object
- * and create a phony cache entry just to leak. This hack is
- * primarily to get to the write_entry() machinery that massages
- * the contents to work-tree format and writes out which only
- * allows it for a cache entry. The code in write_entry() needs
- * to be refactored to allow us to feed a <buffer, size, mode>
- * instead of a cache entry. Such a refactoring would help
- * merge_recursive as well (it also writes the merge result to the
- * object database even when it may contain conflicts).
+ * and create a phony cache entry. This hack is primarily to get
+ * to the write_entry() machinery that massages the contents to
+ * work-tree format and writes out which only allows it for a
+ * cache entry. The code in write_entry() needs to be refactored
+ * to allow us to feed a <buffer, size, mode> instead of a cache
+ * entry. Such a refactoring would help merge_recursive as well
+ * (it also writes the merge result to the object database even
+ * when it may contain conflicts).
*/
if (write_sha1_file(result_buf.ptr, result_buf.size,
blob_type, oid.hash))
die(_("Unable to add merge result for '%s'"), path);
+ free(result_buf.ptr);
ce = make_cache_entry(mode, oid.hash, path, 2, 0);
if (!ce)
die(_("make_cache_entry failed for path '%s'"), path);
status = checkout_entry(ce, state, NULL);
+ free(ce);
return status;
}
@@ -814,7 +835,8 @@ static int switch_branches(const struct checkout_opts *opts,
int flag, writeout_error = 0;
memset(&old, 0, sizeof(old));
old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
- old.commit = lookup_commit_reference_gently(rev.hash, 1);
+ if (old.path)
+ old.commit = lookup_commit_reference_gently(rev.hash, 1);
if (!(flag & REF_ISSYMREF))
old.path = NULL;
@@ -889,11 +911,10 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
static const char *unique_tracking_name(const char *name, struct object_id *oid)
{
struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
- char src_ref[PATH_MAX];
- snprintf(src_ref, PATH_MAX, "refs/heads/%s", name);
- cb_data.src_ref = src_ref;
+ cb_data.src_ref = xstrfmt("refs/heads/%s", name);
cb_data.dst_oid = oid;
for_each_remote(check_tracking_name, &cb_data);
+ free(cb_data.src_ref);
if (cb_data.unique)
return cb_data.dst_ref;
free(cb_data.dst_ref);
@@ -1163,6 +1184,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
N_("second guess 'git checkout <no-such-branch>'")),
OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
N_("do not check if another worktree is holding the given ref")),
+ { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
+ "checkout", "control recursive updating of submodules",
+ PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
OPT_END(),
};
@@ -1193,6 +1217,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
}
+ if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
+ git_config(submodule_config, NULL);
+ if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
+ set_config_update_recurse_submodules(recurse_submodules);
+ }
+
if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
die(_("-b, -B and --orphan are mutually exclusive"));
@@ -1259,9 +1289,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
* new_branch && argc > 1 will be caught later.
*/
if (opts.new_branch && argc == 1)
- die(_("Cannot update paths and switch to branch '%s' at the same time.\n"
- "Did you intend to checkout '%s' which can not be resolved as commit?"),
- opts.new_branch, argv[0]);
+ die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
+ argv[0], opts.new_branch);
if (opts.force_detach)
die(_("git checkout: --detach does not take a path argument '%s'"),
diff --git a/builtin/clean.c b/builtin/clean.c
index d6bc3aaaea..d861f836a2 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -174,8 +174,10 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
/* an empty dir could be removed even if it is unreadble */
res = dry_run ? 0 : rmdir(path->buf);
if (res) {
+ int saved_errno = errno;
quote_path_relative(path->buf, prefix, &quoted);
- warning(_(msg_warn_remove_failed), quoted.buf);
+ errno = saved_errno;
+ warning_errno(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
}
return res;
@@ -208,8 +210,10 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
quote_path_relative(path->buf, prefix, &quoted);
string_list_append(&dels, quoted.buf);
} else {
+ int saved_errno = errno;
quote_path_relative(path->buf, prefix, &quoted);
- warning(_(msg_warn_remove_failed), quoted.buf);
+ errno = saved_errno;
+ warning_errno(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
ret = 1;
}
@@ -230,8 +234,10 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
if (!res)
*dir_gone = 1;
else {
+ int saved_errno = errno;
quote_path_relative(path->buf, prefix, &quoted);
- warning(_(msg_warn_remove_failed), quoted.buf);
+ errno = saved_errno;
+ warning_errno(_(msg_warn_remove_failed), quoted.buf);
*dir_gone = 0;
ret = 1;
}
@@ -981,8 +987,10 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
} else {
res = dry_run ? 0 : unlink(abs_path.buf);
if (res) {
+ int saved_errno = errno;
qname = quote_path_relative(item->string, NULL, &buf);
- warning(_(msg_warn_remove_failed), qname);
+ errno = saved_errno;
+ warning_errno(_(msg_warn_remove_failed), qname);
errors++;
} else if (!quiet) {
qname = quote_path_relative(item->string, NULL, &buf);
diff --git a/builtin/clone.c b/builtin/clone.c
index 3f63edbbf9..a6ae7d6180 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -39,7 +39,7 @@ static const char * const builtin_clone_usage[] = {
};
static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
-static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
+static int option_local = -1, option_no_hardlinks, option_shared;
static int option_shallow_submodules;
static int deepen;
static char *option_template, *option_depth, *option_since;
@@ -56,6 +56,21 @@ static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
static int option_dissociate;
static int max_jobs = -1;
+static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
+
+static int recurse_submodules_cb(const struct option *opt,
+ const char *arg, int unset)
+{
+ if (unset)
+ string_list_clear((struct string_list *)opt->value, 0);
+ else if (arg)
+ string_list_append((struct string_list *)opt->value, arg);
+ else
+ string_list_append((struct string_list *)opt->value,
+ (const char *)opt->defval);
+
+ return 0;
+}
static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
@@ -74,10 +89,13 @@ static struct option builtin_clone_options[] = {
N_("don't use local hardlinks, always copy")),
OPT_BOOL('s', "shared", &option_shared,
N_("setup as shared repository")),
- OPT_BOOL(0, "recursive", &option_recursive,
- N_("initialize submodules in the clone")),
- OPT_BOOL(0, "recurse-submodules", &option_recursive,
- N_("initialize submodules in the clone")),
+ { OPTION_CALLBACK, 0, "recursive", &option_recurse_submodules,
+ N_("pathspec"), N_("initialize submodules in the clone"),
+ PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, recurse_submodules_cb,
+ (intptr_t)"." },
+ { OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules,
+ N_("pathspec"), N_("initialize submodules in the clone"),
+ PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." },
OPT_INTEGER('j', "jobs", &max_jobs,
N_("number of submodules cloned in parallel")),
OPT_STRING(0, "template", &option_template, N_("template-directory"),
@@ -681,7 +699,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
static int checkout(int submodule_progress)
{
- unsigned char sha1[20];
+ struct object_id oid;
char *head;
struct lock_file *lock_file;
struct unpack_trees_options opts;
@@ -692,7 +710,7 @@ static int checkout(int submodule_progress)
if (option_no_checkout)
return 0;
- head = resolve_refdup("HEAD", RESOLVE_REF_READING, sha1, NULL);
+ head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL);
if (!head) {
warning(_("remote HEAD refers to nonexistent ref, "
"unable to checkout.\n"));
@@ -700,7 +718,7 @@ static int checkout(int submodule_progress)
}
if (!strcmp(head, "HEAD")) {
if (advice_detached_head)
- detach_advice(sha1_to_hex(sha1));
+ detach_advice(oid_to_hex(&oid));
} else {
if (!starts_with(head, "refs/heads/"))
die(_("HEAD not found below refs/heads!"));
@@ -721,7 +739,7 @@ static int checkout(int submodule_progress)
opts.src_index = &the_index;
opts.dst_index = &the_index;
- tree = parse_tree_indirect(sha1);
+ tree = parse_tree_indirect(oid.hash);
parse_tree(tree);
init_tree_desc(&t, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts) < 0)
@@ -731,9 +749,9 @@ static int checkout(int submodule_progress)
die(_("unable to write new index file"));
err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
- sha1_to_hex(sha1), "1", NULL);
+ oid_to_hex(&oid), "1", NULL);
- if (!err && option_recursive) {
+ if (!err && (option_recurse_submodules.nr > 0)) {
struct argv_array args = ARGV_ARRAY_INIT;
argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL);
@@ -755,7 +773,9 @@ static int checkout(int submodule_progress)
static int write_one_config(const char *key, const char *value, void *data)
{
- return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0);
+ return git_config_set_multivar_gently(key,
+ value ? value : "true",
+ CONFIG_REGEX_NONE, 0);
}
static void write_config(struct string_list *config)
@@ -957,7 +977,25 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
fprintf(stderr, _("Cloning into '%s'...\n"), dir);
}
- if (option_recursive) {
+ if (option_recurse_submodules.nr > 0) {
+ struct string_list_item *item;
+ struct strbuf sb = STRBUF_INIT;
+
+ /* remove duplicates */
+ string_list_sort(&option_recurse_submodules);
+ string_list_remove_duplicates(&option_recurse_submodules, 0);
+
+ /*
+ * NEEDSWORK: In a multi-working-tree world, this needs to be
+ * set in the per-worktree config.
+ */
+ for_each_string_list_item(item, &option_recurse_submodules) {
+ strbuf_addf(&sb, "submodule.active=%s",
+ item->string);
+ string_list_append(&option_config,
+ strbuf_detach(&sb, NULL));
+ }
+
if (option_required_reference.nr &&
option_optional_reference.nr)
die(_("clone --recursive is not compatible with "
diff --git a/builtin/commit.c b/builtin/commit.c
index 2de5f6cc64..8d1cac0629 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -496,7 +496,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
struct wt_status *s)
{
- unsigned char sha1[20];
+ struct object_id oid;
if (s->relative_paths)
s->prefix = prefix;
@@ -509,9 +509,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
s->index_file = index_file;
s->fp = fp;
s->nowarn = nowarn;
- s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
+ s->is_initial = get_sha1(s->reference, oid.hash) ? 1 : 0;
if (!s->is_initial)
- hashcpy(s->sha1_commit, sha1);
+ hashcpy(s->sha1_commit, oid.hash);
s->status_format = status_format;
s->ignore_submodule_arg = ignore_submodule_arg;
@@ -821,9 +821,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
"If this is not correct, please remove the file\n"
" %s\n"
"and try again.\n"),
- git_path(whence == FROM_MERGE
- ? "MERGE_HEAD"
- : "CHERRY_PICK_HEAD"));
+ whence == FROM_MERGE ?
+ git_path_merge_head() :
+ git_path_cherry_pick_head());
}
fprintf(s->fp, "\n");
@@ -885,7 +885,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
commitable = run_status(s->fp, index_file, prefix, 1, s);
s->use_color = saved_color_setting;
} else {
- unsigned char sha1[20];
+ struct object_id oid;
const char *parent = "HEAD";
if (!active_nr && read_cache() < 0)
@@ -894,7 +894,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (amend)
parent = "HEAD^1";
- if (get_sha1(parent, sha1)) {
+ if (get_sha1(parent, oid.hash)) {
int i, ita_nr = 0;
for (i = 0; i < active_nr; i++)
@@ -1332,7 +1332,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
{
static struct wt_status s;
int fd;
- unsigned char sha1[20];
+ struct object_id oid;
static struct option builtin_status_options[] = {
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_SET_INT('s', "short", &status_format,
@@ -1382,9 +1382,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
fd = hold_locked_index(&index_lock, 0);
- s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
+ s.is_initial = get_sha1(s.reference, oid.hash) ? 1 : 0;
if (!s.is_initial)
- hashcpy(s.sha1_commit, sha1);
+ hashcpy(s.sha1_commit, oid.hash);
s.ignore_submodule_arg = ignore_submodule_arg;
s.status_format = status_format;
@@ -1404,7 +1404,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
static const char *implicit_ident_advice(void)
{
- char *user_config = expand_user_path("~/.gitconfig");
+ char *user_config = expand_user_path("~/.gitconfig", 0);
char *xdg_config = xdg_config_home("config");
int config_exists = file_exists(user_config) || file_exists(xdg_config);
@@ -1418,19 +1418,19 @@ static const char *implicit_ident_advice(void)
}
-static void print_summary(const char *prefix, const unsigned char *sha1,
+static void print_summary(const char *prefix, const struct object_id *oid,
int initial_commit)
{
struct rev_info rev;
struct commit *commit;
struct strbuf format = STRBUF_INIT;
- unsigned char junk_sha1[20];
+ struct object_id junk_oid;
const char *head;
struct pretty_print_context pctx = {0};
struct strbuf author_ident = STRBUF_INIT;
struct strbuf committer_ident = STRBUF_INIT;
- commit = lookup_commit(sha1);
+ commit = lookup_commit(oid->hash);
if (!commit)
die(_("couldn't look up newly created commit"));
if (parse_commit(commit))
@@ -1477,7 +1477,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
rev.diffopt.break_opt = 0;
diff_setup_done(&rev.diffopt);
- head = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL);
+ head = resolve_ref_unsafe("HEAD", 0, junk_oid.hash, NULL);
if (!strcmp(head, "HEAD"))
head = _("detached HEAD");
else
@@ -1522,8 +1522,8 @@ static int git_commit_config(const char *k, const char *v, void *cb)
return git_status_config(k, v, s);
}
-static int run_rewrite_hook(const unsigned char *oldsha1,
- const unsigned char *newsha1)
+static int run_rewrite_hook(const struct object_id *oldoid,
+ const struct object_id *newoid)
{
struct child_process proc = CHILD_PROCESS_INIT;
const char *argv[3];
@@ -1544,7 +1544,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
code = start_command(&proc);
if (code)
return code;
- strbuf_addf(&sb, "%s %s\n", sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
+ strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
sigchain_push(SIGPIPE, SIG_IGN);
write_in_full(proc.in, sb.buf, sb.len);
close(proc.in);
@@ -1636,7 +1636,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct strbuf author_ident = STRBUF_INIT;
const char *index_file, *reflog_msg;
char *nl;
- unsigned char sha1[20];
+ struct object_id oid;
struct commit_list *parents = NULL;
struct stat statbuf;
struct commit *current_head = NULL;
@@ -1651,10 +1651,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
s.colopts = 0;
- if (get_sha1("HEAD", sha1))
+ if (get_sha1("HEAD", oid.hash))
current_head = NULL;
else {
- current_head = lookup_commit_or_die(sha1, "HEAD");
+ current_head = lookup_commit_or_die(oid.hash, "HEAD");
if (parse_commit(current_head))
die(_("could not parse HEAD commit"));
}
@@ -1735,7 +1735,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (verbose || /* Truncate the message just before the diff, if any. */
cleanup_mode == CLEANUP_SCISSORS)
- wt_status_truncate_message_at_cut_line(&sb);
+ strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
if (cleanup_mode != CLEANUP_NONE)
strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
@@ -1759,7 +1759,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1,
- parents, sha1, author_ident.buf, sign_commit, extra)) {
+ parents, oid.hash, author_ident.buf, sign_commit, extra)) {
rollback_index_files();
die(_("failed to write commit object"));
}
@@ -1776,7 +1776,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, "HEAD", sha1,
+ ref_transaction_update(transaction, "HEAD", oid.hash,
current_head
? current_head->object.oid.hash : null_sha1,
0, sb.buf, &err) ||
@@ -1805,13 +1805,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
cfg = init_copy_notes_for_rewrite("amend");
if (cfg) {
/* we are amending, so current_head is not NULL */
- copy_note_for_rewrite(cfg, current_head->object.oid.hash, sha1);
+ copy_note_for_rewrite(cfg, current_head->object.oid.hash, oid.hash);
finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
}
- run_rewrite_hook(current_head->object.oid.hash, sha1);
+ run_rewrite_hook(&current_head->object.oid, &oid);
}
if (!quiet)
- print_summary(prefix, sha1, !current_head);
+ print_summary(prefix, &oid, !current_head);
strbuf_release(&err);
return 0;
diff --git a/builtin/config.c b/builtin/config.c
index 05843a0f96..3a554ad50c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -26,7 +26,8 @@ static int use_global_config, use_system_config, use_local_config;
static struct git_config_source given_config_source;
static int actions, types;
static int end_null;
-static int respect_includes = -1;
+static int respect_includes_opt = -1;
+static struct config_options config_options;
static int show_origin;
#define ACTION_GET (1<<0)
@@ -81,7 +82,7 @@ static struct option builtin_config_options[] = {
OPT_GROUP(N_("Other")),
OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
- OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
+ OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
OPT_END(),
};
@@ -242,7 +243,7 @@ static int get_value(const char *key_, const char *regex_)
}
git_config_with_options(collect_config, &values,
- &given_config_source, respect_includes);
+ &given_config_source, &config_options);
ret = !values.nr;
@@ -320,7 +321,7 @@ static void get_color(const char *var, const char *def_color)
get_color_found = 0;
parsed_color[0] = '\0';
git_config_with_options(git_get_color_config, NULL,
- &given_config_source, respect_includes);
+ &given_config_source, &config_options);
if (!get_color_found && def_color) {
if (color_parse(def_color, parsed_color) < 0)
@@ -352,7 +353,7 @@ static int get_colorbool(const char *var, int print)
get_diff_color_found = -1;
get_color_ui_found = -1;
git_config_with_options(git_get_colorbool_config, NULL,
- &given_config_source, respect_includes);
+ &given_config_source, &config_options);
if (get_colorbool_found < 0) {
if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -441,7 +442,7 @@ static int get_urlmatch(const char *var, const char *url)
}
git_config_with_options(urlmatch_config_entry, &config,
- &given_config_source, respect_includes);
+ &given_config_source, &config_options);
ret = !values.nr;
@@ -502,7 +503,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
if (use_global_config) {
- char *user_config = expand_user_path("~/.gitconfig");
+ char *user_config = expand_user_path("~/.gitconfig", 0);
char *xdg_config = xdg_config_home("config");
if (!user_config)
@@ -527,13 +528,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
else if (given_config_source.file) {
if (!is_absolute_path(given_config_source.file) && prefix)
given_config_source.file =
- xstrdup(prefix_filename(prefix,
- strlen(prefix),
- given_config_source.file));
+ prefix_filename(prefix, given_config_source.file);
}
- if (respect_includes == -1)
- respect_includes = !given_config_source.file;
+ if (respect_includes_opt == -1)
+ config_options.respect_includes = !given_config_source.file;
+ else
+ config_options.respect_includes = respect_includes_opt;
if (end_null) {
term = '\0';
@@ -580,7 +581,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 0, 0);
if (git_config_with_options(show_all_config, NULL,
&given_config_source,
- respect_includes) < 0) {
+ &config_options) < 0) {
if (given_config_source.file)
die_errno("unable to read config file '%s'",
given_config_source.file);
@@ -599,8 +600,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (given_config_source.blob)
die("editing blobs is not supported");
git_config(git_default_config, NULL);
- config_file = xstrdup(given_config_source.file ?
- given_config_source.file : git_path("config"));
+ config_file = given_config_source.file ?
+ xstrdup(given_config_source.file) :
+ git_pathdup("config");
if (use_global_config) {
int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd >= 0) {
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index a04b4f2ef3..acb05940fc 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -53,7 +53,7 @@ static void loose_garbage(const char *path)
report_garbage(PACKDIR_FILE_GARBAGE, path);
}
-static int count_loose(const unsigned char *sha1, const char *path, void *data)
+static int count_loose(const struct object_id *oid, const char *path, void *data)
{
struct stat st;
@@ -62,7 +62,7 @@ static int count_loose(const unsigned char *sha1, const char *path, void *data)
else {
loose_size += on_disk_bytes(st);
loose++;
- if (verbose && has_sha1_pack(sha1))
+ if (verbose && has_sha1_pack(oid->hash))
packed_loose++;
}
return 0;
diff --git a/builtin/describe.c b/builtin/describe.c
index 01490a157e..a5cd8c513f 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -9,6 +9,7 @@
#include "diff.h"
#include "hashmap.h"
#include "argv-array.h"
+#include "run-command.h"
#define SEEN (1u << 0)
#define MAX_TAGS (FLAG_BITS - 1)
@@ -28,9 +29,10 @@ static int abbrev = -1; /* unspecified */
static int max_candidates = 10;
static struct hashmap names;
static int have_util;
-static const char *pattern;
+static struct string_list patterns = STRING_LIST_INIT_NODUP;
+static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
static int always;
-static const char *dirty;
+static const char *suffix, *dirty, *broken;
/* diff-index command arguments to check if working tree is dirty. */
static const char *diff_index_args[] = {
@@ -39,32 +41,32 @@ static const char *diff_index_args[] = {
struct commit_name {
struct hashmap_entry entry;
- unsigned char peeled[20];
+ struct object_id peeled;
struct tag *tag;
unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
unsigned name_checked:1;
- unsigned char sha1[20];
+ struct object_id oid;
char *path;
};
static const char *prio_names[] = {
- "head", "lightweight", "annotated",
+ N_("head"), N_("lightweight"), N_("annotated"),
};
static int commit_name_cmp(const struct commit_name *cn1,
const struct commit_name *cn2, const void *peeled)
{
- return hashcmp(cn1->peeled, peeled ? peeled : cn2->peeled);
+ return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
}
-static inline struct commit_name *find_commit_name(const unsigned char *peeled)
+static inline struct commit_name *find_commit_name(const struct object_id *peeled)
{
- return hashmap_get_from_hash(&names, sha1hash(peeled), peeled);
+ return hashmap_get_from_hash(&names, sha1hash(peeled->hash), peeled->hash);
}
static int replace_name(struct commit_name *e,
int prio,
- const unsigned char *sha1,
+ const struct object_id *oid,
struct tag **tag)
{
if (!e || e->prio < prio)
@@ -77,13 +79,13 @@ static int replace_name(struct commit_name *e,
struct tag *t;
if (!e->tag) {
- t = lookup_tag(e->sha1);
+ t = lookup_tag(e->oid.hash);
if (!t || parse_tag(t))
return 1;
e->tag = t;
}
- t = lookup_tag(sha1);
+ t = lookup_tag(oid->hash);
if (!t || parse_tag(t))
return 0;
*tag = t;
@@ -96,24 +98,24 @@ static int replace_name(struct commit_name *e,
}
static void add_to_known_names(const char *path,
- const unsigned char *peeled,
+ const struct object_id *peeled,
int prio,
- const unsigned char *sha1)
+ const struct object_id *oid)
{
struct commit_name *e = find_commit_name(peeled);
struct tag *tag = NULL;
- if (replace_name(e, prio, sha1, &tag)) {
+ if (replace_name(e, prio, oid, &tag)) {
if (!e) {
e = xmalloc(sizeof(struct commit_name));
- hashcpy(e->peeled, peeled);
- hashmap_entry_init(e, sha1hash(peeled));
+ oidcpy(&e->peeled, peeled);
+ hashmap_entry_init(e, sha1hash(peeled->hash));
hashmap_add(&names, e);
e->path = NULL;
}
e->tag = tag;
e->prio = prio;
e->name_checked = 0;
- hashcpy(e->sha1, sha1);
+ oidcpy(&e->oid, oid);
free(e->path);
e->path = xstrdup(path);
}
@@ -129,9 +131,40 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
if (!all && !is_tag)
return 0;
- /* Accept only tags that match the pattern, if given */
- if (pattern && (!is_tag || wildmatch(pattern, path + 10, 0, NULL)))
- return 0;
+ /*
+ * If we're given exclude patterns, first exclude any tag which match
+ * any of the exclude pattern.
+ */
+ if (exclude_patterns.nr) {
+ struct string_list_item *item;
+
+ if (!is_tag)
+ return 0;
+
+ for_each_string_list_item(item, &exclude_patterns) {
+ if (!wildmatch(item->string, path + 10, 0, NULL))
+ return 0;
+ }
+ }
+
+ /*
+ * If we're given patterns, accept only tags which match at least one
+ * pattern.
+ */
+ if (patterns.nr) {
+ struct string_list_item *item;
+
+ if (!is_tag)
+ return 0;
+
+ for_each_string_list_item(item, &patterns) {
+ if (!wildmatch(item->string, path + 10, 0, NULL))
+ break;
+
+ /* If we get here, no pattern matched. */
+ return 0;
+ }
+ }
/* Is it annotated? */
if (!peel_ref(path, peeled.hash)) {
@@ -154,7 +187,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
else
prio = 0;
- add_to_known_names(all ? path + 5 : path + 10, peeled.hash, prio, oid->hash);
+ add_to_known_names(all ? path + 5 : path + 10, &peeled, prio, oid);
return 0;
}
@@ -212,7 +245,7 @@ static unsigned long finish_depth_computation(
static void display_name(struct commit_name *n)
{
if (n->prio == 2 && !n->tag) {
- n->tag = lookup_tag(n->sha1);
+ n->tag = lookup_tag(n->oid.hash);
if (!n->tag || parse_tag(n->tag))
die(_("annotated tag %s not available"), n->path);
}
@@ -230,14 +263,14 @@ static void display_name(struct commit_name *n)
printf("%s", n->path);
}
-static void show_suffix(int depth, const unsigned char *sha1)
+static void show_suffix(int depth, const struct object_id *oid)
{
- printf("-%d-g%s", depth, find_unique_abbrev(sha1, abbrev));
+ printf("-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
}
static void describe(const char *arg, int last_one)
{
- unsigned char sha1[20];
+ struct object_id oid;
struct commit *cmit, *gave_up_on = NULL;
struct commit_list *list;
struct commit_name *n;
@@ -246,22 +279,22 @@ static void describe(const char *arg, int last_one)
unsigned long seen_commits = 0;
unsigned int unannotated_cnt = 0;
- if (get_sha1(arg, sha1))
+ if (get_oid(arg, &oid))
die(_("Not a valid object name %s"), arg);
- cmit = lookup_commit_reference(sha1);
+ cmit = lookup_commit_reference(oid.hash);
if (!cmit)
die(_("%s is not a valid '%s' object"), arg, commit_type);
- n = find_commit_name(cmit->object.oid.hash);
+ n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
/*
* Exact match to an existing ref.
*/
display_name(n);
if (longformat)
- show_suffix(0, n->tag ? n->tag->tagged->oid.hash : sha1);
- if (dirty)
- printf("%s", dirty);
+ show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid);
+ if (suffix)
+ printf("%s", suffix);
printf("\n");
return;
}
@@ -276,7 +309,7 @@ static void describe(const char *arg, int last_one)
struct commit *c;
struct commit_name *n = hashmap_iter_first(&names, &iter);
for (; n; n = hashmap_iter_next(&iter)) {
- c = lookup_commit_reference_gently(n->peeled, 1);
+ c = lookup_commit_reference_gently(n->peeled.hash, 1);
if (c)
c->util = n;
}
@@ -337,8 +370,8 @@ static void describe(const char *arg, int last_one)
struct object_id *oid = &cmit->object.oid;
if (always) {
printf("%s", find_unique_abbrev(oid->hash, abbrev));
- if (dirty)
- printf("%s", dirty);
+ if (suffix)
+ printf("%s", suffix);
printf("\n");
return;
}
@@ -362,10 +395,19 @@ static void describe(const char *arg, int last_one)
free_commit_list(list);
if (debug) {
+ static int label_width = -1;
+ if (label_width < 0) {
+ int i, w;
+ for (i = 0; i < ARRAY_SIZE(prio_names); i++) {
+ w = strlen(_(prio_names[i]));
+ if (label_width < w)
+ label_width = w;
+ }
+ }
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
struct possible_tag *t = &all_matches[cur_match];
- fprintf(stderr, " %-11s %8d %s\n",
- prio_names[t->name->prio],
+ fprintf(stderr, " %-*s %8d %s\n",
+ label_width, _(prio_names[t->name->prio]),
t->depth, t->name->path);
}
fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
@@ -380,9 +422,9 @@ static void describe(const char *arg, int last_one)
display_name(all_matches[0].name);
if (abbrev)
- show_suffix(all_matches[0].depth, cmit->object.oid.hash);
- if (dirty)
- printf("%s", dirty);
+ show_suffix(all_matches[0].depth, &cmit->object.oid);
+ if (suffix)
+ printf("%s", suffix);
printf("\n");
if (!last_one)
@@ -404,13 +446,18 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
N_("only output exact matches"), 0),
OPT_INTEGER(0, "candidates", &max_candidates,
N_("consider <n> most recent tags (default: 10)")),
- OPT_STRING(0, "match", &pattern, N_("pattern"),
+ OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
N_("only consider tags matching <pattern>")),
+ OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
+ N_("do not consider tags matching <pattern>")),
OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
{OPTION_STRING, 0, "dirty", &dirty, N_("mark"),
N_("append <mark> on dirty working tree (default: \"-dirty\")"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
+ {OPTION_STRING, 0, "broken", &broken, N_("mark"),
+ N_("append <mark> on broken working tree (default: \"-broken\")"),
+ PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"},
OPT_END(),
};
@@ -430,6 +477,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
die(_("--long is incompatible with --abbrev=0"));
if (contains) {
+ struct string_list_item *item;
struct argv_array args;
argv_array_init(&args);
@@ -440,8 +488,10 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
argv_array_push(&args, "--always");
if (!all) {
argv_array_push(&args, "--tags");
- if (pattern)
- argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
+ for_each_string_list_item(item, &patterns)
+ argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
+ for_each_string_list_item(item, &exclude_patterns)
+ argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
}
if (argc)
argv_array_pushv(&args, argv);
@@ -456,7 +506,28 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
die(_("No names found, cannot describe anything."));
if (argc == 0) {
- if (dirty) {
+ if (broken) {
+ struct child_process cp = CHILD_PROCESS_INIT;
+ argv_array_pushv(&cp.args, diff_index_args);
+ cp.git_cmd = 1;
+ cp.no_stdin = 1;
+ cp.no_stdout = 1;
+
+ if (!dirty)
+ dirty = "-dirty";
+
+ switch (run_command(&cp)) {
+ case 0:
+ suffix = NULL;
+ break;
+ case 1:
+ suffix = dirty;
+ break;
+ default:
+ /* diff-index aborted abnormally */
+ suffix = broken;
+ }
+ } else if (dirty) {
static struct lock_file index_lock;
int fd;
@@ -469,11 +540,15 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
diff_index_args, prefix))
- dirty = NULL;
+ suffix = NULL;
+ else
+ suffix = dirty;
}
describe("HEAD", 1);
} else if (dirty) {
die(_("--dirty is incompatible with commit-ishes"));
+ } else if (broken) {
+ die(_("--broken is incompatible with commit-ishes"));
} else {
while (argc-- > 0)
describe(*argv++, argc == 0);
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 8ce00480cd..326f88b657 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -7,46 +7,44 @@
static struct rev_info log_tree_opt;
-static int diff_tree_commit_sha1(const unsigned char *sha1)
+static int diff_tree_commit_sha1(const struct object_id *oid)
{
- struct commit *commit = lookup_commit_reference(sha1);
+ struct commit *commit = lookup_commit_reference(oid->hash);
if (!commit)
return -1;
return log_tree_commit(&log_tree_opt, commit);
}
/* Diff one or more commits. */
-static int stdin_diff_commit(struct commit *commit, char *line, int len)
+static int stdin_diff_commit(struct commit *commit, const char *p)
{
- unsigned char sha1[20];
- if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) {
- /* Graft the fake parents locally to the commit */
- int pos = 41;
- struct commit_list **pptr;
-
- /* Free the real parent list */
- free_commit_list(commit->parents);
- commit->parents = NULL;
- pptr = &(commit->parents);
- while (line[pos] && !get_sha1_hex(line + pos, sha1)) {
- struct commit *parent = lookup_commit(sha1);
- if (parent) {
- pptr = &commit_list_insert(parent, pptr)->next;
- }
- pos += 41;
+ struct object_id oid;
+ struct commit_list **pptr = NULL;
+
+ /* Graft the fake parents locally to the commit */
+ while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) {
+ struct commit *parent = lookup_commit(oid.hash);
+ if (!pptr) {
+ /* Free the real parent list */
+ free_commit_list(commit->parents);
+ commit->parents = NULL;
+ pptr = &(commit->parents);
+ }
+ if (parent) {
+ pptr = &commit_list_insert(parent, pptr)->next;
}
}
return log_tree_commit(&log_tree_opt, commit);
}
/* Diff two trees. */
-static int stdin_diff_trees(struct tree *tree1, char *line, int len)
+static int stdin_diff_trees(struct tree *tree1, const char *p)
{
- unsigned char sha1[20];
+ struct object_id oid;
struct tree *tree2;
- if (len != 82 || !isspace(line[40]) || get_sha1_hex(line + 41, sha1))
+ if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p)
return error("Need exactly two trees, separated by a space");
- tree2 = lookup_tree(sha1);
+ tree2 = lookup_tree(oid.hash);
if (!tree2 || parse_tree(tree2))
return -1;
printf("%s %s\n", oid_to_hex(&tree1->object.oid),
@@ -60,23 +58,24 @@ static int stdin_diff_trees(struct tree *tree1, char *line, int len)
static int diff_tree_stdin(char *line)
{
int len = strlen(line);
- unsigned char sha1[20];
+ struct object_id oid;
struct object *obj;
+ const char *p;
if (!len || line[len-1] != '\n')
return -1;
line[len-1] = 0;
- if (get_sha1_hex(line, sha1))
+ if (parse_oid_hex(line, &oid, &p))
return -1;
- obj = parse_object(sha1);
+ obj = parse_object(oid.hash);
if (!obj)
return -1;
if (obj->type == OBJ_COMMIT)
- return stdin_diff_commit((struct commit *)obj, line, len);
+ return stdin_diff_commit((struct commit *)obj, p);
if (obj->type == OBJ_TREE)
- return stdin_diff_trees((struct tree *)obj, line, len);
+ return stdin_diff_trees((struct tree *)obj, p);
error("Object %s is a %s, not a commit or tree",
- sha1_to_hex(sha1), typename(obj->type));
+ oid_to_hex(&oid), typename(obj->type));
return -1;
}
@@ -141,7 +140,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
break;
case 1:
tree1 = opt->pending.objects[0].item;
- diff_tree_commit_sha1(tree1->oid.hash);
+ diff_tree_commit_sha1(&tree1->oid);
break;
case 2:
tree1 = opt->pending.objects[0].item;
@@ -164,9 +163,9 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
DIFF_SETUP_USE_CACHE);
while (fgets(line, sizeof(line), stdin)) {
- unsigned char sha1[20];
+ struct object_id oid;
- if (get_sha1_hex(line, sha1)) {
+ if (get_oid_hex(line, &oid)) {
fputs(line, stdout);
fflush(stdout);
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 3d64b85337..d184aafab9 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -21,7 +21,7 @@
#define DIFF_NO_INDEX_IMPLICIT 2
struct blobinfo {
- unsigned char sha1[20];
+ struct object_id oid;
const char *name;
unsigned mode;
};
@@ -31,22 +31,22 @@ static const char builtin_diff_usage[] =
static void stuff_change(struct diff_options *opt,
unsigned old_mode, unsigned new_mode,
- const unsigned char *old_sha1,
- const unsigned char *new_sha1,
- int old_sha1_valid,
- int new_sha1_valid,
+ const struct object_id *old_oid,
+ const struct object_id *new_oid,
+ int old_oid_valid,
+ int new_oid_valid,
const char *old_name,
const char *new_name)
{
struct diff_filespec *one, *two;
- if (!is_null_sha1(old_sha1) && !is_null_sha1(new_sha1) &&
- !hashcmp(old_sha1, new_sha1) && (old_mode == new_mode))
+ if (!is_null_oid(old_oid) && !is_null_oid(new_oid) &&
+ !oidcmp(old_oid, new_oid) && (old_mode == new_mode))
return;
if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
SWAP(old_mode, new_mode);
- SWAP(old_sha1, new_sha1);
+ SWAP(old_oid, new_oid);
SWAP(old_name, new_name);
}
@@ -57,8 +57,8 @@ static void stuff_change(struct diff_options *opt,
one = alloc_filespec(old_name);
two = alloc_filespec(new_name);
- fill_filespec(one, old_sha1, old_sha1_valid, old_mode);
- fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
+ fill_filespec(one, old_oid->hash, old_oid_valid, old_mode);
+ fill_filespec(two, new_oid->hash, new_oid_valid, new_mode);
diff_queue(&diff_queued_diff, one, two);
}
@@ -89,7 +89,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
stuff_change(&revs->diffopt,
blob[0].mode, canon_mode(st.st_mode),
- blob[0].sha1, null_sha1,
+ &blob[0].oid, &null_oid,
1, 0,
path, path);
diffcore_std(&revs->diffopt);
@@ -114,7 +114,7 @@ static int builtin_diff_blobs(struct rev_info *revs,
stuff_change(&revs->diffopt,
blob[0].mode, blob[1].mode,
- blob[0].sha1, blob[1].sha1,
+ &blob[0].oid, &blob[1].oid,
1, 1,
blob[0].name, blob[1].name);
diffcore_std(&revs->diffopt);
@@ -160,7 +160,7 @@ static int builtin_diff_tree(struct rev_info *revs,
struct object_array_entry *ent0,
struct object_array_entry *ent1)
{
- const unsigned char *(sha1[2]);
+ const struct object_id *(oid[2]);
int swap = 0;
if (argc > 1)
@@ -172,9 +172,9 @@ static int builtin_diff_tree(struct rev_info *revs,
*/
if (ent1->item->flags & UNINTERESTING)
swap = 1;
- sha1[swap] = ent0->item->oid.hash;
- sha1[1 - swap] = ent1->item->oid.hash;
- diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
+ oid[swap] = &ent0->item->oid;
+ oid[1 - swap] = &ent1->item->oid;
+ diff_tree_sha1(oid[0]->hash, oid[1]->hash, "", &revs->diffopt);
log_tree_diff_flush(revs);
return 0;
}
@@ -184,7 +184,7 @@ static int builtin_diff_combined(struct rev_info *revs,
struct object_array_entry *ent,
int ents)
{
- struct sha1_array parents = SHA1_ARRAY_INIT;
+ struct oid_array parents = OID_ARRAY_INIT;
int i;
if (argc > 1)
@@ -193,10 +193,10 @@ static int builtin_diff_combined(struct rev_info *revs,
if (!revs->dense_combined_merges && !revs->combine_merges)
revs->dense_combined_merges = revs->combine_merges = 1;
for (i = 1; i < ents; i++)
- sha1_array_append(&parents, ent[i].item->oid.hash);
+ oid_array_append(&parents, &ent[i].item->oid);
diff_tree_combined(ent[0].item->oid.hash, &parents,
revs->dense_combined_merges, revs);
- sha1_array_clear(&parents);
+ oid_array_clear(&parents);
return 0;
}
@@ -408,7 +408,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
} else if (obj->type == OBJ_BLOB) {
if (2 <= blobs)
die(_("more than two blobs given: '%s'"), name);
- hashcpy(blob[blobs].sha1, obj->oid.hash);
+ hashcpy(blob[blobs].oid.hash, obj->oid.hash);
blob[blobs].name = name;
blob[blobs].mode = entry->mode;
blobs++;
diff --git a/builtin/difftool.c b/builtin/difftool.c
index d13350ce83..b9a892f269 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
hashmap_entry_init(entry, strhash(buf.buf));
hashmap_add(result, entry);
}
+ fclose(fp);
if (finish_command(&diff_files))
die("diff-files did not exit properly");
strbuf_release(&index_env);
@@ -254,6 +255,62 @@ static int ensure_leading_directories(char *path)
}
}
+/*
+ * Unconditional writing of a plain regular file is what
+ * "git difftool --dir-diff" wants to do for symlinks. We are preparing two
+ * temporary directories to be fed to a Git-unaware tool that knows how to
+ * show a diff of two directories (e.g. "diff -r A B").
+ *
+ * Because the tool is Git-unaware, if a symbolic link appears in either of
+ * these temporary directories, it will try to dereference and show the
+ * difference of the target of the symbolic link, which is not what we want,
+ * as the goal of the dir-diff mode is to produce an output that is logically
+ * equivalent to what "git diff" produces.
+ *
+ * Most importantly, we want to get textual comparison of the result of the
+ * readlink(2). get_symlink() provides that---it returns the contents of
+ * the symlink that gets written to a regular file to force the external tool
+ * to compare the readlink(2) result as text, even on a filesystem that is
+ * capable of doing a symbolic link.
+ */
+static char *get_symlink(const struct object_id *oid, const char *path)
+{
+ char *data;
+ if (is_null_oid(oid)) {
+ /* The symlink is unknown to Git so read from the filesystem */
+ struct strbuf link = STRBUF_INIT;
+ if (has_symlinks) {
+ if (strbuf_readlink(&link, path, strlen(path)))
+ die(_("could not read symlink %s"), path);
+ } else if (strbuf_read_file(&link, path, 128))
+ die(_("could not read symlink file %s"), path);
+
+ data = strbuf_detach(&link, NULL);
+ } else {
+ enum object_type type;
+ unsigned long size;
+ data = read_sha1_file(oid->hash, &type, &size);
+ if (!data)
+ die(_("could not read object %s for symlink %s"),
+ oid_to_hex(oid), path);
+ }
+
+ return data;
+}
+
+static int checkout_path(unsigned mode, struct object_id *oid,
+ const char *path, const struct checkout *state)
+{
+ struct cache_entry *ce;
+ int ret;
+
+ ce = make_cache_entry(mode, oid->hash, path, 0, 0);
+ ret = checkout_entry(ce, state, NULL);
+
+ free(ce);
+ return ret;
+}
+
static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
int argc, const char **argv)
{
@@ -262,16 +319,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT;
struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;
struct strbuf wtdir = STRBUF_INIT;
+ char *lbase_dir, *rbase_dir;
size_t ldir_len, rdir_len, wtdir_len;
- struct cache_entry *ce = xcalloc(1, sizeof(ce) + PATH_MAX + 1);
const char *workdir, *tmp;
int ret = 0, i;
FILE *fp;
struct hashmap working_tree_dups, submodules, symlinks2;
struct hashmap_iter iter;
struct pair_entry *entry;
- enum object_type type;
- unsigned long size;
struct index_state wtindex;
struct checkout lstate, rstate;
int rc, flags = RUN_GIT_CMD, err = 0;
@@ -298,11 +353,11 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
memset(&wtindex, 0, sizeof(wtindex));
memset(&lstate, 0, sizeof(lstate));
- lstate.base_dir = ldir.buf;
+ lstate.base_dir = lbase_dir = xstrdup(ldir.buf);
lstate.base_dir_len = ldir.len;
lstate.force = 1;
memset(&rstate, 0, sizeof(rstate));
- rstate.base_dir = rdir.buf;
+ rstate.base_dir = rbase_dir = xstrdup(rdir.buf);
rstate.base_dir_len = rdir.len;
rstate.force = 1;
@@ -336,7 +391,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct object_id loid, roid;
char status;
const char *src_path, *dst_path;
- size_t src_path_len, dst_path_len;
if (starts_with(info.buf, "::"))
die(N_("combined diff formats('-c' and '--cc') are "
@@ -349,17 +403,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
if (strbuf_getline_nul(&lpath, fp))
break;
src_path = lpath.buf;
- src_path_len = lpath.len;
i++;
if (status != 'C' && status != 'R') {
dst_path = src_path;
- dst_path_len = src_path_len;
} else {
if (strbuf_getline_nul(&rpath, fp))
break;
dst_path = rpath.buf;
- dst_path_len = rpath.len;
}
if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) {
@@ -377,27 +428,25 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
}
if (S_ISLNK(lmode)) {
- char *content = read_sha1_file(loid.hash, &type, &size);
+ char *content = get_symlink(&loid, src_path);
add_left_or_right(&symlinks2, src_path, content, 0);
free(content);
}
if (S_ISLNK(rmode)) {
- char *content = read_sha1_file(roid.hash, &type, &size);
+ char *content = get_symlink(&roid, dst_path);
add_left_or_right(&symlinks2, dst_path, content, 1);
free(content);
}
if (lmode && status != 'C') {
- ce->ce_mode = lmode;
- oidcpy(&ce->oid, &loid);
- strcpy(ce->name, src_path);
- ce->ce_namelen = src_path_len;
- if (checkout_entry(ce, &lstate, NULL))
- return error("could not write '%s'", src_path);
+ if (checkout_path(lmode, &loid, src_path, &lstate)) {
+ ret = error("could not write '%s'", src_path);
+ goto finish;
+ }
}
- if (rmode) {
+ if (rmode && !S_ISLNK(rmode)) {
struct working_tree_entry *entry;
/* Avoid duplicate working_tree entries */
@@ -410,13 +459,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
hashmap_add(&working_tree_dups, entry);
if (!use_wt_file(workdir, dst_path, &roid)) {
- ce->ce_mode = rmode;
- oidcpy(&ce->oid, &roid);
- strcpy(ce->name, dst_path);
- ce->ce_namelen = dst_path_len;
- if (checkout_entry(ce, &rstate, NULL))
- return error("could not write '%s'",
- dst_path);
+ if (checkout_path(rmode, &roid, dst_path,
+ &rstate)) {
+ ret = error("could not write '%s'",
+ dst_path);
+ goto finish;
+ }
} else if (!is_null_oid(&roid)) {
/*
* Changes in the working tree need special
@@ -431,10 +479,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
ADD_CACHE_JUST_APPEND);
add_path(&rdir, rdir_len, dst_path);
- if (ensure_leading_directories(rdir.buf))
- return error("could not create "
- "directory for '%s'",
- dst_path);
+ if (ensure_leading_directories(rdir.buf)) {
+ ret = error("could not create "
+ "directory for '%s'",
+ dst_path);
+ goto finish;
+ }
add_path(&wtdir, wtdir_len, dst_path);
if (symlinks) {
if (symlink(wtdir.buf, rdir.buf)) {
@@ -455,13 +505,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
}
}
+ fclose(fp);
+ fp = NULL;
if (finish_command(&child)) {
ret = error("error occurred running diff --raw");
goto finish;
}
if (!i)
- return 0;
+ goto finish;
/*
* Changes to submodules require special treatment.This loop writes a
@@ -584,7 +636,11 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
exit_cleanup(tmpdir, rc);
finish:
- free(ce);
+ if (fp)
+ fclose(fp);
+
+ free(lbase_dir);
+ free(rbase_dir);
strbuf_release(&ldir);
strbuf_release(&rdir);
strbuf_release(&wtdir);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 1e815b5577..64617ad8e3 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -212,7 +212,7 @@ static char *anonymize_blob(unsigned long *size)
return strbuf_detach(&out, NULL);
}
-static void export_blob(const unsigned char *sha1)
+static void export_blob(const struct object_id *oid)
{
unsigned long size;
enum object_type type;
@@ -223,34 +223,34 @@ static void export_blob(const unsigned char *sha1)
if (no_data)
return;
- if (is_null_sha1(sha1))
+ if (is_null_oid(oid))
return;
- object = lookup_object(sha1);
+ object = lookup_object(oid->hash);
if (object && object->flags & SHOWN)
return;
if (anonymize) {
buf = anonymize_blob(&size);
- object = (struct object *)lookup_blob(sha1);
+ object = (struct object *)lookup_blob(oid->hash);
eaten = 0;
} else {
- buf = read_sha1_file(sha1, &type, &size);
+ buf = read_sha1_file(oid->hash, &type, &size);
if (!buf)
- die ("Could not read blob %s", sha1_to_hex(sha1));
- if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
- die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
- object = parse_object_buffer(sha1, type, size, buf, &eaten);
+ die ("Could not read blob %s", oid_to_hex(oid));
+ if (check_sha1_signature(oid->hash, buf, size, typename(type)) < 0)
+ die("sha1 mismatch in blob %s", oid_to_hex(oid));
+ object = parse_object_buffer(oid->hash, type, size, buf, &eaten);
}
if (!object)
- die("Could not read blob %s", sha1_to_hex(sha1));
+ die("Could not read blob %s", oid_to_hex(oid));
mark_next_object(object);
printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
if (size && fwrite(buf, size, 1, stdout) != 1)
- die_errno ("Could not write blob '%s'", sha1_to_hex(sha1));
+ die_errno ("Could not write blob '%s'", oid_to_hex(oid));
printf("\n");
show_progress();
@@ -323,19 +323,19 @@ static void print_path(const char *path)
}
}
-static void *generate_fake_sha1(const void *old, size_t *len)
+static void *generate_fake_oid(const void *old, size_t *len)
{
static uint32_t counter = 1; /* avoid null sha1 */
- unsigned char *out = xcalloc(20, 1);
- put_be32(out + 16, counter++);
+ unsigned char *out = xcalloc(GIT_SHA1_RAWSZ, 1);
+ put_be32(out + GIT_SHA1_RAWSZ - 4, counter++);
return out;
}
-static const unsigned char *anonymize_sha1(const unsigned char *sha1)
+static const unsigned char *anonymize_sha1(const struct object_id *oid)
{
static struct hashmap sha1s;
- size_t len = 20;
- return anonymize_mem(&sha1s, generate_fake_sha1, sha1, &len);
+ size_t len = GIT_SHA1_RAWSZ;
+ return anonymize_mem(&sha1s, generate_fake_oid, oid, &len);
}
static void show_filemodify(struct diff_queue_struct *q,
@@ -383,7 +383,7 @@ static void show_filemodify(struct diff_queue_struct *q,
if (no_data || S_ISGITLINK(spec->mode))
printf("M %06o %s ", spec->mode,
sha1_to_hex(anonymize ?
- anonymize_sha1(spec->oid.hash) :
+ anonymize_sha1(&spec->oid) :
spec->oid.hash));
else {
struct object *object = lookup_object(spec->oid.hash);
@@ -572,7 +572,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
/* Export the referenced blobs, and remember the marks. */
for (i = 0; i < diff_queued_diff.nr; i++)
if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
- export_blob(diff_queued_diff.queue[i]->two->oid.hash);
+ export_blob(&diff_queued_diff.queue[i]->two->oid);
refname = commit->util;
if (anonymize) {
@@ -734,6 +734,7 @@ static void handle_tag(const char *name, struct tag *tag)
oid_to_hex(&tag->object.oid));
case DROP:
/* Ignore this tag altogether */
+ free(buf);
return;
case REWRITE:
if (tagged->type != OBJ_COMMIT) {
@@ -765,6 +766,7 @@ static void handle_tag(const char *name, struct tag *tag)
(int)(tagger_end - tagger), tagger,
tagger == tagger_end ? "" : "\n",
(int)message_size, (int)message_size, message ? message : "");
+ free(buf);
}
static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
@@ -797,14 +799,14 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
for (i = 0; i < info->nr; i++) {
struct rev_cmdline_entry *e = info->rev + i;
- unsigned char sha1[20];
+ struct object_id oid;
struct commit *commit;
char *full_name;
if (e->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
+ if (dwim_ref(e->name, strlen(e->name), oid.hash, &full_name) != 1)
continue;
if (refspecs) {
@@ -828,7 +830,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
case OBJ_COMMIT:
break;
case OBJ_BLOB:
- export_blob(commit->object.oid.hash);
+ export_blob(&commit->object.oid);
continue;
default: /* OBJ_TAG (nested tags) is already handled */
warning("Tag points to object of unexpected type %s, skipping.",
@@ -912,7 +914,7 @@ static void import_marks(char *input_file)
while (fgets(line, sizeof(line), f)) {
uint32_t mark;
char *line_end, *mark_end;
- unsigned char sha1[20];
+ struct object_id oid;
struct object *object;
struct commit *commit;
enum object_type type;
@@ -924,28 +926,28 @@ static void import_marks(char *input_file)
mark = strtoumax(line + 1, &mark_end, 10);
if (!mark || mark_end == line + 1
- || *mark_end != ' ' || get_sha1_hex(mark_end + 1, sha1))
+ || *mark_end != ' ' || get_oid_hex(mark_end + 1, &oid))
die("corrupt mark line: %s", line);
if (last_idnum < mark)
last_idnum = mark;
- type = sha1_object_info(sha1, NULL);
+ type = sha1_object_info(oid.hash, NULL);
if (type < 0)
- die("object not found: %s", sha1_to_hex(sha1));
+ die("object not found: %s", oid_to_hex(&oid));
if (type != OBJ_COMMIT)
/* only commits */
continue;
- commit = lookup_commit(sha1);
+ commit = lookup_commit(oid.hash);
if (!commit)
- die("not a commit? can't happen: %s", sha1_to_hex(sha1));
+ die("not a commit? can't happen: %s", oid_to_hex(&oid));
object = &commit->object;
if (object->flags & SHOWN)
- error("Object %s already has a mark", sha1_to_hex(sha1));
+ error("Object %s already has a mark", oid_to_hex(&oid));
mark_object(object, mark);
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 2a1c1c213f..366b9d13f9 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -50,7 +50,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
char **pack_lockfile_ptr = NULL;
struct child_process *conn;
struct fetch_pack_args args;
- struct sha1_array shallow = SHA1_ARRAY_INIT;
+ struct oid_array shallow = OID_ARRAY_INIT;
struct string_list deepen_not = STRING_LIST_INIT_DUP;
packet_trace_identity("fetch-pack");
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b5ad09d046..5f2c2ab23e 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -421,7 +421,7 @@ static int s_update_ref(const char *action,
struct ref *ref,
int check_old)
{
- char msg[1024];
+ char *msg;
char *rla = getenv("GIT_REFLOG_ACTION");
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
@@ -431,7 +431,7 @@ static int s_update_ref(const char *action,
return 0;
if (!rla)
rla = default_rla.buf;
- snprintf(msg, sizeof(msg), "%s: %s", rla, action);
+ msg = xstrfmt("%s: %s", rla, action);
transaction = ref_transaction_begin(&err);
if (!transaction ||
@@ -449,11 +449,13 @@ static int s_update_ref(const char *action,
ref_transaction_free(transaction);
strbuf_release(&err);
+ free(msg);
return 0;
fail:
ref_transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&err);
+ free(msg);
return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
: STORE_REF_ERROR_OTHER;
}
@@ -659,7 +661,7 @@ static int update_local_ref(struct ref *ref,
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
- check_for_new_submodule_commits(ref->new_oid.hash);
+ check_for_new_submodule_commits(&ref->new_oid);
r = s_update_ref(msg, ref, 0);
format_display(display, r ? '!' : '*', what,
r ? _("unable to update local ref") : NULL,
@@ -675,7 +677,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV);
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
- check_for_new_submodule_commits(ref->new_oid.hash);
+ check_for_new_submodule_commits(&ref->new_oid);
r = s_update_ref("fast-forward", ref, 1);
format_display(display, r ? '!' : ' ', quickref.buf,
r ? _("unable to update local ref") : NULL,
@@ -690,7 +692,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV);
if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
(recurse_submodules != RECURSE_SUBMODULES_ON))
- check_for_new_submodule_commits(ref->new_oid.hash);
+ check_for_new_submodule_commits(&ref->new_oid);
r = s_update_ref("forced-update", ref, 1);
format_display(display, r ? '!' : '+', quickref.buf,
r ? _("unable to update local ref") : _("forced update"),
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index efab62fd85..6faa3c0d24 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -41,7 +41,7 @@ struct src_data {
};
struct origin_data {
- unsigned char sha1[20];
+ struct object_id oid;
unsigned is_local_branch:1;
};
@@ -59,8 +59,8 @@ static struct string_list origins = STRING_LIST_INIT_DUP;
struct merge_parents {
int alloc, nr;
struct merge_parent {
- unsigned char given[20];
- unsigned char commit[20];
+ struct object_id given;
+ struct object_id commit;
unsigned char used;
} *item;
};
@@ -70,14 +70,14 @@ struct merge_parents {
* hundreds of heads at a time anyway.
*/
static struct merge_parent *find_merge_parent(struct merge_parents *table,
- unsigned char *given,
- unsigned char *commit)
+ struct object_id *given,
+ struct object_id *commit)
{
int i;
for (i = 0; i < table->nr; i++) {
- if (given && hashcmp(table->item[i].given, given))
+ if (given && oidcmp(&table->item[i].given, given))
continue;
- if (commit && hashcmp(table->item[i].commit, commit))
+ if (commit && oidcmp(&table->item[i].commit, commit))
continue;
return &table->item[i];
}
@@ -85,14 +85,14 @@ static struct merge_parent *find_merge_parent(struct merge_parents *table,
}
static void add_merge_parent(struct merge_parents *table,
- unsigned char *given,
- unsigned char *commit)
+ struct object_id *given,
+ struct object_id *commit)
{
if (table->nr && find_merge_parent(table, given, commit))
return;
ALLOC_GROW(table->item, table->nr + 1, table->alloc);
- hashcpy(table->item[table->nr].given, given);
- hashcpy(table->item[table->nr].commit, commit);
+ oidcpy(&table->item[table->nr].given, given);
+ oidcpy(&table->item[table->nr].commit, commit);
table->item[table->nr].used = 0;
table->nr++;
}
@@ -106,30 +106,30 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
struct src_data *src_data;
struct string_list_item *item;
int pulling_head = 0;
- unsigned char sha1[20];
+ struct object_id oid;
- if (len < 43 || line[40] != '\t')
+ if (len < GIT_SHA1_HEXSZ + 3 || line[GIT_SHA1_HEXSZ] != '\t')
return 1;
- if (starts_with(line + 41, "not-for-merge"))
+ if (starts_with(line + GIT_SHA1_HEXSZ + 1, "not-for-merge"))
return 0;
- if (line[41] != '\t')
+ if (line[GIT_SHA1_HEXSZ + 1] != '\t')
return 2;
- i = get_sha1_hex(line, sha1);
+ i = get_oid_hex(line, &oid);
if (i)
return 3;
- if (!find_merge_parent(merge_parents, sha1, NULL))
+ if (!find_merge_parent(merge_parents, &oid, NULL))
return 0; /* subsumed by other parents */
origin_data = xcalloc(1, sizeof(struct origin_data));
- hashcpy(origin_data->sha1, sha1);
+ oidcpy(&origin_data->oid, &oid);
if (line[len - 1] == '\n')
line[len - 1] = 0;
- line += 42;
+ line += GIT_SHA1_HEXSZ + 2;
/*
* At this point, line points at the beginning of comment e.g.
@@ -338,10 +338,10 @@ static void shortlog(const char *name,
struct string_list committers = STRING_LIST_INIT_DUP;
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
struct strbuf sb = STRBUF_INIT;
- const unsigned char *sha1 = origin_data->sha1;
+ const struct object_id *oid = &origin_data->oid;
int limit = opts->shortlog_len;
- branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
+ branch = deref_tag(parse_object(oid->hash), oid_to_hex(oid), GIT_SHA1_HEXSZ);
if (!branch || branch->type != OBJ_COMMIT)
return;
@@ -531,7 +531,7 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
}
static void find_merge_parents(struct merge_parents *result,
- struct strbuf *in, unsigned char *head)
+ struct strbuf *in, struct object_id *head)
{
struct commit_list *parents;
struct commit *head_commit;
@@ -542,31 +542,31 @@ static void find_merge_parents(struct merge_parents *result,
int len;
char *p = in->buf + pos;
char *newline = strchr(p, '\n');
- unsigned char sha1[20];
+ struct object_id oid;
struct commit *parent;
struct object *obj;
len = newline ? newline - p : strlen(p);
pos += len + !!newline;
- if (len < 43 ||
- get_sha1_hex(p, sha1) ||
- p[40] != '\t' ||
- p[41] != '\t')
+ if (len < GIT_SHA1_HEXSZ + 3 ||
+ get_oid_hex(p, &oid) ||
+ p[GIT_SHA1_HEXSZ] != '\t' ||
+ p[GIT_SHA1_HEXSZ + 1] != '\t')
continue; /* skip not-for-merge */
/*
* Do not use get_merge_parent() here; we do not have
* "name" here and we do not want to contaminate its
* util field yet.
*/
- obj = parse_object(sha1);
+ obj = parse_object(oid.hash);
parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
if (!parent)
continue;
commit_list_insert(parent, &parents);
- add_merge_parent(result, obj->oid.hash, parent->object.oid.hash);
+ add_merge_parent(result, &obj->oid, &parent->object.oid);
}
- head_commit = lookup_commit(head);
+ head_commit = lookup_commit(head->hash);
if (head_commit)
commit_list_insert(head_commit, &parents);
parents = reduce_heads(parents);
@@ -574,7 +574,7 @@ static void find_merge_parents(struct merge_parents *result,
while (parents) {
struct commit *cmit = pop_commit(&parents);
for (i = 0; i < result->nr; i++)
- if (!hashcmp(result->item[i].commit, cmit->object.oid.hash))
+ if (!oidcmp(&result->item[i].commit, &cmit->object.oid))
result->item[i].used = 1;
}
@@ -592,7 +592,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
struct fmt_merge_msg_opts *opts)
{
int i = 0, pos = 0;
- unsigned char head_sha1[20];
+ struct object_id head_oid;
const char *current_branch;
void *current_branch_to_free;
struct merge_parents merge_parents;
@@ -601,13 +601,13 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
/* get current branch */
current_branch = current_branch_to_free =
- resolve_refdup("HEAD", RESOLVE_REF_READING, head_sha1, NULL);
+ resolve_refdup("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL);
if (!current_branch)
die("No current branch");
if (starts_with(current_branch, "refs/heads/"))
current_branch += 11;
- find_merge_parents(&merge_parents, in, head_sha1);
+ find_merge_parents(&merge_parents, in, &head_oid);
/* get a line */
while (pos < in->len) {
@@ -633,7 +633,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
struct commit *head;
struct rev_info rev;
- head = lookup_commit_or_die(head_sha1, "HEAD");
+ head = lookup_commit_or_die(head_oid.hash, "HEAD");
init_revisions(&rev, NULL);
rev.commit_format = CMIT_FMT_ONELINE;
rev.ignore_merges = 1;
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index df41fa0350..eca365bf89 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -8,8 +8,8 @@
static char const * const for_each_ref_usage[] = {
N_("git for-each-ref [<options>] [<pattern>]"),
N_("git for-each-ref [--points-at <object>]"),
- N_("git for-each-ref [(--merged | --no-merged) [<object>]]"),
- N_("git for-each-ref [--contains [<object>]]"),
+ N_("git for-each-ref [(--merged | --no-merged) [<commit>]]"),
+ N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"),
NULL
};
@@ -43,6 +43,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_MERGED(&filter, N_("print only refs that are merged")),
OPT_NO_MERGED(&filter, N_("print only refs that are not merged")),
OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")),
+ OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
OPT_END(),
};
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 1a5caccd0f..b5e13a4556 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -396,13 +396,13 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
static int default_refs;
-static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1,
+static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
unsigned long timestamp)
{
struct object *obj;
- if (!is_null_sha1(sha1)) {
- obj = lookup_object(sha1);
+ if (!is_null_oid(oid)) {
+ obj = lookup_object(oid->hash);
if (obj && (obj->flags & HAS_OBJ)) {
if (timestamp && name_objects)
add_decoration(fsck_walk_options.object_names,
@@ -411,13 +411,13 @@ static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1,
obj->used = 1;
mark_object_reachable(obj);
} else {
- error("%s: invalid reflog entry %s", refname, sha1_to_hex(sha1));
+ error("%s: invalid reflog entry %s", refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
}
}
}
-static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,
const char *email, unsigned long timestamp, int tz,
const char *message, void *cb_data)
{
@@ -425,10 +425,10 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
if (verbose)
fprintf(stderr, "Checking reflog %s->%s\n",
- sha1_to_hex(osha1), sha1_to_hex(nsha1));
+ oid_to_hex(ooid), oid_to_hex(noid));
- fsck_handle_reflog_sha1(refname, osha1, 0);
- fsck_handle_reflog_sha1(refname, nsha1, timestamp);
+ fsck_handle_reflog_oid(refname, ooid, 0);
+ fsck_handle_reflog_oid(refname, noid, timestamp);
return 0;
}
@@ -491,7 +491,7 @@ static void get_default_heads(void)
}
}
-static struct object *parse_loose_object(const unsigned char *sha1,
+static struct object *parse_loose_object(const struct object_id *oid,
const char *path)
{
struct object *obj;
@@ -500,27 +500,27 @@ static struct object *parse_loose_object(const unsigned char *sha1,
unsigned long size;
int eaten;
- if (read_loose_object(path, sha1, &type, &size, &contents) < 0)
+ if (read_loose_object(path, oid->hash, &type, &size, &contents) < 0)
return NULL;
if (!contents && type != OBJ_BLOB)
die("BUG: read_loose_object streamed a non-blob");
- obj = parse_object_buffer(sha1, type, size, contents, &eaten);
+ obj = parse_object_buffer(oid->hash, type, size, contents, &eaten);
if (!eaten)
free(contents);
return obj;
}
-static int fsck_loose(const unsigned char *sha1, const char *path, void *data)
+static int fsck_loose(const struct object_id *oid, const char *path, void *data)
{
- struct object *obj = parse_loose_object(sha1, path);
+ struct object *obj = parse_loose_object(oid, path);
if (!obj) {
errors_found |= ERROR_OBJECT;
error("%s: object corrupt or missing: %s",
- sha1_to_hex(sha1), path);
+ oid_to_hex(oid), path);
return 0; /* keep checking other objects */
}
@@ -619,26 +619,26 @@ static int fsck_cache_tree(struct cache_tree *it)
return err;
}
-static void mark_object_for_connectivity(const unsigned char *sha1)
+static void mark_object_for_connectivity(const struct object_id *oid)
{
- struct object *obj = lookup_unknown_object(sha1);
+ struct object *obj = lookup_unknown_object(oid->hash);
obj->flags |= HAS_OBJ;
}
-static int mark_loose_for_connectivity(const unsigned char *sha1,
+static int mark_loose_for_connectivity(const struct object_id *oid,
const char *path,
void *data)
{
- mark_object_for_connectivity(sha1);
+ mark_object_for_connectivity(oid);
return 0;
}
-static int mark_packed_for_connectivity(const unsigned char *sha1,
+static int mark_packed_for_connectivity(const struct object_id *oid,
struct packed_git *pack,
uint32_t pos,
void *data)
{
- mark_object_for_connectivity(sha1);
+ mark_object_for_connectivity(oid);
return 0;
}
@@ -771,6 +771,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
if (keep_cache_objects) {
+ verify_index_checksum = 1;
read_cache();
for (i = 0; i < active_nr; i++) {
unsigned int mode;
diff --git a/builtin/gc.c b/builtin/gc.c
index a2b9e8924e..91f7696a85 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -64,17 +64,6 @@ static void report_pack_garbage(unsigned seen_bits, const char *path)
string_list_append(&pack_garbage, path);
}
-static void git_config_date_string(const char *key, const char **output)
-{
- if (git_config_get_string_const(key, output))
- return;
- if (strcmp(*output, "now")) {
- unsigned long now = approxidate("now");
- if (approxidate(*output) >= now)
- git_die_config(key, _("Invalid %s: '%s'"), key, *output);
- }
-}
-
static void process_log_file(void)
{
struct stat st;
@@ -131,9 +120,9 @@ static void gc_config(void)
git_config_get_int("gc.auto", &gc_auto_threshold);
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
git_config_get_bool("gc.autodetach", &detach_auto);
- git_config_date_string("gc.pruneexpire", &prune_expire);
- git_config_date_string("gc.worktreepruneexpire", &prune_worktrees_expire);
- git_config_date_string("gc.logexpiry", &gc_log_expire);
+ git_config_get_expiry("gc.pruneexpire", &prune_expire);
+ git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
+ git_config_get_expiry("gc.logexpiry", &gc_log_expire);
git_config(git_default_config, NULL);
}
@@ -146,8 +135,6 @@ static int too_many_loose_objects(void)
* distributed, we can check only one and get a reasonable
* estimate.
*/
- char path[PATH_MAX];
- const char *objdir = get_object_directory();
DIR *dir;
struct dirent *ent;
int auto_threshold;
@@ -157,11 +144,7 @@ static int too_many_loose_objects(void)
if (gc_auto_threshold <= 0)
return 0;
- if (sizeof(path) <= snprintf(path, sizeof(path), "%s/17", objdir)) {
- warning(_("insanely long object directory %.*s"), 50, objdir);
- return 0;
- }
- dir = opendir(path);
+ dir = opendir(git_path("objects/17"));
if (!dir)
return 0;
@@ -249,7 +232,7 @@ static int need_to_gc(void)
static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
{
static struct lock_file lock;
- char my_host[128];
+ char my_host[HOST_NAME_MAX + 1];
struct strbuf sb = STRBUF_INIT;
struct stat st;
uintmax_t pid;
@@ -261,15 +244,19 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
/* already locked */
return NULL;
- if (gethostname(my_host, sizeof(my_host)))
+ if (xgethostname(my_host, sizeof(my_host)))
xsnprintf(my_host, sizeof(my_host), "unknown");
pidfile_path = git_pathdup("gc.pid");
fd = hold_lock_file_for_update(&lock, pidfile_path,
LOCK_DIE_ON_ERROR);
if (!force) {
- static char locking_host[128];
+ static char locking_host[HOST_NAME_MAX + 1];
+ static char *scan_fmt;
int should_exit;
+
+ if (!scan_fmt)
+ scan_fmt = xstrfmt("%s %%%dc", "%"SCNuMAX, HOST_NAME_MAX);
fp = fopen(pidfile_path, "r");
memset(locking_host, 0, sizeof(locking_host));
should_exit =
@@ -285,7 +272,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
* running.
*/
time(NULL) - st.st_mtime <= 12 * 3600 &&
- fscanf(fp, "%"SCNuMAX" %127c", &pid, locking_host) == 2 &&
+ fscanf(fp, scan_fmt, &pid, locking_host) == 2 &&
/* be gentle to concurrent "gc" on remote hosts */
(strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
if (fp != NULL)
diff --git a/builtin/grep.c b/builtin/grep.c
index 9304c33e75..3ffb5b4e81 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -294,26 +294,23 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)
return st;
}
-static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
+static void *lock_and_read_oid_file(const struct object_id *oid, enum object_type *type, unsigned long *size)
{
void *data;
grep_read_lock();
- data = read_sha1_file(sha1, type, size);
+ data = read_sha1_file(oid->hash, type, size);
grep_read_unlock();
return data;
}
-static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
+static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
const char *filename, int tree_name_len,
const char *path)
{
struct strbuf pathbuf = STRBUF_INIT;
- if (opt->relative && opt->prefix_length) {
- quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
- strbuf_insert(&pathbuf, 0, filename, tree_name_len);
- } else if (super_prefix) {
+ if (super_prefix) {
strbuf_add(&pathbuf, filename, tree_name_len);
strbuf_addstr(&pathbuf, super_prefix);
strbuf_addstr(&pathbuf, filename + tree_name_len);
@@ -321,9 +318,16 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
strbuf_addstr(&pathbuf, filename);
}
+ if (opt->relative && opt->prefix_length) {
+ char *name = strbuf_detach(&pathbuf, NULL);
+ quote_path_relative(name + tree_name_len, opt->prefix, &pathbuf);
+ strbuf_insert(&pathbuf, 0, name, tree_name_len);
+ free(name);
+ }
+
#ifndef NO_PTHREADS
if (num_threads) {
- add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
+ add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, oid);
strbuf_release(&pathbuf);
return 0;
} else
@@ -332,7 +336,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
struct grep_source gs;
int hit;
- grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
+ grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, oid);
strbuf_release(&pathbuf);
hit = grep_source(opt, &gs);
@@ -345,12 +349,14 @@ static int grep_file(struct grep_opt *opt, const char *filename)
{
struct strbuf buf = STRBUF_INIT;
+ if (super_prefix)
+ strbuf_addstr(&buf, super_prefix);
+ strbuf_addstr(&buf, filename);
+
if (opt->relative && opt->prefix_length) {
- quote_path_relative(filename, opt->prefix, &buf);
- } else {
- if (super_prefix)
- strbuf_addstr(&buf, super_prefix);
- strbuf_addstr(&buf, filename);
+ char *name = strbuf_detach(&buf, NULL);
+ quote_path_relative(name, opt->prefix, &buf);
+ free(name);
}
#ifndef NO_PTHREADS
@@ -399,13 +405,12 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
}
static void compile_submodule_options(const struct grep_opt *opt,
- const struct pathspec *pathspec,
+ const char **argv,
int cached, int untracked,
int opt_exclude, int use_index,
int pattern_type_arg)
{
struct grep_pat *pattern;
- int i;
if (recurse_submodules)
argv_array_push(&submodule_options, "--recurse-submodules");
@@ -523,9 +528,8 @@ static void compile_submodule_options(const struct grep_opt *opt,
/* Add Pathspecs */
argv_array_push(&submodule_options, "--");
- for (i = 0; i < pathspec->nr; i++)
- argv_array_push(&submodule_options,
- pathspec->items[i].original);
+ for (; *argv; argv++)
+ argv_array_push(&submodule_options, *argv);
}
/*
@@ -538,7 +542,7 @@ static int grep_submodule_launch(struct grep_opt *opt,
int status, i;
const char *end_of_base;
const char *name;
- struct work_item *w = opt->output_priv;
+ struct strbuf child_output = STRBUF_INIT;
end_of_base = strchr(gs->name, ':');
if (gs->identifier && end_of_base)
@@ -549,6 +553,11 @@ static int grep_submodule_launch(struct grep_opt *opt,
prepare_submodule_repo_env(&cp.env_array);
argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
+ if (opt->relative && opt->prefix_length)
+ argv_array_pushf(&cp.env_array, "%s=%s",
+ GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
+ opt->prefix);
+
/* Add super prefix */
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
super_prefix ? super_prefix : "",
@@ -593,14 +602,16 @@ static int grep_submodule_launch(struct grep_opt *opt,
* child process. A '0' indicates a hit, a '1' indicates no hit and
* anything else is an error.
*/
- status = capture_command(&cp, &w->out, 0);
+ status = capture_command(&cp, &child_output, 0);
if (status && (status != 1)) {
/* flush the buffer */
- write_or_die(1, w->out.buf, w->out.len);
+ write_or_die(1, child_output.buf, child_output.len);
die("process for submodule '%s' failed with exit code: %d",
gs->name, status);
}
+ opt->output(opt, child_output.buf, child_output.len);
+ strbuf_release(&child_output);
/* invert the return code to make a hit equal to 1 */
return !status;
}
@@ -616,7 +627,7 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,
{
if (!is_submodule_initialized(path))
return 0;
- if (!is_submodule_populated(path)) {
+ if (!is_submodule_populated_gently(path, NULL)) {
/*
* If searching history, check for the presense of the
* submodule's gitdir before skipping the submodule.
@@ -641,19 +652,14 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,
} else
#endif
{
- struct work_item w;
+ struct grep_source gs;
int hit;
- grep_source_init(&w.source, GREP_SOURCE_SUBMODULE,
+ grep_source_init(&gs, GREP_SOURCE_SUBMODULE,
filename, path, sha1);
- strbuf_init(&w.out, 0);
- opt->output_priv = &w;
- hit = grep_submodule_launch(opt, &w.source);
-
- write_or_die(1, w.out.buf, w.out.len);
+ hit = grep_submodule_launch(opt, &gs);
- grep_source_clear(&w.source);
- strbuf_release(&w.out);
+ grep_source_clear(&gs);
return hit;
}
}
@@ -690,7 +696,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
ce_skip_worktree(ce)) {
if (ce_stage(ce) || ce_intent_to_add(ce))
continue;
- hit |= grep_sha1(opt, ce->oid.hash, ce->name,
+ hit |= grep_oid(opt, &ce->oid, ce->name,
0, ce->name);
} else {
hit |= grep_file(opt, ce->name);
@@ -750,7 +756,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
strbuf_add(base, entry.path, te_len);
if (S_ISREG(entry.mode)) {
- hit |= grep_sha1(opt, entry.oid->hash, base->buf, tn_len,
+ hit |= grep_oid(opt, entry.oid, base->buf, tn_len,
check_attr ? base->buf + tn_len : NULL);
} else if (S_ISDIR(entry.mode)) {
enum object_type type;
@@ -758,7 +764,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
void *data;
unsigned long size;
- data = lock_and_read_sha1_file(entry.oid->hash, &type, &size);
+ data = lock_and_read_oid_file(entry.oid, &type, &size);
if (!data)
die(_("unable to read tree (%s)"),
oid_to_hex(entry.oid));
@@ -787,7 +793,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
struct object *obj, const char *name, const char *path)
{
if (obj->type == OBJ_BLOB)
- return grep_sha1(opt, obj->oid.hash, name, 0, path);
+ return grep_oid(opt, &obj->oid, name, 0, path);
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
struct tree_desc tree;
void *data;
@@ -979,7 +985,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
N_("ignore files specified via '.gitignore'"), 1),
OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
- N_("recursivley search in each submodule")),
+ N_("recursively search in each submodule")),
OPT_STRING(0, "parent-basename", &parent_basename,
N_("basename"),
N_("prepend parent project's basename to output")),
@@ -1169,7 +1175,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
allow_revs = use_index && !untracked;
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
- unsigned char sha1[20];
+ struct object_id oid;
struct object_context oc;
struct object *object;
@@ -1184,13 +1190,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
break;
}
- if (get_sha1_with_context(arg, 0, sha1, &oc)) {
+ if (get_sha1_with_context(arg, 0, oid.hash, &oc)) {
if (seen_dashdash)
die(_("unable to resolve revision: %s"), arg);
break;
}
- object = parse_object_or_die(sha1, arg);
+ object = parse_object_or_die(oid.hash, arg);
if (!seen_dashdash)
verify_non_filename(prefix, arg);
add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
@@ -1236,7 +1242,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (recurse_submodules) {
gitmodules_config();
- compile_submodule_options(&opt, &pathspec, cached, untracked,
+ compile_submodule_options(&opt, argv + i, cached, untracked,
opt_exclude, use_index,
pattern_type_arg);
}
@@ -1293,6 +1299,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
hit |= wait_all();
if (hit && show_in_pager)
run_pager(&opt, prefix);
+ clear_pathspec(&pathspec);
free_grep_patterns(&opt);
return !hit;
}
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 9028e1fdcc..bbeaf20bcc 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -102,7 +102,6 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
OPT_END()
};
int i;
- int prefix_length = -1;
const char *errstr = NULL;
argc = parse_options(argc, argv, NULL, hash_object_options,
@@ -113,9 +112,8 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
else
prefix = setup_git_directory_gently(&nongit);
- prefix_length = prefix ? strlen(prefix) : 0;
if (vpath && prefix)
- vpath = prefix_filename(prefix, prefix_length, vpath);
+ vpath = xstrdup(prefix_filename(prefix, vpath));
git_config(git_default_config, NULL);
@@ -144,11 +142,13 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
for (i = 0 ; i < argc; i++) {
const char *arg = argv[i];
+ char *to_free = NULL;
- if (0 <= prefix_length)
- arg = prefix_filename(prefix, prefix_length, arg);
+ if (prefix)
+ arg = to_free = prefix_filename(prefix, arg);
hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
flags, literally);
+ free(to_free);
}
if (stdin_paths)
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 88d205f858..4ff567db47 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -307,14 +307,15 @@ static const char *open_pack_file(const char *pack_name)
if (from_stdin) {
input_fd = 0;
if (!pack_name) {
- static char tmp_file[PATH_MAX];
- output_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),
+ struct strbuf tmp_file = STRBUF_INIT;
+ output_fd = odb_mkstemp(&tmp_file,
"pack/tmp_pack_XXXXXX");
- pack_name = xstrdup(tmp_file);
- } else
+ pack_name = strbuf_detach(&tmp_file, NULL);
+ } else {
output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
- if (output_fd < 0)
- die_errno(_("unable to create '%s'"), pack_name);
+ if (output_fd < 0)
+ die_errno(_("unable to create '%s'"), pack_name);
+ }
nothread_data.pack_fd = output_fd;
} else {
input_fd = open(pack_name, O_RDONLY);
@@ -809,6 +810,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
unsigned long has_size;
read_lock();
has_type = sha1_object_info(sha1, &has_size);
+ if (has_type < 0)
+ die(_("cannot read existing object info %s"), sha1_to_hex(sha1));
if (has_type != type || has_size != size)
die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
has_data = read_sha1_file(sha1, &has_type, &has_size);
@@ -1442,10 +1445,11 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (!from_stdin) {
printf("%s\n", sha1_to_hex(sha1));
} else {
- char buf[48];
- int len = snprintf(buf, sizeof(buf), "%s\t%s\n",
- report, sha1_to_hex(sha1));
- write_or_die(1, buf, len);
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1));
+ write_or_die(1, buf.buf, buf.len);
+ strbuf_release(&buf);
/*
* Let's just mimic git-unpack-objects here and write
diff --git a/builtin/log.c b/builtin/log.c
index 55d20cc2d8..ec3258368c 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -52,6 +52,11 @@ struct line_opt_callback_data {
struct string_list args;
};
+static int auto_decoration_style(void)
+{
+ return (isatty(1) || pager_in_use()) ? DECORATE_SHORT_REFS : 0;
+}
+
static int parse_decoration_style(const char *var, const char *value)
{
switch (git_config_maybe_bool(var, value)) {
@@ -67,7 +72,7 @@ static int parse_decoration_style(const char *var, const char *value)
else if (!strcmp(value, "short"))
return DECORATE_SHORT_REFS;
else if (!strcmp(value, "auto"))
- return (isatty(1) || pager_in_use()) ? DECORATE_SHORT_REFS : 0;
+ return auto_decoration_style();
return -1;
}
@@ -105,6 +110,8 @@ static void init_log_defaults(void)
{
init_grep_defaults();
init_diff_ui_defaults();
+
+ decoration_style = auto_decoration_style();
}
static void cmd_log_init_defaults(struct rev_info *rev)
@@ -989,8 +996,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
return;
- log_write_email_headers(rev, head, &pp.subject, &pp.after_subject,
- &need_8bit_cte);
+ log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte);
for (i = 0; !need_8bit_cte && i < nr; i++) {
const char *buf = get_commit_buffer(list[i], NULL);
@@ -1005,6 +1011,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
msg = body;
pp.fmt = CMIT_FMT_EMAIL;
pp.date_mode.type = DATE_RFC2822;
+ pp.rev = rev;
+ pp.print_email_subject = 1;
pp_user_info(&pp, NULL, &sb, committer, encoding);
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
pp_remainder(&pp, &msg, &sb, 0);
@@ -1083,8 +1091,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
if (!output_directory)
return prefix;
- return xstrdup(prefix_filename(prefix, outdir_offset,
- output_directory));
+ return prefix_filename(prefix, output_directory);
}
static const char * const builtin_format_patch_usage[] = {
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 1c0f057d02..a6c70dbe9e 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -15,6 +15,7 @@
#include "string-list.h"
#include "pathspec.h"
#include "run-command.h"
+#include "submodule.h"
static int abbrev;
static int show_deleted;
@@ -30,7 +31,7 @@ static int line_terminator = '\n';
static int debug_mode;
static int show_eol;
static int recurse_submodules;
-static struct argv_array submodules_options = ARGV_ARRAY_INIT;
+static struct argv_array submodule_options = ARGV_ARRAY_INIT;
static const char *prefix;
static const char *super_prefix;
@@ -172,20 +173,27 @@ static void show_killed_files(struct dir_struct *dir)
/*
* Compile an argv_array with all of the options supported by --recurse_submodules
*/
-static void compile_submodule_options(const struct dir_struct *dir, int show_tag)
+static void compile_submodule_options(const char **argv,
+ const struct dir_struct *dir,
+ int show_tag)
{
if (line_terminator == '\0')
- argv_array_push(&submodules_options, "-z");
+ argv_array_push(&submodule_options, "-z");
if (show_tag)
- argv_array_push(&submodules_options, "-t");
+ argv_array_push(&submodule_options, "-t");
if (show_valid_bit)
- argv_array_push(&submodules_options, "-v");
+ argv_array_push(&submodule_options, "-v");
if (show_cached)
- argv_array_push(&submodules_options, "--cached");
+ argv_array_push(&submodule_options, "--cached");
if (show_eol)
- argv_array_push(&submodules_options, "--eol");
+ argv_array_push(&submodule_options, "--eol");
if (debug_mode)
- argv_array_push(&submodules_options, "--debug");
+ argv_array_push(&submodule_options, "--debug");
+
+ /* Add Pathspecs */
+ argv_array_push(&submodule_options, "--");
+ for (; *argv; argv++)
+ argv_array_push(&submodule_options, *argv);
}
/**
@@ -195,8 +203,15 @@ static void show_gitlink(const struct cache_entry *ce)
{
struct child_process cp = CHILD_PROCESS_INIT;
int status;
- int i;
+ char *dir;
+
+ prepare_submodule_repo_env(&cp.env_array);
+ argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
+ if (prefix_len)
+ argv_array_pushf(&cp.env_array, "%s=%s",
+ GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
+ prefix);
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
super_prefix ? super_prefix : "",
ce->name);
@@ -204,20 +219,13 @@ static void show_gitlink(const struct cache_entry *ce)
argv_array_push(&cp.args, "--recurse-submodules");
/* add supported options */
- argv_array_pushv(&cp.args, submodules_options.argv);
-
- /*
- * Pass in the original pathspec args. The submodule will be
- * responsible for prepending the 'submodule_prefix' prior to comparing
- * against the pathspec for matches.
- */
- argv_array_push(&cp.args, "--");
- for (i = 0; i < pathspec.nr; i++)
- argv_array_push(&cp.args, pathspec.items[i].original);
+ argv_array_pushv(&cp.args, submodule_options.argv);
cp.git_cmd = 1;
- cp.dir = ce->name;
+ dir = mkpathdup("%s/%s", get_git_work_tree(), ce->name);
+ cp.dir = dir;
status = run_command(&cp);
+ free(dir);
if (status)
exit(status);
}
@@ -604,7 +612,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
setup_work_tree();
if (recurse_submodules)
- compile_submodule_options(&dir, show_tag);
+ compile_submodule_options(argv, &dir, show_tag);
if (recurse_submodules &&
(show_stage || show_deleted || show_others || show_unmerged ||
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 66cdd45cc1..b2d7d5ce68 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -17,17 +17,19 @@ static const char * const ls_remote_usage[] = {
static int tail_match(const char **pattern, const char *path)
{
const char *p;
- char pathbuf[PATH_MAX];
+ char *pathbuf;
if (!pattern)
return 1; /* no restriction */
- if (snprintf(pathbuf, sizeof(pathbuf), "/%s", path) > sizeof(pathbuf))
- return error("insanely long ref %.*s...", 20, path);
+ pathbuf = xstrfmt("/%s", path);
while ((p = *(pattern++)) != NULL) {
- if (!wildmatch(p, pathbuf, 0, NULL))
+ if (!wildmatch(p, pathbuf, 0, NULL)) {
+ free(pathbuf);
return 1;
+ }
}
+ free(pathbuf);
return 0;
}
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index e3b62f2fc7..cfb667a594 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -11,13 +11,6 @@
static const char mailinfo_usage[] =
"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info";
-static char *prefix_copy(const char *prefix, const char *filename)
-{
- if (!prefix || is_absolute_path(filename))
- return xstrdup(filename);
- return xstrdup(prefix_filename(prefix, strlen(prefix), filename));
-}
-
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
{
const char *def_charset;
@@ -60,8 +53,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
mi.input = stdin;
mi.output = stdout;
- msgfile = prefix_copy(prefix, argv[1]);
- patchfile = prefix_copy(prefix, argv[2]);
+ msgfile = prefix_filename(prefix, argv[1]);
+ patchfile = prefix_filename(prefix, argv[2]);
status = !!mailinfo(&mi, msgfile, patchfile);
clear_mailinfo(&mi);
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c1..664400b816 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -232,6 +232,16 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
do {
peek = fgetc(f);
+ if (peek == EOF) {
+ if (f == stdin)
+ /* empty stdin is OK */
+ ret = skip;
+ else {
+ fclose(f);
+ error(_("empty mbox: '%s'"), file);
+ }
+ goto out;
+ }
} while (isspace(peek));
ungetc(peek, f);
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index b572a37c26..cfe2a796f8 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -36,12 +36,12 @@ static const char * const merge_base_usage[] = {
static struct commit *get_commit_reference(const char *arg)
{
- unsigned char revkey[20];
+ struct object_id revkey;
struct commit *r;
- if (get_sha1(arg, revkey))
+ if (get_oid(arg, &revkey))
die("Not a valid object name %s", arg);
- r = lookup_commit_reference(revkey);
+ r = lookup_commit_reference(revkey.hash);
if (!r)
die("Not a valid commit name %s", arg);
@@ -113,14 +113,14 @@ struct rev_collect {
unsigned int initial : 1;
};
-static void add_one_commit(unsigned char *sha1, struct rev_collect *revs)
+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
{
struct commit *commit;
- if (is_null_sha1(sha1))
+ if (is_null_oid(oid))
return;
- commit = lookup_commit(sha1);
+ commit = lookup_commit(oid->hash);
if (!commit ||
(commit->object.flags & TMP_MARK) ||
parse_commit(commit))
@@ -131,7 +131,7 @@ static void add_one_commit(unsigned char *sha1, struct rev_collect *revs)
commit->object.flags |= TMP_MARK;
}
-static int collect_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
const char *ident, unsigned long timestamp,
int tz, const char *message, void *cbdata)
{
@@ -139,15 +139,15 @@ static int collect_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
if (revs->initial) {
revs->initial = 0;
- add_one_commit(osha1, revs);
+ add_one_commit(ooid, revs);
}
- add_one_commit(nsha1, revs);
+ add_one_commit(noid, revs);
return 0;
}
static int handle_fork_point(int argc, const char **argv)
{
- unsigned char sha1[20];
+ struct object_id oid;
char *refname;
const char *commitname;
struct rev_collect revs;
@@ -155,7 +155,7 @@ static int handle_fork_point(int argc, const char **argv)
struct commit_list *bases;
int i, ret = 0;
- switch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) {
+ switch (dwim_ref(argv[0], strlen(argv[0]), oid.hash, &refname)) {
case 0:
die("No such ref: '%s'", argv[0]);
case 1:
@@ -165,16 +165,16 @@ static int handle_fork_point(int argc, const char **argv)
}
commitname = (argc == 2) ? argv[1] : "HEAD";
- if (get_sha1(commitname, sha1))
+ if (get_oid(commitname, &oid))
die("Not a valid object name: '%s'", commitname);
- derived = lookup_commit_reference(sha1);
+ derived = lookup_commit_reference(oid.hash);
memset(&revs, 0, sizeof(revs));
revs.initial = 1;
for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
- if (!revs.nr && !get_sha1(refname, sha1))
- add_one_commit(sha1, &revs);
+ if (!revs.nr && !get_oid(refname, &oid))
+ add_one_commit(&oid, &revs);
for (i = 0; i < revs.nr; i++)
revs.commit[i]->object.flags &= ~TMP_MARK;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 13e22a2f0b..47dde7c39c 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -28,7 +28,6 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
xmparam_t xmp = {{0}};
int ret = 0, i = 0, to_stdout = 0;
int quiet = 0;
- int prefixlen = 0;
struct option options[] = {
OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
@@ -65,15 +64,19 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
return error_errno("failed to redirect stderr to /dev/null");
}
- if (prefix)
- prefixlen = strlen(prefix);
-
for (i = 0; i < 3; i++) {
- const char *fname = prefix_filename(prefix, prefixlen, argv[i]);
+ char *fname;
+ int ret;
+
if (!names[i])
names[i] = argv[i];
- if (read_mmfile(mmfs + i, fname))
+
+ fname = prefix_filename(prefix, argv[i]);
+ ret = read_mmfile(mmfs + i, fname);
+ free(fname);
+ if (ret)
return -1;
+
if (mmfs[i].size > MAX_XDIFF_SIZE ||
buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
return error("Cannot merge binary files: %s",
@@ -90,7 +93,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
if (ret >= 0) {
const char *filename = argv[0];
- const char *fpath = prefix_filename(prefix, prefixlen, argv[0]);
+ char *fpath = prefix_filename(prefix, argv[0]);
FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
if (!f)
@@ -102,6 +105,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
else if (fclose(f))
ret = error_errno("Could not close %s", filename);
free(result.ptr);
+ free(fpath);
}
if (ret > 127)
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 2d1b6db6bd..c99443b095 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -9,7 +9,7 @@ static int merge_entry(int pos, const char *path)
{
int found;
const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL };
- char hexbuf[4][GIT_SHA1_HEXSZ + 1];
+ char hexbuf[4][GIT_MAX_HEXSZ + 1];
char ownbuf[4][60];
if (pos >= active_nr)
diff --git a/builtin/merge.c b/builtin/merge.c
index 848a298556..703827f006 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -44,7 +44,6 @@ struct strategy {
static const char * const builtin_merge_usage[] = {
N_("git merge [<options>] [<commit>...]"),
- N_("git merge [<options>] <msg> HEAD <commit>"),
N_("git merge --abort"),
N_("git merge --continue"),
NULL
@@ -244,7 +243,7 @@ static void drop_save(void)
unlink(git_path_merge_mode());
}
-static int save_state(unsigned char *stash)
+static int save_state(struct object_id *stash)
{
int len;
struct child_process cp = CHILD_PROCESS_INIT;
@@ -265,7 +264,7 @@ static int save_state(unsigned char *stash)
else if (!len) /* no changes */
return -1;
strbuf_setlen(&buffer, buffer.len-1);
- if (get_sha1(buffer.buf, stash))
+ if (get_oid(buffer.buf, stash))
die(_("not a valid object: %s"), buffer.buf);
return 0;
}
@@ -305,18 +304,18 @@ static void reset_hard(unsigned const char *sha1, int verbose)
die(_("read-tree failed"));
}
-static void restore_state(const unsigned char *head,
- const unsigned char *stash)
+static void restore_state(const struct object_id *head,
+ const struct object_id *stash)
{
struct strbuf sb = STRBUF_INIT;
const char *args[] = { "stash", "apply", NULL, NULL };
- if (is_null_sha1(stash))
+ if (is_null_oid(stash))
return;
- reset_hard(head, 1);
+ reset_hard(head->hash, 1);
- args[2] = sha1_to_hex(stash);
+ args[2] = oid_to_hex(stash);
/*
* It is OK to ignore error here, for example when there was
@@ -376,10 +375,10 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
static void finish(struct commit *head_commit,
struct commit_list *remoteheads,
- const unsigned char *new_head, const char *msg)
+ const struct object_id *new_head, const char *msg)
{
struct strbuf reflog_message = STRBUF_INIT;
- const unsigned char *head = head_commit->object.oid.hash;
+ const struct object_id *head = &head_commit->object.oid;
if (!msg)
strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION"));
@@ -397,7 +396,7 @@ static void finish(struct commit *head_commit,
else {
const char *argv_gc_auto[] = { "gc", "--auto", NULL };
update_ref(reflog_message.buf, "HEAD",
- new_head, head, 0,
+ new_head->hash, head->hash, 0,
UPDATE_REFS_DIE_ON_ERR);
/*
* We ignore errors in 'gc --auto', since the
@@ -416,7 +415,7 @@ static void finish(struct commit *head_commit,
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
diff_setup_done(&opts);
- diff_tree_sha1(head, new_head, "", &opts);
+ diff_tree_sha1(head->hash, new_head->hash, "", &opts);
diffcore_std(&opts);
diff_flush(&opts);
}
@@ -431,7 +430,7 @@ static void finish(struct commit *head_commit,
static void merge_name(const char *remote, struct strbuf *msg)
{
struct commit *remote_head;
- unsigned char branch_head[20];
+ struct object_id branch_head;
struct strbuf buf = STRBUF_INIT;
struct strbuf bname = STRBUF_INIT;
const char *ptr;
@@ -441,25 +440,25 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_branchname(&bname, remote, 0);
remote = bname.buf;
- memset(branch_head, 0, sizeof(branch_head));
+ oidclr(&branch_head);
remote_head = get_merge_parent(remote);
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
- if (dwim_ref(remote, strlen(remote), branch_head, &found_ref) > 0) {
+ if (dwim_ref(remote, strlen(remote), branch_head.hash, &found_ref) > 0) {
if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
- sha1_to_hex(branch_head), remote);
+ oid_to_hex(&branch_head), remote);
goto cleanup;
}
if (starts_with(found_ref, "refs/tags/")) {
strbuf_addf(msg, "%s\t\ttag '%s' of .\n",
- sha1_to_hex(branch_head), remote);
+ oid_to_hex(&branch_head), remote);
goto cleanup;
}
if (starts_with(found_ref, "refs/remotes/")) {
strbuf_addf(msg, "%s\t\tremote-tracking branch '%s' of .\n",
- sha1_to_hex(branch_head), remote);
+ oid_to_hex(&branch_head), remote);
goto cleanup;
}
}
@@ -590,8 +589,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
return git_diff_ui_config(k, v, cb);
}
-static int read_tree_trivial(unsigned char *common, unsigned char *head,
- unsigned char *one)
+static int read_tree_trivial(struct object_id *common, struct object_id *head,
+ struct object_id *one)
{
int i, nr_trees = 0;
struct tree *trees[MAX_UNPACK_TREES];
@@ -606,13 +605,13 @@ static int read_tree_trivial(unsigned char *common, unsigned char *head,
opts.verbose_update = 1;
opts.trivial_merges_only = 1;
opts.merge = 1;
- trees[nr_trees] = parse_tree_indirect(common);
+ trees[nr_trees] = parse_tree_indirect(common->hash);
if (!trees[nr_trees++])
return -1;
- trees[nr_trees] = parse_tree_indirect(head);
+ trees[nr_trees] = parse_tree_indirect(head->hash);
if (!trees[nr_trees++])
return -1;
- trees[nr_trees] = parse_tree_indirect(one);
+ trees[nr_trees] = parse_tree_indirect(one->hash);
if (!trees[nr_trees++])
return -1;
opts.fn = threeway_merge;
@@ -626,17 +625,18 @@ static int read_tree_trivial(unsigned char *common, unsigned char *head,
return 0;
}
-static void write_tree_trivial(unsigned char *sha1)
+static void write_tree_trivial(struct object_id *oid)
{
- if (write_cache_as_tree(sha1, 0, NULL))
+ if (write_cache_as_tree(oid->hash, 0, NULL))
die(_("git write-tree failed to write a tree"));
}
static int try_merge_strategy(const char *strategy, struct commit_list *common,
struct commit_list *remoteheads,
- struct commit *head, const char *head_arg)
+ struct commit *head)
{
static struct lock_file lock;
+ const char *head_arg = "HEAD";
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
@@ -781,7 +781,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
{
- unsigned char result_tree[20], result_commit[20];
+ struct object_id result_tree, result_commit;
struct commit_list *parents, **pptr = &parents;
static struct lock_file lock;
@@ -792,15 +792,15 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
return error(_("Unable to write index."));
rollback_lock_file(&lock);
- write_tree_trivial(result_tree);
+ write_tree_trivial(&result_tree);
printf(_("Wonderful.\n"));
pptr = commit_list_append(head, pptr);
pptr = commit_list_append(remoteheads->item, pptr);
prepare_to_commit(remoteheads);
- if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
- result_commit, NULL, sign_commit))
+ if (commit_tree(merge_msg.buf, merge_msg.len, result_tree.hash, parents,
+ result_commit.hash, NULL, sign_commit))
die(_("failed to write commit object"));
- finish(head, remoteheads, result_commit, "In-index merge");
+ finish(head, remoteheads, &result_commit, "In-index merge");
drop_save();
return 0;
}
@@ -809,12 +809,12 @@ static int finish_automerge(struct commit *head,
int head_subsumed,
struct commit_list *common,
struct commit_list *remoteheads,
- unsigned char *result_tree,
+ struct object_id *result_tree,
const char *wt_strategy)
{
struct commit_list *parents = NULL;
struct strbuf buf = STRBUF_INIT;
- unsigned char result_commit[20];
+ struct object_id result_commit;
free_commit_list(common);
parents = remoteheads;
@@ -822,11 +822,11 @@ static int finish_automerge(struct commit *head,
commit_list_insert(head, &parents);
strbuf_addch(&merge_msg, '\n');
prepare_to_commit(remoteheads);
- if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
- result_commit, NULL, sign_commit))
+ if (commit_tree(merge_msg.buf, merge_msg.len, result_tree->hash, parents,
+ result_commit.hash, NULL, sign_commit))
die(_("failed to write commit object"));
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
- finish(head, remoteheads, result_commit, buf.buf);
+ finish(head, remoteheads, &result_commit, buf.buf);
strbuf_release(&buf);
drop_save();
return 0;
@@ -853,24 +853,6 @@ static int suggest_conflicts(void)
return 1;
}
-static struct commit *is_old_style_invocation(int argc, const char **argv,
- const unsigned char *head)
-{
- struct commit *second_token = NULL;
- if (argc > 2) {
- unsigned char second_sha1[20];
-
- if (get_sha1(argv[1], second_sha1))
- return NULL;
- second_token = lookup_commit_reference_gently(second_sha1, 0);
- if (!second_token)
- die(_("'%s' is not a commit"), argv[1]);
- if (hashcmp(second_token->object.oid.hash, head))
- return NULL;
- }
- return second_token;
-}
-
static int evaluate_result(void)
{
int cnt = 0;
@@ -1038,7 +1020,7 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
die_errno(_("could not close '%s'"), filename);
for (pos = 0; pos < merge_names->len; pos = npos) {
- unsigned char sha1[20];
+ struct object_id oid;
char *ptr;
struct commit *commit;
@@ -1048,16 +1030,16 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
else
npos = merge_names->len;
- if (npos - pos < 40 + 2 ||
- get_sha1_hex(merge_names->buf + pos, sha1))
+ if (npos - pos < GIT_SHA1_HEXSZ + 2 ||
+ get_oid_hex(merge_names->buf + pos, &oid))
commit = NULL; /* bad */
- else if (memcmp(merge_names->buf + pos + 40, "\t\t", 2))
+ else if (memcmp(merge_names->buf + pos + GIT_SHA1_HEXSZ, "\t\t", 2))
continue; /* not-for-merge */
else {
- char saved = merge_names->buf[pos + 40];
- merge_names->buf[pos + 40] = '\0';
+ char saved = merge_names->buf[pos + GIT_SHA1_HEXSZ];
+ merge_names->buf[pos + GIT_SHA1_HEXSZ] = '\0';
commit = get_merge_parent(merge_names->buf + pos);
- merge_names->buf[pos + 40] = saved;
+ merge_names->buf[pos + GIT_SHA1_HEXSZ] = saved;
}
if (!commit) {
if (ptr)
@@ -1117,12 +1099,9 @@ static struct commit_list *collect_parents(struct commit *head_commit,
int cmd_merge(int argc, const char **argv, const char *prefix)
{
- unsigned char result_tree[20];
- unsigned char stash[20];
- unsigned char head_sha1[20];
+ struct object_id result_tree, stash, head_oid;
struct commit *head_commit;
struct strbuf buf = STRBUF_INIT;
- const char *head_arg;
int i, ret = 0, head_subsumed;
int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
struct commit_list *common = NULL;
@@ -1138,13 +1117,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* Check if we are _not_ on a detached HEAD, i.e. if there is a
* current branch.
*/
- branch = branch_to_free = resolve_refdup("HEAD", 0, head_sha1, NULL);
+ branch = branch_to_free = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
if (branch && starts_with(branch, "refs/heads/"))
branch += 11;
- if (!branch || is_null_sha1(head_sha1))
+ if (!branch || is_null_oid(&head_oid))
head_commit = NULL;
else
- head_commit = lookup_commit_or_die(head_sha1, "HEAD");
+ head_commit = lookup_commit_or_die(head_oid.hash, "HEAD");
init_diff_ui_defaults();
git_config(git_merge_config, NULL);
@@ -1242,7 +1221,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* to forbid "git merge" into a branch yet to be born.
* We do the same for "git pull".
*/
- unsigned char *remote_head_sha1;
+ struct object_id *remote_head_oid;
if (squash)
die(_("Squash commit into empty head not supported yet"));
if (fast_forward == FF_NO)
@@ -1254,42 +1233,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die(_("%s - not something we can merge"), argv[0]);
if (remoteheads->next)
die(_("Can merge only exactly one commit into empty head"));
- remote_head_sha1 = remoteheads->item->object.oid.hash;
- read_empty(remote_head_sha1, 0);
- update_ref("initial pull", "HEAD", remote_head_sha1,
+ remote_head_oid = &remoteheads->item->object.oid;
+ read_empty(remote_head_oid->hash, 0);
+ update_ref("initial pull", "HEAD", remote_head_oid->hash,
NULL, 0, UPDATE_REFS_DIE_ON_ERR);
goto done;
}
/*
- * This could be traditional "merge <msg> HEAD <commit>..." and
- * the way we can tell it is to see if the second token is HEAD,
- * but some people might have misused the interface and used a
- * commit-ish that is the same as HEAD there instead.
- * Traditional format never would have "-m" so it is an
- * additional safety measure to check for it.
+ * All the rest are the commits being merged; prepare
+ * the standard merge summary message to be appended
+ * to the given message.
*/
- if (!have_message &&
- is_old_style_invocation(argc, argv, head_commit->object.oid.hash)) {
- warning("old-style 'git merge <msg> HEAD <commit>' is deprecated.");
- strbuf_addstr(&merge_msg, argv[0]);
- head_arg = argv[1];
- argv += 2;
- argc -= 2;
- remoteheads = collect_parents(head_commit, &head_subsumed,
- argc, argv, NULL);
- } else {
- /* We are invoked directly as the first-class UI. */
- head_arg = "HEAD";
-
- /*
- * All the rest are the commits being merged; prepare
- * the standard merge summary message to be appended
- * to the given message.
- */
- remoteheads = collect_parents(head_commit, &head_subsumed,
- argc, argv, &merge_msg);
- }
+ remoteheads = collect_parents(head_commit, &head_subsumed,
+ argc, argv, &merge_msg);
if (!head_commit || !argc)
usage_with_options(builtin_merge_usage,
@@ -1298,7 +1255,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (verify_signatures) {
for (p = remoteheads; p; p = p->next) {
struct commit *commit = p->item;
- char hex[GIT_SHA1_HEXSZ + 1];
+ char hex[GIT_MAX_HEXSZ + 1];
struct signature_check signature_check;
memset(&signature_check, 0, sizeof(signature_check));
@@ -1422,7 +1379,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
goto done;
}
- finish(head_commit, remoteheads, commit->object.oid.hash, msg.buf);
+ finish(head_commit, remoteheads, &commit->object.oid, msg.buf);
drop_save();
goto done;
} else if (!remoteheads->next && common->next)
@@ -1441,9 +1398,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
/* See if it is really trivial. */
git_committer_info(IDENT_STRICT);
printf(_("Trying really trivial in-index merge...\n"));
- if (!read_tree_trivial(common->item->object.oid.hash,
- head_commit->object.oid.hash,
- remoteheads->item->object.oid.hash)) {
+ if (!read_tree_trivial(&common->item->object.oid,
+ &head_commit->object.oid,
+ &remoteheads->item->object.oid)) {
ret = merge_trivial(head_commit, remoteheads);
goto done;
}
@@ -1495,14 +1452,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
/*
* Stash away the local changes so that we can try more than one.
*/
- save_state(stash))
- hashclr(stash);
+ save_state(&stash))
+ oidclr(&stash);
for (i = 0; i < use_strategies_nr; i++) {
int ret;
if (i) {
printf(_("Rewinding the tree to pristine...\n"));
- restore_state(head_commit->object.oid.hash, stash);
+ restore_state(&head_commit->object.oid, &stash);
}
if (use_strategies_nr != 1)
printf(_("Trying merge strategy %s...\n"),
@@ -1515,7 +1472,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
ret = try_merge_strategy(use_strategies[i]->name,
common, remoteheads,
- head_commit, head_arg);
+ head_commit);
if (!option_commit && !ret) {
merge_was_ok = 1;
/*
@@ -1547,7 +1504,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
/* Automerge succeeded. */
- write_tree_trivial(result_tree);
+ write_tree_trivial(&result_tree);
automerge_was_ok = 1;
break;
}
@@ -1559,7 +1516,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (automerge_was_ok) {
ret = finish_automerge(head_commit, head_subsumed,
common, remoteheads,
- result_tree, wt_strategy);
+ &result_tree, wt_strategy);
goto done;
}
@@ -1568,7 +1525,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* it up.
*/
if (!best_strategy) {
- restore_state(head_commit->object.oid.hash, stash);
+ restore_state(&head_commit->object.oid, &stash);
if (use_strategies_nr > 1)
fprintf(stderr,
_("No merge strategy handled the merge.\n"));
@@ -1581,11 +1538,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
; /* We already have its result in the working tree. */
else {
printf(_("Rewinding the tree to pristine...\n"));
- restore_state(head_commit->object.oid.hash, stash);
+ restore_state(&head_commit->object.oid, &stash);
printf(_("Using the %s to prepare resolving by hand.\n"),
best_strategy);
try_merge_strategy(best_strategy, common, remoteheads,
- head_commit, head_arg);
+ head_commit);
}
if (squash)
diff --git a/builtin/mktree.c b/builtin/mktree.c
index de9b40fc63..da0fd8cd70 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
unsigned mode;
enum object_type mode_type; /* object type derived from mode */
enum object_type obj_type; /* object type derived from sha */
- char *path;
+ char *path, *to_free = NULL;
unsigned char sha1[20];
ptr = buf;
@@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
struct strbuf p_uq = STRBUF_INIT;
if (unquote_c_style(&p_uq, path, NULL))
die("invalid quoting");
- path = strbuf_detach(&p_uq, NULL);
+ path = to_free = strbuf_detach(&p_uq, NULL);
}
/*
@@ -136,6 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
}
append_to_tree(mode, sha1, path);
+ free(to_free);
}
int cmd_mktree(int ac, const char **av, const char *prefix)
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index cd89d48b65..e7a3fe7ee7 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
struct rev_name *name = (struct rev_name *)commit->util;
struct commit_list *parents;
int parent_number = 1;
+ char *to_free = NULL;
parse_commit(commit);
@@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
return;
if (deref) {
- tip_name = xstrfmt("%s^0", tip_name);
+ tip_name = to_free = xstrfmt("%s^0", tip_name);
if (generation)
die("generation: %d, but deref?", generation);
@@ -53,8 +54,10 @@ copy_data:
name->taggerdate = taggerdate;
name->generation = generation;
name->distance = distance;
- } else
+ } else {
+ free(to_free);
return;
+ }
for (parents = commit->parents;
parents;
@@ -108,7 +111,8 @@ static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
struct name_ref_data {
int tags_only;
int name_only;
- const char *ref_filter;
+ struct string_list ref_filters;
+ struct string_list exclude_filters;
};
static struct tip_table {
@@ -150,18 +154,49 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
if (data->tags_only && !starts_with(path, "refs/tags/"))
return 0;
- if (data->ref_filter) {
- switch (subpath_matches(path, data->ref_filter)) {
- case -1: /* did not match */
- return 0;
- case 0: /* matched fully */
- break;
- default: /* matched subpath */
- can_abbreviate_output = 1;
- break;
+ if (data->exclude_filters.nr) {
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, &data->exclude_filters) {
+ if (subpath_matches(path, item->string) >= 0)
+ return 0;
}
}
+ if (data->ref_filters.nr) {
+ struct string_list_item *item;
+ int matched = 0;
+
+ /* See if any of the patterns match. */
+ for_each_string_list_item(item, &data->ref_filters) {
+ /*
+ * Check all patterns even after finding a match, so
+ * that we can see if a match with a subpath exists.
+ * When a user asked for 'refs/tags/v*' and 'v1.*',
+ * both of which match, the user is showing her
+ * willingness to accept a shortened output by having
+ * the 'v1.*' in the acceptable refnames, so we
+ * shouldn't stop when seeing 'refs/tags/v1.4' matches
+ * 'refs/tags/v*'. We should show it as 'v1.4'.
+ */
+ switch (subpath_matches(path, item->string)) {
+ case -1: /* did not match */
+ break;
+ case 0: /* matched fully */
+ matched = 1;
+ break;
+ default: /* matched subpath */
+ matched = 1;
+ can_abbreviate_output = 1;
+ break;
+ }
+ }
+
+ /* If none of the patterns matched, stop now */
+ if (!matched)
+ return 0;
+ }
+
add_to_tip_table(oid->hash, path, can_abbreviate_output);
while (o && o->type == OBJ_TAG) {
@@ -206,10 +241,9 @@ static const char *get_exact_ref_match(const struct object *o)
return NULL;
}
-/* returns a static buffer */
-static const char *get_rev_name(const struct object *o)
+/* may return a constant string or use "buf" as scratch space */
+static const char *get_rev_name(const struct object *o, struct strbuf *buf)
{
- static char buffer[1024];
struct rev_name *n;
struct commit *c;
@@ -226,10 +260,9 @@ static const char *get_rev_name(const struct object *o)
int len = strlen(n->tip_name);
if (len > 2 && !strcmp(n->tip_name + len - 2, "^0"))
len -= 2;
- snprintf(buffer, sizeof(buffer), "%.*s~%d", len, n->tip_name,
- n->generation);
-
- return buffer;
+ strbuf_reset(buf);
+ strbuf_addf(buf, "%.*s~%d", len, n->tip_name, n->generation);
+ return buf->buf;
}
}
@@ -239,10 +272,11 @@ static void show_name(const struct object *obj,
{
const char *name;
const struct object_id *oid = &obj->oid;
+ struct strbuf buf = STRBUF_INIT;
if (!name_only)
printf("%s ", caller_name ? caller_name : oid_to_hex(oid));
- name = get_rev_name(obj);
+ name = get_rev_name(obj, &buf);
if (name)
printf("%s\n", name);
else if (allow_undefined)
@@ -251,6 +285,7 @@ static void show_name(const struct object *obj,
printf("%s\n", find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
else
die("cannot describe '%s'", oid_to_hex(oid));
+ strbuf_release(&buf);
}
static char const * const name_rev_usage[] = {
@@ -262,6 +297,7 @@ static char const * const name_rev_usage[] = {
static void name_rev_line(char *p, struct name_ref_data *data)
{
+ struct strbuf buf = STRBUF_INIT;
int forty = 0;
char *p_start;
for (p_start = p; *p; p++) {
@@ -282,7 +318,7 @@ static void name_rev_line(char *p, struct name_ref_data *data)
struct object *o =
lookup_object(sha1);
if (o)
- name = get_rev_name(o);
+ name = get_rev_name(o, &buf);
}
*(p+1) = c;
@@ -300,18 +336,22 @@ static void name_rev_line(char *p, struct name_ref_data *data)
/* flush */
if (p_start != p)
fwrite(p_start, p - p_start, 1, stdout);
+
+ strbuf_release(&buf);
}
int cmd_name_rev(int argc, const char **argv, const char *prefix)
{
struct object_array revs = OBJECT_ARRAY_INIT;
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
- struct name_ref_data data = { 0, 0, NULL };
+ struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
struct option opts[] = {
OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
- OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
+ OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
N_("only use refs matching <pattern>")),
+ OPT_STRING_LIST(0, "exclude", &data.exclude_filters, N_("pattern"),
+ N_("ignore refs matching <pattern>")),
OPT_GROUP(""),
OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
OPT_BOOL(0, "stdin", &transform_stdin, N_("read from stdin")),
diff --git a/builtin/notes.c b/builtin/notes.c
index 5248a9bad8..fb856e53b6 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -340,8 +340,10 @@ static struct notes_tree *init_notes_check(const char *subcommand,
ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref;
if (!starts_with(ref, "refs/notes/"))
- /* TRANSLATORS: the first %s will be replaced by a
- git notes command: 'add', 'merge', 'remove', etc.*/
+ /*
+ * TRANSLATORS: the first %s will be replaced by a git
+ * notes command: 'add', 'merge', 'remove', etc.
+ */
die(_("refusing to %s notes in %s (outside of refs/notes/)"),
subcommand, ref);
return t;
@@ -554,7 +556,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
struct notes_tree *t;
unsigned char object[20], new_note[20];
const unsigned char *note;
- char logmsg[100];
+ char *logmsg;
const char * const *usage;
struct note_data d = { 0, 0, NULL, STRBUF_INIT };
struct option options[] = {
@@ -618,17 +620,16 @@ static int append_edit(int argc, const char **argv, const char *prefix)
write_note_data(&d, new_note);
if (add_note(t, object, new_note, combine_notes_overwrite))
die("BUG: combine_notes_overwrite failed");
- snprintf(logmsg, sizeof(logmsg), "Notes added by 'git notes %s'",
- argv[0]);
+ logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
} else {
fprintf(stderr, _("Removing note for object %s\n"),
sha1_to_hex(object));
remove_note(t, object);
- snprintf(logmsg, sizeof(logmsg), "Notes removed by 'git notes %s'",
- argv[0]);
+ logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]);
}
commit_notes(t, logmsg);
+ free(logmsg);
free_note_data(&d);
free_notes(t);
return 0;
@@ -681,9 +682,9 @@ static int merge_abort(struct notes_merge_options *o)
* notes_merge_abort() to remove .git/NOTES_MERGE_WORKTREE.
*/
- if (delete_ref("NOTES_MERGE_PARTIAL", NULL, 0))
+ if (delete_ref(NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
- if (delete_ref("NOTES_MERGE_REF", NULL, REF_NODEREF))
+ if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NODEREF))
ret += error(_("failed to delete ref NOTES_MERGE_REF"));
if (notes_merge_abort(o))
ret += error(_("failed to remove 'git notes merge' worktree"));
@@ -693,7 +694,7 @@ static int merge_abort(struct notes_merge_options *o)
static int merge_commit(struct notes_merge_options *o)
{
struct strbuf msg = STRBUF_INIT;
- unsigned char sha1[20], parent_sha1[20];
+ struct object_id oid, parent_oid;
struct notes_tree *t;
struct commit *partial;
struct pretty_print_context pretty_ctx;
@@ -705,27 +706,27 @@ static int merge_commit(struct notes_merge_options *o)
* and target notes ref from .git/NOTES_MERGE_REF.
*/
- if (get_sha1("NOTES_MERGE_PARTIAL", sha1))
+ if (get_oid("NOTES_MERGE_PARTIAL", &oid))
die(_("failed to read ref NOTES_MERGE_PARTIAL"));
- else if (!(partial = lookup_commit_reference(sha1)))
+ else if (!(partial = lookup_commit_reference(oid.hash)))
die(_("could not find commit from NOTES_MERGE_PARTIAL."));
else if (parse_commit(partial))
die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
if (partial->parents)
- hashcpy(parent_sha1, partial->parents->item->object.oid.hash);
+ oidcpy(&parent_oid, &partial->parents->item->object.oid);
else
- hashclr(parent_sha1);
+ oidclr(&parent_oid);
t = xcalloc(1, sizeof(struct notes_tree));
init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
o->local_ref = local_ref_to_free =
- resolve_refdup("NOTES_MERGE_REF", 0, sha1, NULL);
+ resolve_refdup("NOTES_MERGE_REF", 0, oid.hash, NULL);
if (!o->local_ref)
die(_("failed to resolve NOTES_MERGE_REF"));
- if (notes_merge_commit(o, t, partial, sha1))
+ if (notes_merge_commit(o, t, partial, oid.hash))
die(_("failed to finalize notes merge"));
/* Reuse existing commit message in reflog message */
@@ -733,8 +734,8 @@ static int merge_commit(struct notes_merge_options *o)
format_commit_message(partial, "%s", &msg, &pretty_ctx);
strbuf_trim(&msg);
strbuf_insert(&msg, 0, "notes: ", 7);
- update_ref(msg.buf, o->local_ref, sha1,
- is_null_sha1(parent_sha1) ? NULL : parent_sha1,
+ update_ref(msg.buf, o->local_ref, oid.hash,
+ is_null_oid(&parent_oid) ? NULL : parent_oid.hash,
0, UPDATE_REFS_DIE_ON_ERR);
free_notes(t);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index c7af475485..50e01aa80e 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -239,7 +239,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
unsigned long limit, int usable_delta)
{
unsigned long size, datalen;
- unsigned char header[10], dheader[10];
+ unsigned char header[MAX_PACK_OBJECT_HEADER],
+ dheader[MAX_PACK_OBJECT_HEADER];
unsigned hdrlen;
enum object_type type;
void *buf;
@@ -286,7 +287,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
* The object header is a byte of 'type' followed by zero or
* more bytes of length.
*/
- hdrlen = encode_in_pack_object_header(type, size, header);
+ hdrlen = encode_in_pack_object_header(header, sizeof(header),
+ type, size);
if (type == OBJ_OFS_DELTA) {
/*
@@ -352,13 +354,15 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
off_t offset;
enum object_type type = entry->type;
off_t datalen;
- unsigned char header[10], dheader[10];
+ unsigned char header[MAX_PACK_OBJECT_HEADER],
+ dheader[MAX_PACK_OBJECT_HEADER];
unsigned hdrlen;
if (entry->delta)
type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
- hdrlen = encode_in_pack_object_header(type, entry->size, header);
+ hdrlen = encode_in_pack_object_header(header, sizeof(header),
+ type, entry->size);
offset = entry->in_pack_offset;
revidx = find_pack_revindex(p, offset);
@@ -894,24 +898,15 @@ static void write_pack_file(void)
written, nr_result);
}
-static void setup_delta_attr_check(struct git_attr_check *check)
-{
- static struct git_attr *attr_delta;
-
- if (!attr_delta)
- attr_delta = git_attr("delta");
-
- check[0].attr = attr_delta;
-}
-
static int no_try_delta(const char *path)
{
- struct git_attr_check check[1];
+ static struct attr_check *check;
- setup_delta_attr_check(check);
- if (git_check_attr(path, ARRAY_SIZE(check), check))
+ if (!check)
+ check = attr_check_initl("delta", NULL);
+ if (git_check_attr(path, check))
return 0;
- if (ATTR_FALSE(check->value))
+ if (ATTR_FALSE(check->items[0].value))
return 1;
return 0;
}
@@ -2621,17 +2616,17 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
free(in_pack.array);
}
-static int add_loose_object(const unsigned char *sha1, const char *path,
+static int add_loose_object(const struct object_id *oid, const char *path,
void *data)
{
- enum object_type type = sha1_object_info(sha1, NULL);
+ enum object_type type = sha1_object_info(oid->hash, NULL);
if (type < 0) {
warning("loose object at %s could not be examined", path);
return 0;
}
- add_object_entry(sha1, type, "", 0);
+ add_object_entry(oid->hash, type, "", 0);
return 0;
}
@@ -2677,16 +2672,16 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
*
* This is filled by get_object_list.
*/
-static struct sha1_array recent_objects;
+static struct oid_array recent_objects;
-static int loosened_object_can_be_discarded(const unsigned char *sha1,
+static int loosened_object_can_be_discarded(const struct object_id *oid,
unsigned long mtime)
{
if (!unpack_unreachable_expiration)
return 0;
if (mtime > unpack_unreachable_expiration)
return 0;
- if (sha1_array_lookup(&recent_objects, sha1) >= 0)
+ if (oid_array_lookup(&recent_objects, oid) >= 0)
return 0;
return 1;
}
@@ -2695,7 +2690,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
{
struct packed_git *p;
uint32_t i;
- const unsigned char *sha1;
+ struct object_id oid;
for (p = packed_git; p; p = p->next) {
if (!p->pack_local || p->pack_keep)
@@ -2705,11 +2700,11 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
die("cannot open pack index");
for (i = 0; i < p->num_objects; i++) {
- sha1 = nth_packed_object_sha1(p, i);
- if (!packlist_find(&to_pack, sha1, NULL) &&
- !has_sha1_pack_kept_or_nonlocal(sha1) &&
- !loosened_object_can_be_discarded(sha1, p->mtime))
- if (force_object_loose(sha1, p->mtime))
+ nth_packed_object_oid(&oid, p, i);
+ if (!packlist_find(&to_pack, oid.hash, NULL) &&
+ !has_sha1_pack_kept_or_nonlocal(oid.hash) &&
+ !loosened_object_can_be_discarded(&oid, p->mtime))
+ if (force_object_loose(oid.hash, p->mtime))
die("unable to force loose object");
}
}
@@ -2722,7 +2717,11 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
*/
static int pack_options_allow_reuse(void)
{
- return pack_to_stdout && allow_ofs_delta;
+ return pack_to_stdout &&
+ allow_ofs_delta &&
+ !ignore_packed_keep &&
+ (!local || !have_non_local_packs) &&
+ !incremental;
}
static int get_object_list_from_bitmap(struct rev_info *revs)
@@ -2748,12 +2747,12 @@ static void record_recent_object(struct object *obj,
const char *name,
void *data)
{
- sha1_array_append(&recent_objects, obj->oid.hash);
+ oid_array_append(&recent_objects, &obj->oid);
}
static void record_recent_commit(struct commit *commit, void *data)
{
- sha1_array_append(&recent_objects, commit->object.oid.hash);
+ oid_array_append(&recent_objects, &commit->object.oid);
}
static void get_object_list(int ac, const char **av)
@@ -2821,7 +2820,7 @@ static void get_object_list(int ac, const char **av)
if (unpack_unreachable)
loosen_unused_packed_objects(&revs);
- sha1_array_clear(&recent_objects);
+ oid_array_clear(&recent_objects);
}
static int option_parse_index_version(const struct option *opt,
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 72c815844d..cb1df1c761 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -442,6 +442,7 @@ static void minimize(struct pack_list **min)
/* return if there are no objects missing from the unique set */
if (missing->size == 0) {
*min = unique;
+ free(missing);
return;
}
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index 39f9a55d16..b106a392a4 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -17,5 +17,5 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
};
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
usage_with_options(pack_refs_usage, opts);
- return pack_refs(flags);
+ return refs_pack_refs(get_main_ref_store(), flags);
}
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index a84d0003a3..81552e02e4 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -55,7 +55,7 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
static void flush_one_hunk(struct object_id *result, git_SHA_CTX *ctx)
{
- unsigned char hash[GIT_SHA1_RAWSZ];
+ unsigned char hash[GIT_MAX_RAWSZ];
unsigned short carry = 0;
int i;
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index 7cf900ea07..c026299e78 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -19,12 +19,12 @@ static int prune_subdir(int nr, const char *path, void *data)
return 0;
}
-static int prune_object(const unsigned char *sha1, const char *path,
+static int prune_object(const struct object_id *oid, const char *path,
void *data)
{
int *opts = data;
- if (!has_sha1_pack(sha1))
+ if (!has_sha1_pack(oid->hash))
return 0;
if (*opts & PRUNE_PACKED_DRY_RUN)
diff --git a/builtin/prune.c b/builtin/prune.c
index 8f4f052285..42633e0c6e 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -30,7 +30,7 @@ static int prune_tmp_file(const char *fullpath)
return 0;
}
-static int prune_object(const unsigned char *sha1, const char *fullpath,
+static int prune_object(const struct object_id *oid, const char *fullpath,
void *data)
{
struct stat st;
@@ -39,7 +39,7 @@ static int prune_object(const unsigned char *sha1, const char *fullpath,
* Do we know about this object?
* It must have been reachable
*/
- if (lookup_object(sha1))
+ if (lookup_object(oid->hash))
return 0;
if (lstat(fullpath, &st)) {
@@ -50,8 +50,8 @@ static int prune_object(const unsigned char *sha1, const char *fullpath,
if (st.st_mtime > expire)
return 0;
if (show_only || verbose) {
- enum object_type type = sha1_object_info(sha1, NULL);
- printf("%s %s\n", sha1_to_hex(sha1),
+ enum object_type type = sha1_object_info(oid->hash, NULL);
+ printf("%s %s\n", oid_to_hex(oid),
(type > 0) ? typename(type) : "unknown");
}
if (!show_only)
diff --git a/builtin/pull.c b/builtin/pull.c
index 3ecb881b0b..dd1a4a94e4 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -330,21 +330,21 @@ static int git_pull_config(const char *var, const char *value, void *cb)
* Appends merge candidates from FETCH_HEAD that are not marked not-for-merge
* into merge_heads.
*/
-static void get_merge_heads(struct sha1_array *merge_heads)
+static void get_merge_heads(struct oid_array *merge_heads)
{
- const char *filename = git_path("FETCH_HEAD");
+ const char *filename = git_path_fetch_head();
FILE *fp;
struct strbuf sb = STRBUF_INIT;
- unsigned char sha1[GIT_SHA1_RAWSZ];
+ struct object_id oid;
if (!(fp = fopen(filename, "r")))
die_errno(_("could not open '%s' for reading"), filename);
while (strbuf_getline_lf(&sb, fp) != EOF) {
- if (get_sha1_hex(sb.buf, sha1))
+ if (get_oid_hex(sb.buf, &oid))
continue; /* invalid line: does not start with SHA1 */
if (starts_with(sb.buf + GIT_SHA1_HEXSZ, "\tnot-for-merge\t"))
continue; /* ref is not-for-merge */
- sha1_array_append(merge_heads, sha1);
+ oid_array_append(merge_heads, &oid);
}
fclose(fp);
strbuf_release(&sb);
@@ -514,8 +514,8 @@ static int run_fetch(const char *repo, const char **refspecs)
/**
* "Pulls into void" by branching off merge_head.
*/
-static int pull_into_void(const unsigned char *merge_head,
- const unsigned char *curr_head)
+static int pull_into_void(const struct object_id *merge_head,
+ const struct object_id *curr_head)
{
/*
* Two-way merge: we treat the index as based on an empty tree,
@@ -523,10 +523,10 @@ static int pull_into_void(const unsigned char *merge_head,
* index/worktree changes that the user already made on the unborn
* branch.
*/
- if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0))
+ if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0))
return 1;
- if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+ if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
return 1;
return 0;
@@ -647,7 +647,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
* current branch forked from its remote tracking branch. Returns 0 on success,
* -1 on failure.
*/
-static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
+static int get_rebase_fork_point(struct object_id *fork_point, const char *repo,
const char *refspec)
{
int ret;
@@ -678,7 +678,7 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
if (ret)
goto cleanup;
- ret = get_sha1_hex(sb.buf, fork_point);
+ ret = get_oid_hex(sb.buf, fork_point);
if (ret)
goto cleanup;
@@ -691,24 +691,24 @@ cleanup:
* Sets merge_base to the octopus merge base of curr_head, merge_head and
* fork_point. Returns 0 if a merge base is found, 1 otherwise.
*/
-static int get_octopus_merge_base(unsigned char *merge_base,
- const unsigned char *curr_head,
- const unsigned char *merge_head,
- const unsigned char *fork_point)
+static int get_octopus_merge_base(struct object_id *merge_base,
+ const struct object_id *curr_head,
+ const struct object_id *merge_head,
+ const struct object_id *fork_point)
{
struct commit_list *revs = NULL, *result;
- commit_list_insert(lookup_commit_reference(curr_head), &revs);
- commit_list_insert(lookup_commit_reference(merge_head), &revs);
- if (!is_null_sha1(fork_point))
- commit_list_insert(lookup_commit_reference(fork_point), &revs);
+ commit_list_insert(lookup_commit_reference(curr_head->hash), &revs);
+ commit_list_insert(lookup_commit_reference(merge_head->hash), &revs);
+ if (!is_null_oid(fork_point))
+ commit_list_insert(lookup_commit_reference(fork_point->hash), &revs);
result = reduce_heads(get_octopus_merge_bases(revs));
free_commit_list(revs);
if (!result)
return 1;
- hashcpy(merge_base, result->item->object.oid.hash);
+ oidcpy(merge_base, &result->item->object.oid);
return 0;
}
@@ -717,16 +717,16 @@ static int get_octopus_merge_base(unsigned char *merge_base,
* fork point calculated by get_rebase_fork_point(), runs git-rebase with the
* appropriate arguments and returns its exit status.
*/
-static int run_rebase(const unsigned char *curr_head,
- const unsigned char *merge_head,
- const unsigned char *fork_point)
+static int run_rebase(const struct object_id *curr_head,
+ const struct object_id *merge_head,
+ const struct object_id *fork_point)
{
int ret;
- unsigned char oct_merge_base[GIT_SHA1_RAWSZ];
+ struct object_id oct_merge_base;
struct argv_array args = ARGV_ARRAY_INIT;
- if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point))
- if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point))
+ if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point))
+ if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point))
fork_point = NULL;
argv_array_push(&args, "rebase");
@@ -754,12 +754,12 @@ static int run_rebase(const unsigned char *curr_head,
warning(_("ignoring --verify-signatures for rebase"));
argv_array_push(&args, "--onto");
- argv_array_push(&args, sha1_to_hex(merge_head));
+ argv_array_push(&args, oid_to_hex(merge_head));
- if (fork_point && !is_null_sha1(fork_point))
- argv_array_push(&args, sha1_to_hex(fork_point));
+ if (fork_point && !is_null_oid(fork_point))
+ argv_array_push(&args, oid_to_hex(fork_point));
else
- argv_array_push(&args, sha1_to_hex(merge_head));
+ argv_array_push(&args, oid_to_hex(merge_head));
ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
argv_array_clear(&args);
@@ -769,9 +769,9 @@ static int run_rebase(const unsigned char *curr_head,
int cmd_pull(int argc, const char **argv, const char *prefix)
{
const char *repo, **refspecs;
- struct sha1_array merge_heads = SHA1_ARRAY_INIT;
- unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ];
- unsigned char rebase_fork_point[GIT_SHA1_RAWSZ];
+ struct oid_array merge_heads = OID_ARRAY_INIT;
+ struct object_id orig_head, curr_head;
+ struct object_id rebase_fork_point;
if (!getenv("GIT_REFLOG_ACTION"))
set_reflog_message(argc, argv);
@@ -791,11 +791,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (read_cache_unmerged())
die_resolve_conflict("pull");
- if (file_exists(git_path("MERGE_HEAD")))
+ if (file_exists(git_path_merge_head()))
die_conclude_merge();
- if (get_sha1("HEAD", orig_head))
- hashclr(orig_head);
+ if (get_oid("HEAD", &orig_head))
+ oidclr(&orig_head);
if (!opt_rebase && opt_autostash != -1)
die(_("--[no-]autostash option is only valid with --rebase."));
@@ -805,15 +805,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (opt_autostash != -1)
autostash = opt_autostash;
- if (is_null_sha1(orig_head) && !is_cache_unborn())
+ if (is_null_oid(&orig_head) && !is_cache_unborn())
die(_("Updating an unborn branch with changes added to the index."));
if (!autostash)
require_clean_work_tree(N_("pull with rebase"),
_("please commit or stash them."), 1, 0);
- if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
- hashclr(rebase_fork_point);
+ if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
+ oidclr(&rebase_fork_point);
}
if (run_fetch(repo, refspecs))
@@ -822,11 +822,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (opt_dry_run)
return 0;
- if (get_sha1("HEAD", curr_head))
- hashclr(curr_head);
+ if (get_oid("HEAD", &curr_head))
+ oidclr(&curr_head);
- if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) &&
- hashcmp(orig_head, curr_head)) {
+ if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
+ oidcmp(&orig_head, &curr_head)) {
/*
* The fetch involved updating the current branch.
*
@@ -837,15 +837,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
warning(_("fetch updated the current branch head.\n"
"fast-forwarding your working tree from\n"
- "commit %s."), sha1_to_hex(orig_head));
+ "commit %s."), oid_to_hex(&orig_head));
- if (checkout_fast_forward(orig_head, curr_head, 0))
+ if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
die(_("Cannot fast-forward your working tree.\n"
"After making sure that you saved anything precious from\n"
"$ git diff %s\n"
"output, run\n"
"$ git reset --hard\n"
- "to recover."), sha1_to_hex(orig_head));
+ "to recover."), oid_to_hex(&orig_head));
}
get_merge_heads(&merge_heads);
@@ -853,10 +853,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (!merge_heads.nr)
die_no_merge_candidates(repo, refspecs);
- if (is_null_sha1(orig_head)) {
+ if (is_null_oid(&orig_head)) {
if (merge_heads.nr > 1)
die(_("Cannot merge multiple branches into empty head."));
- return pull_into_void(*merge_heads.sha1, curr_head);
+ return pull_into_void(merge_heads.oid, &curr_head);
}
if (opt_rebase && merge_heads.nr > 1)
die(_("Cannot rebase onto multiple branches."));
@@ -865,15 +865,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
struct commit_list *list = NULL;
struct commit *merge_head, *head;
- head = lookup_commit_reference(orig_head);
+ head = lookup_commit_reference(orig_head.hash);
commit_list_insert(head, &list);
- merge_head = lookup_commit_reference(merge_heads.sha1[0]);
+ merge_head = lookup_commit_reference(merge_heads.oid[0].hash);
if (is_descendant_of(merge_head, list)) {
/* we can fast-forward this without invoking rebase */
opt_ff = "--ff-only";
return run_merge();
}
- return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
+ return run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
} else {
return run_merge();
}
diff --git a/builtin/push.c b/builtin/push.c
index 5c22e9f2e5..a597759d8f 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -510,8 +510,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
int push_cert = -1;
int rc;
const char *repo = NULL; /* default repository */
- static struct string_list push_options = STRING_LIST_INIT_DUP;
- static struct string_list_item *item;
+ struct string_list push_options = STRING_LIST_INIT_DUP;
+ const struct string_list_item *item;
struct option options[] = {
OPT__VERBOSITY(&verbosity),
@@ -584,6 +584,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
die(_("push options must not have new line characters"));
rc = do_push(repo, flags, &push_options);
+ string_list_clear(&push_options, 0);
if (rc == -1)
usage_with_options(push_usage, options);
else
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 8ba64bc785..a52a9e11bb 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -15,10 +15,13 @@
#include "builtin.h"
#include "parse-options.h"
#include "resolve-undo.h"
+#include "submodule.h"
+#include "submodule-config.h"
static int nr_trees;
static int read_empty;
static struct tree *trees[MAX_UNPACK_TREES];
+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int list_tree(unsigned char *sha1)
{
@@ -96,6 +99,23 @@ static int debug_merge(const struct cache_entry * const *stages,
return 0;
}
+static int option_parse_recurse_submodules(const struct option *opt,
+ const char *arg, int unset)
+{
+ if (unset) {
+ recurse_submodules = RECURSE_SUBMODULES_OFF;
+ return 0;
+ }
+ if (arg)
+ recurse_submodules =
+ parse_update_recurse_submodules_arg(opt->long_name,
+ arg);
+ else
+ recurse_submodules = RECURSE_SUBMODULES_ON;
+
+ return 0;
+}
+
static struct lock_file lock_file;
int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
@@ -137,6 +157,9 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
N_("skip applying sparse checkout filter")),
OPT_BOOL(0, "debug-unpack", &opts.debug_unpack,
N_("debug unpack-trees")),
+ { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
+ "checkout", "control recursive updating of submodules",
+ PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_END()
};
@@ -152,6 +175,12 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {
+ gitmodules_config();
+ git_config(submodule_config, NULL);
+ set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);
+ }
+
prefix_set = opts.prefix ? 1 : 0;
if (1 < opts.merge + opts.reset + prefix_set)
die("Which one? -m, --reset, or --prefix?");
@@ -181,7 +210,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
die("failed to unpack tree object %s", arg);
stage++;
}
- if (nr_trees == 0 && !read_empty)
+ if (!nr_trees && !read_empty && !opts.merge)
warning("read-tree: emptying the index with no arguments is deprecated; use --empty");
else if (nr_trees > 0 && read_empty)
die("passing trees as arguments contradicts --empty");
@@ -197,9 +226,10 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
setup_work_tree();
if (opts.merge) {
- if (stage < 2)
- die("just how do you expect me to merge %d trees?", stage-1);
switch (stage - 1) {
+ case 0:
+ die("you must specify at least one tree to merge");
+ break;
case 1:
opts.fn = opts.prefix ? bind_merge : oneway_merge;
break;
diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c
new file mode 100644
index 0000000000..ca1ebb2fa1
--- /dev/null
+++ b/builtin/rebase--helper.c
@@ -0,0 +1,40 @@
+#include "builtin.h"
+#include "cache.h"
+#include "parse-options.h"
+#include "sequencer.h"
+
+static const char * const builtin_rebase_helper_usage[] = {
+ N_("git rebase--helper [<options>]"),
+ NULL
+};
+
+int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
+{
+ struct replay_opts opts = REPLAY_OPTS_INIT;
+ enum {
+ CONTINUE = 1, ABORT
+ } command = 0;
+ struct option options[] = {
+ OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
+ OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
+ CONTINUE),
+ OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
+ ABORT),
+ OPT_END()
+ };
+
+ git_config(git_default_config, NULL);
+
+ opts.action = REPLAY_INTERACTIVE_REBASE;
+ opts.allow_ff = 1;
+ opts.allow_empty = 1;
+
+ argc = parse_options(argc, argv, NULL, options,
+ builtin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);
+
+ if (command == CONTINUE && argc == 1)
+ return !!sequencer_continue(&opts);
+ if (command == ABORT && argc == 1)
+ return !!sequencer_remove_state(&opts);
+ usage_with_options(builtin_rebase_helper_usage, options);
+}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index b618d52139..da9a3a2c9d 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -21,6 +21,7 @@
#include "sigchain.h"
#include "fsck.h"
#include "tmp-objdir.h"
+#include "oidset.h"
static const char * const receive_pack_usage[] = {
N_("git receive-pack <git-dir>"),
@@ -224,10 +225,10 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
-static void show_ref(const char *path, const unsigned char *sha1)
+static void show_ref(const char *path, const struct object_id *oid)
{
if (sent_capabilities) {
- packet_write_fmt(1, "%s %s\n", sha1_to_hex(sha1), path);
+ packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), path);
} else {
struct strbuf cap = STRBUF_INIT;
@@ -243,15 +244,16 @@ static void show_ref(const char *path, const unsigned char *sha1)
strbuf_addstr(&cap, " push-options");
strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
packet_write_fmt(1, "%s %s%c%s\n",
- sha1_to_hex(sha1), path, 0, cap.buf);
+ oid_to_hex(oid), path, 0, cap.buf);
strbuf_release(&cap);
sent_capabilities = 1;
}
}
static int show_ref_cb(const char *path_full, const struct object_id *oid,
- int flag, void *unused)
+ int flag, void *data)
{
+ struct oidset *seen = data;
const char *path = strip_namespace(path_full);
if (ref_is_hidden(path, path_full))
@@ -260,39 +262,40 @@ static int show_ref_cb(const char *path_full, const struct object_id *oid,
/*
* Advertise refs outside our current namespace as ".have"
* refs, so that the client can use them to minimize data
- * transfer but will otherwise ignore them. This happens to
- * cover ".have" that are thrown in by add_one_alternate_ref()
- * to mark histories that are complete in our alternates as
- * well.
+ * transfer but will otherwise ignore them.
*/
- if (!path)
+ if (!path) {
+ if (oidset_insert(seen, oid))
+ return 0;
path = ".have";
- show_ref(path, oid->hash);
+ } else {
+ oidset_insert(seen, oid);
+ }
+ show_ref(path, oid);
return 0;
}
-static int show_one_alternate_sha1(const unsigned char sha1[20], void *unused)
+static void show_one_alternate_ref(const char *refname,
+ const struct object_id *oid,
+ void *data)
{
- show_ref(".have", sha1);
- return 0;
-}
+ struct oidset *seen = data;
-static void collect_one_alternate_ref(const struct ref *ref, void *data)
-{
- struct sha1_array *sa = data;
- sha1_array_append(sa, ref->old_oid.hash);
+ if (oidset_insert(seen, oid))
+ return;
+
+ show_ref(".have", oid);
}
static void write_head_info(void)
{
- struct sha1_array sa = SHA1_ARRAY_INIT;
+ static struct oidset seen = OIDSET_INIT;
- for_each_alternate_ref(collect_one_alternate_ref, &sa);
- sha1_array_for_each_unique(&sa, show_one_alternate_sha1, NULL);
- sha1_array_clear(&sa);
- for_each_ref(show_ref_cb, NULL);
+ for_each_ref(show_ref_cb, &seen);
+ for_each_alternate_ref(show_one_alternate_ref, &seen);
+ oidset_clear(&seen);
if (!sent_capabilities)
- show_ref("capabilities^{}", null_sha1);
+ show_ref("capabilities^{}", &null_oid);
advertise_shallow_grafts(1);
@@ -306,8 +309,8 @@ struct command {
unsigned int skip_update:1,
did_not_exist:1;
int index;
- unsigned char old_sha1[20];
- unsigned char new_sha1[20];
+ struct object_id old_oid;
+ struct object_id new_oid;
char ref_name[FLEX_ARRAY]; /* more */
};
@@ -470,7 +473,8 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)
* after dropping "_commit" from its name and possibly moving it out
* of commit.c
*/
-static char *find_header(const char *msg, size_t len, const char *key)
+static char *find_header(const char *msg, size_t len, const char *key,
+ const char **next_line)
{
int key_len = strlen(key);
const char *line = msg;
@@ -483,6 +487,8 @@ static char *find_header(const char *msg, size_t len, const char *key)
if (line + key_len < eol &&
!memcmp(line, key, key_len) && line[key_len] == ' ') {
int offset = key_len + 1;
+ if (next_line)
+ *next_line = *eol ? eol + 1 : eol;
return xmemdupz(line + offset, (eol - line) - offset);
}
line = *eol ? eol + 1 : NULL;
@@ -492,7 +498,7 @@ static char *find_header(const char *msg, size_t len, const char *key)
static const char *check_nonce(const char *buf, size_t len)
{
- char *nonce = find_header(buf, len, "nonce");
+ char *nonce = find_header(buf, len, "nonce", NULL);
unsigned long stamp, ostamp;
char *bohmac, *expect = NULL;
const char *retval = NONCE_BAD;
@@ -572,6 +578,45 @@ leave:
return retval;
}
+/*
+ * Return 1 if there is no push_cert or if the push options in push_cert are
+ * the same as those in the argument; 0 otherwise.
+ */
+static int check_cert_push_options(const struct string_list *push_options)
+{
+ const char *buf = push_cert.buf;
+ int len = push_cert.len;
+
+ char *option;
+ const char *next_line;
+ int options_seen = 0;
+
+ int retval = 1;
+
+ if (!len)
+ return 1;
+
+ while ((option = find_header(buf, len, "push-option", &next_line))) {
+ len -= (next_line - buf);
+ buf = next_line;
+ options_seen++;
+ if (options_seen > push_options->nr
+ || strcmp(option,
+ push_options->items[options_seen - 1].string)) {
+ retval = 0;
+ goto leave;
+ }
+ free(option);
+ }
+
+ if (options_seen != push_options->nr)
+ retval = 0;
+
+leave:
+ free(option);
+ return retval;
+}
+
static void prepare_push_cert_sha1(struct child_process *proc)
{
static int already_done;
@@ -720,7 +765,7 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
return -1; /* EOF */
strbuf_reset(&state->buf);
strbuf_addf(&state->buf, "%s %s %s\n",
- sha1_to_hex(cmd->old_sha1), sha1_to_hex(cmd->new_sha1),
+ oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
cmd->ref_name);
state->cmd = cmd->next;
if (bufp) {
@@ -761,15 +806,14 @@ static int run_update_hook(struct command *cmd)
return 0;
argv[1] = cmd->ref_name;
- argv[2] = sha1_to_hex(cmd->old_sha1);
- argv[3] = sha1_to_hex(cmd->new_sha1);
+ argv[2] = oid_to_hex(&cmd->old_oid);
+ argv[3] = oid_to_hex(&cmd->new_oid);
argv[4] = NULL;
proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
proc.argv = argv;
- proc.env = tmp_objdir_env(tmp_objdir);
code = start_command(&proc);
if (code)
@@ -828,7 +872,7 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]);
static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
{
static struct lock_file shallow_lock;
- struct sha1_array extra = SHA1_ARRAY_INIT;
+ struct oid_array extra = OID_ARRAY_INIT;
struct check_connected_options opt = CHECK_CONNECTED_INIT;
uint32_t mask = 1 << (cmd->index % 32);
int i;
@@ -839,13 +883,13 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
if (si->used_shallow[i] &&
(si->used_shallow[i][cmd->index / 32] & mask) &&
!delayed_reachability_test(si, i))
- sha1_array_append(&extra, si->shallow->sha1[i]);
+ oid_array_append(&extra, &si->shallow->oid[i]);
opt.env = tmp_objdir_env(tmp_objdir);
setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra);
if (check_connected(command_singleton_iterator, cmd, &opt)) {
rollback_lock_file(&shallow_lock);
- sha1_array_clear(&extra);
+ oid_array_clear(&extra);
return -1;
}
@@ -856,10 +900,10 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
* not lose these new roots..
*/
for (i = 0; i < extra.nr; i++)
- register_shallow(extra.sha1[i]);
+ register_shallow(extra.oid[i].hash);
si->shallow_ref[cmd->index] = 0;
- sha1_array_clear(&extra);
+ oid_array_clear(&extra);
return 0;
}
@@ -984,9 +1028,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
{
const char *name = cmd->ref_name;
struct strbuf namespaced_name_buf = STRBUF_INIT;
- const char *namespaced_name, *ret;
- unsigned char *old_sha1 = cmd->old_sha1;
- unsigned char *new_sha1 = cmd->new_sha1;
+ static char *namespaced_name;
+ const char *ret;
+ struct object_id *old_oid = &cmd->old_oid;
+ struct object_id *new_oid = &cmd->new_oid;
/* only refs/... are allowed */
if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@@ -995,6 +1040,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+ free(namespaced_name);
namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
if (is_ref_checked_out(namespaced_name)) {
@@ -1011,20 +1057,20 @@ static const char *update(struct command *cmd, struct shallow_info *si)
refuse_unconfigured_deny();
return "branch is currently checked out";
case DENY_UPDATE_INSTEAD:
- ret = update_worktree(new_sha1);
+ ret = update_worktree(new_oid->hash);
if (ret)
return ret;
break;
}
}
- if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) {
+ if (!is_null_oid(new_oid) && !has_object_file(new_oid)) {
error("unpack should have generated %s, "
- "but I can't find it!", sha1_to_hex(new_sha1));
+ "but I can't find it!", oid_to_hex(new_oid));
return "bad pack";
}
- if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
+ if (!is_null_oid(old_oid) && is_null_oid(new_oid)) {
if (deny_deletes && starts_with(name, "refs/heads/")) {
rp_error("denying ref deletion for %s", name);
return "deletion prohibited";
@@ -1050,14 +1096,14 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
}
- if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
- !is_null_sha1(old_sha1) &&
+ if (deny_non_fast_forwards && !is_null_oid(new_oid) &&
+ !is_null_oid(old_oid) &&
starts_with(name, "refs/heads/")) {
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
- old_object = parse_object(old_sha1);
- new_object = parse_object(new_sha1);
+ old_object = parse_object(old_oid->hash);
+ new_object = parse_object(new_oid->hash);
if (!old_object || !new_object ||
old_object->type != OBJ_COMMIT ||
@@ -1078,10 +1124,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
return "hook declined";
}
- if (is_null_sha1(new_sha1)) {
+ if (is_null_oid(new_oid)) {
struct strbuf err = STRBUF_INIT;
- if (!parse_object(old_sha1)) {
- old_sha1 = NULL;
+ if (!parse_object(old_oid->hash)) {
+ old_oid = NULL;
if (ref_exists(name)) {
rp_warning("Allowing deletion of corrupt ref.");
} else {
@@ -1091,7 +1137,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
if (ref_transaction_delete(transaction,
namespaced_name,
- old_sha1,
+ old_oid->hash,
0, "push", &err)) {
rp_error("%s", err.buf);
strbuf_release(&err);
@@ -1108,7 +1154,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (ref_transaction_update(transaction,
namespaced_name,
- new_sha1, old_sha1,
+ new_oid->hash, old_oid->hash,
0, "push",
&err)) {
rp_error("%s", err.buf);
@@ -1159,7 +1205,7 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
const char *dst_name;
struct string_list_item *item;
struct command *dst_cmd;
- unsigned char sha1[GIT_SHA1_RAWSZ];
+ unsigned char sha1[GIT_MAX_RAWSZ];
int flag;
strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
@@ -1184,8 +1230,8 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
dst_cmd = (struct command *) item->util;
- if (!hashcmp(cmd->old_sha1, dst_cmd->old_sha1) &&
- !hashcmp(cmd->new_sha1, dst_cmd->new_sha1))
+ if (!oidcmp(&cmd->old_oid, &dst_cmd->old_oid) &&
+ !oidcmp(&cmd->new_oid, &dst_cmd->new_oid))
return;
dst_cmd->skip_update = 1;
@@ -1193,11 +1239,11 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
" its target '%s' (%s..%s)",
cmd->ref_name,
- find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV),
- find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV),
+ find_unique_abbrev(cmd->old_oid.hash, DEFAULT_ABBREV),
+ find_unique_abbrev(cmd->new_oid.hash, DEFAULT_ABBREV),
dst_cmd->ref_name,
- find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV),
- find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV));
+ find_unique_abbrev(dst_cmd->old_oid.hash, DEFAULT_ABBREV),
+ find_unique_abbrev(dst_cmd->new_oid.hash, DEFAULT_ABBREV));
cmd->error_string = dst_cmd->error_string =
"inconsistent aliased update";
@@ -1228,10 +1274,10 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
struct command **cmd_list = cb_data;
struct command *cmd = *cmd_list;
- if (!cmd || is_null_sha1(cmd->new_sha1))
+ if (!cmd || is_null_oid(&cmd->new_oid))
return -1; /* end of list */
*cmd_list = NULL; /* this returns only one */
- hashcpy(sha1, cmd->new_sha1);
+ hashcpy(sha1, cmd->new_oid.hash);
return 0;
}
@@ -1272,8 +1318,8 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
if (shallow_update && data->si->shallow_ref[cmd->index])
/* to be checked in update_shallow_ref() */
continue;
- if (!is_null_sha1(cmd->new_sha1) && !cmd->skip_update) {
- hashcpy(sha1, cmd->new_sha1);
+ if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) {
+ hashcpy(sha1, cmd->new_oid.hash);
*cmd_list = cmd->next;
return 0;
}
@@ -1300,7 +1346,7 @@ static void reject_updates_to_hidden(struct command *commands)
if (!ref_is_hidden(cmd->ref_name, refname_full.buf))
continue;
- if (is_null_sha1(cmd->new_sha1))
+ if (is_null_oid(&cmd->new_oid))
cmd->error_string = "deny deleting a hidden ref";
else
cmd->error_string = "deny updating a hidden ref";
@@ -1411,7 +1457,7 @@ static void execute_commands(struct command *commands,
{
struct check_connected_options opt = CHECK_CONNECTED_INIT;
struct command *cmd;
- unsigned char sha1[20];
+ struct object_id oid;
struct iterate_data data;
struct async muxer;
int err_fd = 0;
@@ -1468,7 +1514,7 @@ static void execute_commands(struct command *commands,
check_aliased_updates(commands);
free(head_name_to_free);
- head_name = head_name_to_free = resolve_refdup("HEAD", 0, sha1, NULL);
+ head_name = head_name_to_free = resolve_refdup("HEAD", 0, oid.hash, NULL);
if (use_atomic)
execute_commands_atomic(commands, si);
@@ -1483,23 +1529,23 @@ static struct command **queue_command(struct command **tail,
const char *line,
int linelen)
{
- unsigned char old_sha1[20], new_sha1[20];
+ struct object_id old_oid, new_oid;
struct command *cmd;
const char *refname;
int reflen;
+ const char *p;
- if (linelen < 83 ||
- line[40] != ' ' ||
- line[81] != ' ' ||
- get_sha1_hex(line, old_sha1) ||
- get_sha1_hex(line + 41, new_sha1))
+ if (parse_oid_hex(line, &old_oid, &p) ||
+ *p++ != ' ' ||
+ parse_oid_hex(p, &new_oid, &p) ||
+ *p++ != ' ')
die("protocol error: expected old/new/ref, got '%s'", line);
- refname = line + 82;
- reflen = linelen - 82;
+ refname = p;
+ reflen = linelen - (p - line);
FLEX_ALLOC_MEM(cmd, ref_name, refname, reflen);
- hashcpy(cmd->old_sha1, old_sha1);
- hashcpy(cmd->new_sha1, new_sha1);
+ oidcpy(&cmd->old_oid, &old_oid);
+ oidcpy(&cmd->new_oid, &new_oid);
*tail = cmd;
return &cmd->next;
}
@@ -1521,12 +1567,12 @@ static void queue_commands_from_cert(struct command **tail,
while (boc < eoc) {
const char *eol = memchr(boc, '\n', eoc - boc);
- tail = queue_command(tail, boc, eol ? eol - boc : eoc - eol);
+ tail = queue_command(tail, boc, eol ? eol - boc : eoc - boc);
boc = eol ? eol + 1 : eoc;
}
}
-static struct command *read_head_info(struct sha1_array *shallow)
+static struct command *read_head_info(struct oid_array *shallow)
{
struct command *commands = NULL;
struct command **p = &commands;
@@ -1538,12 +1584,12 @@ static struct command *read_head_info(struct sha1_array *shallow)
if (!line)
break;
- if (len == 48 && starts_with(line, "shallow ")) {
- unsigned char sha1[20];
- if (get_sha1_hex(line + 8, sha1))
+ if (len > 8 && starts_with(line, "shallow ")) {
+ struct object_id oid;
+ if (get_oid_hex(line + 8, &oid))
die("protocol error: expected shallow sha, got '%s'",
line + 8);
- sha1_array_append(shallow, sha1);
+ oid_array_append(shallow, &oid);
continue;
}
@@ -1631,12 +1677,17 @@ static const char *parse_pack_header(struct pack_header *hdr)
static const char *pack_lockfile;
+static void push_header_arg(struct argv_array *args, struct pack_header *hdr)
+{
+ argv_array_pushf(args, "--pack_header=%"PRIu32",%"PRIu32,
+ ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries));
+}
+
static const char *unpack(int err_fd, struct shallow_info *si)
{
struct pack_header hdr;
const char *hdr_err;
int status;
- char hdr_arg[38];
struct child_process child = CHILD_PROCESS_INIT;
int fsck_objects = (receive_fsck_objects >= 0
? receive_fsck_objects
@@ -1650,9 +1701,6 @@ static const char *unpack(int err_fd, struct shallow_info *si)
close(err_fd);
return hdr_err;
}
- snprintf(hdr_arg, sizeof(hdr_arg),
- "--pack_header=%"PRIu32",%"PRIu32,
- ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
if (si->nr_ours || si->nr_theirs) {
alt_shallow_file = setup_temporary_shallow(si->shallow);
@@ -1676,7 +1724,8 @@ static const char *unpack(int err_fd, struct shallow_info *si)
tmp_objdir_add_as_alternate(tmp_objdir);
if (ntohl(hdr.hdr_entries) < unpack_limit) {
- argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL);
+ argv_array_push(&child.args, "unpack-objects");
+ push_header_arg(&child.args, &hdr);
if (quiet)
argv_array_push(&child.args, "-q");
if (fsck_objects)
@@ -1692,12 +1741,12 @@ static const char *unpack(int err_fd, struct shallow_info *si)
if (status)
return "unpack-objects abnormal exit";
} else {
- char hostname[256];
+ char hostname[HOST_NAME_MAX + 1];
- argv_array_pushl(&child.args, "index-pack",
- "--stdin", hdr_arg, NULL);
+ argv_array_pushl(&child.args, "index-pack", "--stdin", NULL);
+ push_header_arg(&child.args, &hdr);
- if (gethostname(hostname, sizeof(hostname)))
+ if (xgethostname(hostname, sizeof(hostname)))
xsnprintf(hostname, sizeof(hostname), "localhost");
argv_array_pushf(&child.args,
"--keep=receive-pack %"PRIuMAX" on %s",
@@ -1801,7 +1850,7 @@ static void prepare_shallow_update(struct command *commands,
static void update_shallow_info(struct command *commands,
struct shallow_info *si,
- struct sha1_array *ref)
+ struct oid_array *ref)
{
struct command *cmd;
int *ref_status;
@@ -1812,9 +1861,9 @@ static void update_shallow_info(struct command *commands,
}
for (cmd = commands; cmd; cmd = cmd->next) {
- if (is_null_sha1(cmd->new_sha1))
+ if (is_null_oid(&cmd->new_oid))
continue;
- sha1_array_append(ref, cmd->new_sha1);
+ oid_array_append(ref, &cmd->new_oid);
cmd->index = ref->nr - 1;
}
si->ref = ref;
@@ -1827,7 +1876,7 @@ static void update_shallow_info(struct command *commands,
ALLOC_ARRAY(ref_status, ref->nr);
assign_shallow_commits_to_refs(si, NULL, ref_status);
for (cmd = commands; cmd; cmd = cmd->next) {
- if (is_null_sha1(cmd->new_sha1))
+ if (is_null_oid(&cmd->new_oid))
continue;
if (ref_status[cmd->index]) {
cmd->error_string = "shallow update not allowed";
@@ -1865,7 +1914,7 @@ static int delete_only(struct command *commands)
{
struct command *cmd;
for (cmd = commands; cmd; cmd = cmd->next) {
- if (!is_null_sha1(cmd->new_sha1))
+ if (!is_null_oid(&cmd->new_oid))
return 0;
}
return 1;
@@ -1875,8 +1924,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
{
int advertise_refs = 0;
struct command *commands;
- struct sha1_array shallow = SHA1_ARRAY_INIT;
- struct sha1_array ref = SHA1_ARRAY_INIT;
+ struct oid_array shallow = OID_ARRAY_INIT;
+ struct oid_array ref = OID_ARRAY_INIT;
struct shallow_info si;
struct option options[] = {
@@ -1924,6 +1973,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (use_push_options)
read_push_options(&push_options);
+ if (!check_cert_push_options(&push_options)) {
+ struct command *cmd;
+ for (cmd = commands; cmd; cmd = cmd->next)
+ cmd->error_string = "inconsistent push options";
+ }
prepare_shallow_info(&si, &shallow);
if (!si.nr_ours && !si.nr_theirs)
@@ -1968,8 +2022,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
}
if (use_sideband)
packet_flush(1);
- sha1_array_clear(&shallow);
- sha1_array_clear(&ref);
+ oid_array_clear(&shallow);
+ oid_array_clear(&ref);
free((void *)push_cert_nonce);
return 0;
}
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 7a7136e53e..7472775778 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -615,7 +615,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
return status;
}
-static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
const char *email, unsigned long timestamp, int tz,
const char *message, void *cb_data)
{
diff --git a/builtin/remote.c b/builtin/remote.c
index 7682206c1e..9054e2858e 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -691,7 +691,7 @@ static int mv(int argc, const char **argv)
read_ref_full(item->string, RESOLVE_REF_READING, oid.hash, &flag);
if (!(flag & REF_ISSYMREF))
continue;
- if (delete_ref(item->string, NULL, REF_NODEREF))
+ if (delete_ref(NULL, item->string, NULL, REF_NODEREF))
die(_("deleting '%s' failed"), item->string);
}
for (i = 0; i < remote_branches.nr; i++) {
@@ -1151,8 +1151,11 @@ static int show(int argc, const char **argv)
url_nr = states.remote->url_nr;
}
for (i = 0; i < url_nr; i++)
- /* TRANSLATORS: the colon ':' should align with
- the one in " Fetch URL: %s" translation */
+ /*
+ * TRANSLATORS: the colon ':' should align
+ * with the one in " Fetch URL: %s"
+ * translation.
+ */
printf_ln(_(" Push URL: %s"), url[i]);
if (!i)
printf_ln(_(" Push URL: %s"), _("(no URL)"));
@@ -1250,7 +1253,7 @@ static int set_head(int argc, const char **argv)
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
- if (delete_ref(buf.buf, NULL, REF_NODEREF))
+ if (delete_ref(NULL, buf.buf, NULL, REF_NODEREF))
result |= error(_("Could not delete %s"), buf.buf);
} else
usage_with_options(builtin_remote_sethead_usage, options);
diff --git a/builtin/replace.c b/builtin/replace.c
index b58c714cb8..ab17668f43 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -88,78 +88,81 @@ static int list_replace_refs(const char *pattern, const char *format)
}
typedef int (*each_replace_name_fn)(const char *name, const char *ref,
- const unsigned char *sha1);
+ const struct object_id *oid);
static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
{
const char **p, *full_hex;
- char ref[PATH_MAX];
+ struct strbuf ref = STRBUF_INIT;
+ size_t base_len;
int had_error = 0;
- unsigned char sha1[20];
+ struct object_id oid;
+
+ strbuf_addstr(&ref, git_replace_ref_base);
+ base_len = ref.len;
for (p = argv; *p; p++) {
- if (get_sha1(*p, sha1)) {
+ if (get_oid(*p, &oid)) {
error("Failed to resolve '%s' as a valid ref.", *p);
had_error = 1;
continue;
}
- full_hex = sha1_to_hex(sha1);
- snprintf(ref, sizeof(ref), "%s%s", git_replace_ref_base, full_hex);
- /* read_ref() may reuse the buffer */
- full_hex = ref + strlen(git_replace_ref_base);
- if (read_ref(ref, sha1)) {
+
+ strbuf_setlen(&ref, base_len);
+ strbuf_addstr(&ref, oid_to_hex(&oid));
+ full_hex = ref.buf + base_len;
+
+ if (read_ref(ref.buf, oid.hash)) {
error("replace ref '%s' not found.", full_hex);
had_error = 1;
continue;
}
- if (fn(full_hex, ref, sha1))
+ if (fn(full_hex, ref.buf, &oid))
had_error = 1;
}
+ strbuf_release(&ref);
return had_error;
}
static int delete_replace_ref(const char *name, const char *ref,
- const unsigned char *sha1)
+ const struct object_id *oid)
{
- if (delete_ref(ref, sha1, 0))
+ if (delete_ref(NULL, ref, oid->hash, 0))
return 1;
printf("Deleted replace ref '%s'\n", name);
return 0;
}
-static void check_ref_valid(unsigned char object[20],
- unsigned char prev[20],
- char *ref,
- int ref_size,
+static void check_ref_valid(struct object_id *object,
+ struct object_id *prev,
+ struct strbuf *ref,
int force)
{
- if (snprintf(ref, ref_size,
- "%s%s", git_replace_ref_base,
- sha1_to_hex(object)) > ref_size - 1)
- die("replace ref name too long: %.*s...", 50, ref);
- if (check_refname_format(ref, 0))
- die("'%s' is not a valid ref name.", ref);
-
- if (read_ref(ref, prev))
- hashclr(prev);
+ strbuf_reset(ref);
+ strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
+ if (check_refname_format(ref->buf, 0))
+ die("'%s' is not a valid ref name.", ref->buf);
+
+ if (read_ref(ref->buf, prev->hash))
+ oidclr(prev);
else if (!force)
- die("replace ref '%s' already exists", ref);
+ die("replace ref '%s' already exists", ref->buf);
}
-static int replace_object_sha1(const char *object_ref,
- unsigned char object[20],
+static int replace_object_oid(const char *object_ref,
+ struct object_id *object,
const char *replace_ref,
- unsigned char repl[20],
+ struct object_id *repl,
int force)
{
- unsigned char prev[20];
+ struct object_id prev;
enum object_type obj_type, repl_type;
- char ref[PATH_MAX];
+ struct strbuf ref = STRBUF_INIT;
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
- obj_type = sha1_object_info(object, NULL);
- repl_type = sha1_object_info(repl, NULL);
+ obj_type = sha1_object_info(object->hash, NULL);
+ repl_type = sha1_object_info(repl->hash, NULL);
if (!force && obj_type != repl_type)
die("Objects must be of the same type.\n"
"'%s' points to a replaced object of type '%s'\n"
@@ -167,29 +170,30 @@ static int replace_object_sha1(const char *object_ref,
object_ref, typename(obj_type),
replace_ref, typename(repl_type));
- check_ref_valid(object, prev, ref, sizeof(ref), force);
+ check_ref_valid(object, &prev, &ref, force);
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref, repl, prev,
+ ref_transaction_update(transaction, ref.buf, repl->hash, prev.hash,
0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
+ strbuf_release(&ref);
return 0;
}
static int replace_object(const char *object_ref, const char *replace_ref, int force)
{
- unsigned char object[20], repl[20];
+ struct object_id object, repl;
- if (get_sha1(object_ref, object))
+ if (get_oid(object_ref, &object))
die("Failed to resolve '%s' as a valid ref.", object_ref);
- if (get_sha1(replace_ref, repl))
+ if (get_oid(replace_ref, &repl))
die("Failed to resolve '%s' as a valid ref.", replace_ref);
- return replace_object_sha1(object_ref, object, replace_ref, repl, force);
+ return replace_object_oid(object_ref, &object, replace_ref, &repl, force);
}
/*
@@ -197,7 +201,7 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
* If "raw" is true, then the object's raw contents are printed according to
* "type". Otherwise, we pretty-print the contents for human editing.
*/
-static void export_object(const unsigned char *sha1, enum object_type type,
+static void export_object(const struct object_id *oid, enum object_type type,
int raw, const char *filename)
{
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -213,7 +217,7 @@ static void export_object(const unsigned char *sha1, enum object_type type,
argv_array_push(&cmd.args, typename(type));
else
argv_array_push(&cmd.args, "-p");
- argv_array_push(&cmd.args, sha1_to_hex(sha1));
+ argv_array_push(&cmd.args, oid_to_hex(oid));
cmd.git_cmd = 1;
cmd.out = fd;
@@ -226,7 +230,7 @@ static void export_object(const unsigned char *sha1, enum object_type type,
* interpreting it as "type", and writing the result to the object database.
* The sha1 of the written object is returned via sha1.
*/
-static void import_object(unsigned char *sha1, enum object_type type,
+static void import_object(struct object_id *oid, enum object_type type,
int raw, const char *filename)
{
int fd;
@@ -254,7 +258,7 @@ static void import_object(unsigned char *sha1, enum object_type type,
if (finish_command(&cmd))
die("mktree reported failure");
- if (get_sha1_hex(result.buf, sha1) < 0)
+ if (get_oid_hex(result.buf, oid) < 0)
die("mktree did not return an object name");
strbuf_release(&result);
@@ -264,7 +268,7 @@ static void import_object(unsigned char *sha1, enum object_type type,
if (fstat(fd, &st) < 0)
die_errno("unable to fstat %s", filename);
- if (index_fd(sha1, fd, &st, type, NULL, flags) < 0)
+ if (index_fd(oid->hash, fd, &st, type, NULL, flags) < 0)
die("unable to write object to database");
/* index_fd close()s fd for us */
}
@@ -279,29 +283,30 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
{
char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
enum object_type type;
- unsigned char old[20], new[20], prev[20];
- char ref[PATH_MAX];
+ struct object_id old, new, prev;
+ struct strbuf ref = STRBUF_INIT;
- if (get_sha1(object_ref, old) < 0)
+ if (get_oid(object_ref, &old) < 0)
die("Not a valid object name: '%s'", object_ref);
- type = sha1_object_info(old, NULL);
+ type = sha1_object_info(old.hash, NULL);
if (type < 0)
- die("unable to get object type for %s", sha1_to_hex(old));
+ die("unable to get object type for %s", oid_to_hex(&old));
- check_ref_valid(old, prev, ref, sizeof(ref), force);
+ check_ref_valid(&old, &prev, &ref, force);
+ strbuf_release(&ref);
- export_object(old, type, raw, tmpfile);
+ export_object(&old, type, raw, tmpfile);
if (launch_editor(tmpfile, NULL, NULL) < 0)
die("editing object file failed");
- import_object(new, type, raw, tmpfile);
+ import_object(&new, type, raw, tmpfile);
free(tmpfile);
- if (!hashcmp(old, new))
- return error("new object is the same as the old one: '%s'", sha1_to_hex(old));
+ if (!oidcmp(&old, &new))
+ return error("new object is the same as the old one: '%s'", oid_to_hex(&old));
- return replace_object_sha1(object_ref, old, "replacement", new, force);
+ return replace_object_oid(object_ref, &old, "replacement", &new, force);
}
static void replace_parents(struct strbuf *buf, int argc, const char **argv)
@@ -312,7 +317,7 @@ static void replace_parents(struct strbuf *buf, int argc, const char **argv)
/* find existing parents */
parent_start = buf->buf;
- parent_start += 46; /* "tree " + "hex sha1" + "\n" */
+ parent_start += GIT_SHA1_HEXSZ + 6; /* "tree " + "hex sha1" + "\n" */
parent_end = parent_start;
while (starts_with(parent_end, "parent "))
@@ -320,11 +325,11 @@ static void replace_parents(struct strbuf *buf, int argc, const char **argv)
/* prepare new parents */
for (i = 0; i < argc; i++) {
- unsigned char sha1[20];
- if (get_sha1(argv[i], sha1) < 0)
+ struct object_id oid;
+ if (get_oid(argv[i], &oid) < 0)
die(_("Not a valid object name: '%s'"), argv[i]);
- lookup_commit_or_die(sha1, argv[i]);
- strbuf_addf(&new_parents, "parent %s\n", sha1_to_hex(sha1));
+ lookup_commit_or_die(oid.hash, argv[i]);
+ strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid));
}
/* replace existing parents with new ones */
@@ -345,12 +350,12 @@ static void check_one_mergetag(struct commit *commit,
{
struct check_mergetag_data *mergetag_data = (struct check_mergetag_data *)data;
const char *ref = mergetag_data->argv[0];
- unsigned char tag_sha1[20];
+ struct object_id tag_oid;
struct tag *tag;
int i;
- hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_sha1);
- tag = lookup_tag(tag_sha1);
+ hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_oid.hash);
+ tag = lookup_tag(tag_oid.hash);
if (!tag)
die(_("bad mergetag in commit '%s'"), ref);
if (parse_tag_buffer(tag, extra->value, extra->len))
@@ -366,7 +371,7 @@ static void check_one_mergetag(struct commit *commit,
}
die(_("original commit '%s' contains mergetag '%s' that is discarded; "
- "use --edit instead of --graft"), ref, sha1_to_hex(tag_sha1));
+ "use --edit instead of --graft"), ref, oid_to_hex(&tag_oid));
}
static void check_mergetags(struct commit *commit, int argc, const char **argv)
@@ -380,16 +385,16 @@ static void check_mergetags(struct commit *commit, int argc, const char **argv)
static int create_graft(int argc, const char **argv, int force)
{
- unsigned char old[20], new[20];
+ struct object_id old, new;
const char *old_ref = argv[0];
struct commit *commit;
struct strbuf buf = STRBUF_INIT;
const char *buffer;
unsigned long size;
- if (get_sha1(old_ref, old) < 0)
+ if (get_oid(old_ref, &old) < 0)
die(_("Not a valid object name: '%s'"), old_ref);
- commit = lookup_commit_or_die(old, old_ref);
+ commit = lookup_commit_or_die(old.hash, old_ref);
buffer = get_commit_buffer(commit, &size);
strbuf_add(&buf, buffer, size);
@@ -404,15 +409,15 @@ static int create_graft(int argc, const char **argv, int force)
check_mergetags(commit, argc, argv);
- if (write_sha1_file(buf.buf, buf.len, commit_type, new))
+ if (write_sha1_file(buf.buf, buf.len, commit_type, new.hash))
die(_("could not write replacement commit for: '%s'"), old_ref);
strbuf_release(&buf);
- if (!hashcmp(old, new))
- return error("new commit is the same as the old one: '%s'", sha1_to_hex(old));
+ if (!oidcmp(&old, &new))
+ return error("new commit is the same as the old one: '%s'", oid_to_hex(&old));
- return replace_object_sha1(old_ref, old, "replacement", new, force);
+ return replace_object_oid(old_ref, &old, "replacement", &new, force);
}
int cmd_replace(int argc, const char **argv, const char *prefix)
diff --git a/builtin/reset.c b/builtin/reset.c
index 8ab915bfcb..fc3b906c47 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -256,7 +256,7 @@ static int reset_refs(const char *rev, const struct object_id *oid)
update_ref_oid(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
- delete_ref("ORIG_HEAD", old_orig->hash, 0);
+ delete_ref(NULL, "ORIG_HEAD", old_orig->hash, 0);
set_reflog_message(&msg, "updating HEAD", rev);
update_ref_status = update_ref_oid(msg.buf, "HEAD", oid, orig, 0,
UPDATE_REFS_MSG_ON_ERR);
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 0aa93d5891..bcf77f0b8a 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -212,7 +212,7 @@ static void print_var_int(const char *var, int val)
static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
{
int cnt, flags = info->flags;
- char hex[GIT_SHA1_HEXSZ + 1] = "";
+ char hex[GIT_MAX_HEXSZ + 1] = "";
struct commit_list *tried;
struct rev_info *revs = info->revs;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index ed8819b451..0513330910 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -12,6 +12,7 @@
#include "diff.h"
#include "revision.h"
#include "split-index.h"
+#include "submodule.h"
#define DO_REVS 1
#define DO_NOREV 2
@@ -204,21 +205,22 @@ static int anti_reference(const char *refname, const struct object_id *oid, int
return 0;
}
-static int show_abbrev(const unsigned char *sha1, void *cb_data)
+static int show_abbrev(const struct object_id *oid, void *cb_data)
{
- show_rev(NORMAL, sha1, NULL);
+ show_rev(NORMAL, oid->hash, NULL);
return 0;
}
static void show_datestring(const char *flag, const char *datestr)
{
- static char buffer[100];
+ char *buffer;
/* date handling requires both flags and revs */
if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
return;
- snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr));
+ buffer = xstrfmt("%s%lu", flag, approxidate(datestr));
show(buffer);
+ free(buffer);
}
static int show_file(const char *arg, int output_prefix)
@@ -227,9 +229,9 @@ static int show_file(const char *arg, int output_prefix)
if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
if (output_prefix) {
const char *prefix = startup_info->prefix;
- show(prefix_filename(prefix,
- prefix ? strlen(prefix) : 0,
- arg));
+ char *fname = prefix_filename(prefix, arg);
+ show(fname);
+ free(fname);
} else
show(arg);
return 1;
@@ -573,6 +575,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
unsigned int flags = 0;
const char *name = NULL;
struct object_context unused;
+ struct strbuf buf = STRBUF_INIT;
if (argc > 1 && !strcmp("--parseopt", argv[1]))
return cmd_parseopt(argc - 1, argv + 1, prefix);
@@ -627,7 +630,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--git-path")) {
if (!argv[i + 1])
die("--git-path requires an argument");
- puts(git_path("%s", argv[i + 1]));
+ strbuf_reset(&buf);
+ puts(relative_path(git_path("%s", argv[i + 1]),
+ prefix, &buf));
i++;
continue;
}
@@ -781,6 +786,12 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(work_tree);
continue;
}
+ if (!strcmp(arg, "--show-superproject-working-tree")) {
+ const char *superproject = get_superproject_working_tree();
+ if (superproject)
+ puts(superproject);
+ continue;
+ }
if (!strcmp(arg, "--show-prefix")) {
if (prefix)
puts(prefix);
@@ -807,17 +818,27 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
putchar('\n');
continue;
}
- if (!strcmp(arg, "--git-dir")) {
+ if (!strcmp(arg, "--git-dir") ||
+ !strcmp(arg, "--absolute-git-dir")) {
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
char *cwd;
int len;
- if (gitdir) {
- puts(gitdir);
- continue;
- }
- if (!prefix) {
- puts(".git");
- continue;
+ if (arg[2] == 'g') { /* --git-dir */
+ if (gitdir) {
+ puts(gitdir);
+ continue;
+ }
+ if (!prefix) {
+ puts(".git");
+ continue;
+ }
+ } else { /* --absolute-git-dir */
+ if (!gitdir && !prefix)
+ gitdir = ".git";
+ if (gitdir) {
+ puts(real_path(gitdir));
+ continue;
+ }
}
cwd = xgetcwd();
len = strlen(cwd);
@@ -826,8 +847,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--git-common-dir")) {
- const char *pfx = prefix ? prefix : "";
- puts(prefix_filename(pfx, strlen(pfx), get_git_common_dir()));
+ strbuf_reset(&buf);
+ puts(relative_path(get_git_common_dir(),
+ prefix, &buf));
continue;
}
if (!strcmp(arg, "--is-inside-git-dir")) {
@@ -850,7 +872,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
die(_("Could not read the index"));
if (the_index.split_index) {
const unsigned char *sha1 = the_index.split_index->base_sha1;
- puts(git_path("sharedindex.%s", sha1_to_hex(sha1)));
+ const char *path = git_path("sharedindex.%s", sha1_to_hex(sha1));
+ strbuf_reset(&buf);
+ puts(relative_path(path, prefix, &buf));
}
continue;
}
@@ -902,6 +926,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
verify_filename(prefix, arg, 1);
}
+ strbuf_release(&buf);
if (verify) {
if (revs_count == 1) {
show_rev(type, sha1, name);
diff --git a/builtin/revert.c b/builtin/revert.c
index 4ca5b51544..345d9586a7 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -54,6 +54,24 @@ static int option_parse_x(const struct option *opt,
return 0;
}
+static int option_parse_m(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct replay_opts *replay = opt->value;
+ char *end;
+
+ if (unset) {
+ replay->mainline = 0;
+ return 0;
+ }
+
+ replay->mainline = strtol(arg, &end, 10);
+ if (*end || replay->mainline <= 0)
+ return opterror(opt, "expects a number greater than zero", 0);
+
+ return 0;
+}
+
LAST_ARG_MUST_BE_NULL
static void verify_opt_compatible(const char *me, const char *base_opt, ...)
{
@@ -84,7 +102,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
OPT_BOOL('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
- OPT_INTEGER('m', "mainline", &opts->mainline, N_("parent number")),
+ OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
+ N_("select mainline parent"), option_parse_m),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 1ff5a67538..b8e2e74fe0 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -131,8 +131,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
const char *dest = NULL;
int fd[2];
struct child_process *conn;
- struct sha1_array extra_have = SHA1_ARRAY_INIT;
- struct sha1_array shallow = SHA1_ARRAY_INIT;
+ struct oid_array extra_have = OID_ARRAY_INIT;
+ struct oid_array shallow = OID_ARRAY_INIT;
struct ref *remote_refs, *local_refs;
int ret;
int helper_status = 0;
@@ -144,6 +144,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
unsigned force_update = 0;
unsigned quiet = 0;
int push_cert = 0;
+ struct string_list push_options = STRING_LIST_INIT_NODUP;
unsigned use_thin_pack = 0;
unsigned atomic = 0;
unsigned stateless_rpc = 0;
@@ -165,6 +166,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK,
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
+ OPT_STRING_LIST(0, "push-option", &push_options,
+ N_("server-specific"),
+ N_("option to transmit")),
OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
OPT_BOOL(0, "thin", &use_thin_pack, N_("use thin pack")),
OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")),
@@ -199,6 +203,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.use_thin_pack = use_thin_pack;
args.atomic = atomic;
args.stateless_rpc = stateless_rpc;
+ args.push_options = push_options.nr ? &push_options : NULL;
if (from_stdin) {
struct argv_array all_refspecs = ARGV_ARRAY_INIT;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 677f372083..7cff1839fc 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -148,7 +148,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.fmt = CMIT_FMT_USERFORMAT;
ctx.abbrev = log->abbrev;
- ctx.subject = "";
+ ctx.print_email_subject = 1;
ctx.date_mode.type = DATE_NORMAL;
ctx.output_encoding = get_log_output_encoding();
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 899dc334e3..566a5b6a6f 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -270,6 +270,29 @@ static int module_list_compute(int argc, const char **argv,
return result;
}
+static void module_list_active(struct module_list *list)
+{
+ int i;
+ struct module_list active_modules = MODULE_LIST_INIT;
+
+ gitmodules_config();
+
+ for (i = 0; i < list->nr; i++) {
+ const struct cache_entry *ce = list->entries[i];
+
+ if (!is_submodule_initialized(ce->name))
+ continue;
+
+ ALLOC_GROW(active_modules.entries,
+ active_modules.nr + 1,
+ active_modules.alloc);
+ active_modules.entries[active_modules.nr++] = ce;
+ }
+
+ free(list->entries);
+ *list = active_modules;
+}
+
static int module_list(int argc, const char **argv, const char *prefix)
{
int i;
@@ -334,6 +357,18 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
displaypath);
/*
+ * NEEDSWORK: In a multi-working-tree world, this needs to be
+ * set in the per-worktree config.
+ *
+ * Set active flag for the submodule being initialized
+ */
+ if (!is_submodule_initialized(path)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.active", sub->name);
+ git_config_set_gently(sb.buf, "true");
+ }
+
+ /*
* Copy url setting when it is not set yet.
* To look up the url in .git/config, we must not fall back to
* .gitmodules, so look it up directly.
@@ -341,12 +376,12 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.url", sub->name);
if (git_config_get_string(sb.buf, &url)) {
- url = xstrdup(sub->url);
-
- if (!url)
+ if (!sub->url)
die(_("No url found for submodule path '%s' in .gitmodules"),
displaypath);
+ url = xstrdup(sub->url);
+
/* Possibly a url relative to parent */
if (starts_with_dot_dot_slash(url) ||
starts_with_dot_slash(url)) {
@@ -356,12 +391,10 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
strbuf_addf(&remotesb, "remote.%s.url", remote);
free(remote);
- if (git_config_get_string(remotesb.buf, &remoteurl))
- /*
- * The repository is its own
- * authoritative upstream
- */
+ if (git_config_get_string(remotesb.buf, &remoteurl)) {
+ warning(_("could not lookup configuration '%s'. Assuming this repository is its own authoritative upstream."), remotesb.buf);
remoteurl = xgetcwd();
+ }
relurl = relative_url(remoteurl, url, NULL);
strbuf_release(&remotesb);
free(remoteurl);
@@ -422,6 +455,13 @@ static int module_init(int argc, const char **argv, const char *prefix)
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
return 1;
+ /*
+ * If there are no path args and submodule.active is set then,
+ * by default, only initialize 'active' modules.
+ */
+ if (!argc && git_config_get_value_multi("submodule.active"))
+ module_list_active(&list);
+
for (i = 0; i < list.nr; i++)
init_submodule(list.entries[i]->name, prefix, quiet);
@@ -579,9 +619,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
const char *name = NULL, *url = NULL, *depth = NULL;
int quiet = 0;
int progress = 0;
- FILE *submodule_dot_git;
char *p, *path = NULL, *sm_gitdir;
- struct strbuf rel_path = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
struct string_list reference = STRING_LIST_INIT_NODUP;
char *sm_alternate = NULL, *error_strategy = NULL;
@@ -653,27 +691,12 @@ static int module_clone(int argc, const char **argv, const char *prefix)
strbuf_reset(&sb);
}
- /* Write a .git file in the submodule to redirect to the superproject. */
- strbuf_addf(&sb, "%s/.git", path);
- if (safe_create_leading_directories_const(sb.buf) < 0)
- die(_("could not create leading directories of '%s'"), sb.buf);
- submodule_dot_git = fopen(sb.buf, "w");
- if (!submodule_dot_git)
- die_errno(_("cannot open file '%s'"), sb.buf);
-
- fprintf_or_die(submodule_dot_git, "gitdir: %s\n",
- relative_path(sm_gitdir, path, &rel_path));
- if (fclose(submodule_dot_git))
- die(_("could not close file %s"), sb.buf);
- strbuf_reset(&sb);
- strbuf_reset(&rel_path);
+ /* Connect module worktree and git dir */
+ connect_work_tree_and_git_dir(path, sm_gitdir);
- /* Redirect the worktree of the submodule in the superproject's config */
p = git_pathdup_submodule(path, "config");
if (!p)
die(_("could not get submodule directory for '%s'"), path);
- git_config_set_in_file(p, "core.worktree",
- relative_path(path, sm_gitdir, &rel_path));
/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
git_config_get_string("submodule.alternateLocation", &sm_alternate);
@@ -689,7 +712,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
free(error_strategy);
strbuf_release(&sb);
- strbuf_release(&rel_path);
free(sm_gitdir);
free(path);
free(p);
@@ -761,7 +783,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
struct strbuf displaypath_sb = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
const char *displaypath = NULL;
- char *url = NULL;
int needs_cloning = 0;
if (ce_stage(ce)) {
@@ -795,15 +816,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
goto cleanup;
}
- /*
- * Looking up the url in .git/config.
- * We must not fall back to .gitmodules as we only want
- * to process configured submodules.
- */
- strbuf_reset(&sb);
- strbuf_addf(&sb, "submodule.%s.url", sub->name);
- git_config_get_string(sb.buf, &url);
- if (!url) {
+ /* Check if the submodule has been initialized. */
+ if (!is_submodule_initialized(ce->name)) {
next_submodule_warn_missing(suc, out, displaypath);
goto cleanup;
}
@@ -837,7 +851,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
argv_array_push(&child->args, "--depth=1");
argv_array_pushl(&child->args, "--path", sub->path, NULL);
argv_array_pushl(&child->args, "--name", sub->name, NULL);
- argv_array_pushl(&child->args, "--url", url, NULL);
+ argv_array_pushl(&child->args, "--url", sub->url, NULL);
if (suc->references.nr) {
struct string_list_item *item;
for_each_string_list_item(item, &suc->references)
@@ -847,7 +861,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
argv_array_push(&child->args, suc->depth);
cleanup:
- free(url);
strbuf_reset(&displaypath_sb);
strbuf_reset(&sb);
@@ -1092,6 +1105,50 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,
return 0;
}
+static int push_check(int argc, const char **argv, const char *prefix)
+{
+ struct remote *remote;
+
+ if (argc < 2)
+ die("submodule--helper push-check requires at least 1 argument");
+
+ /*
+ * The remote must be configured.
+ * This is to avoid pushing to the exact same URL as the parent.
+ */
+ remote = pushremote_get(argv[1]);
+ if (!remote || remote->origin == REMOTE_UNCONFIGURED)
+ die("remote '%s' not configured", argv[1]);
+
+ /* Check the refspec */
+ if (argc > 2) {
+ int i, refspec_nr = argc - 2;
+ struct ref *local_refs = get_local_heads();
+ struct refspec *refspec = parse_push_refspec(refspec_nr,
+ argv + 2);
+
+ for (i = 0; i < refspec_nr; i++) {
+ struct refspec *rs = refspec + i;
+
+ if (rs->pattern || rs->matching)
+ continue;
+
+ /*
+ * LHS must match a single ref
+ * NEEDSWORK: add logic to special case 'HEAD' once
+ * working with submodules in a detached head state
+ * ceases to be the norm.
+ */
+ if (count_refspec_match(rs->src, local_refs, NULL) != 1)
+ die("src refspec '%s' must name a ref",
+ rs->src);
+ }
+ free_refspec(refspec_nr, refspec);
+ }
+
+ return 0;
+}
+
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
{
int i;
@@ -1129,6 +1186,16 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
return 0;
}
+static int is_active(int argc, const char **argv, const char *prefix)
+{
+ if (argc != 2)
+ die("submodule--helper is-active takes exactly 1 argument");
+
+ gitmodules_config();
+
+ return !is_submodule_initialized(argv[1]);
+}
+
#define SUPPORT_SUPER_PREFIX (1<<0)
struct cmd_struct {
@@ -1147,7 +1214,9 @@ static struct cmd_struct commands[] = {
{"resolve-relative-url-test", resolve_relative_url_test, 0},
{"init", module_init, SUPPORT_SUPER_PREFIX},
{"remote-branch", resolve_remote_submodule_branch, 0},
+ {"push-check", push_check, 0},
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
+ {"is-active", is_active, 0},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 96eed94468..70addef158 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -58,7 +58,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
die("Cannot delete %s, not a symbolic ref", argv[0]);
if (!strcmp(argv[0], "HEAD"))
die("deleting '%s' is not allowed", argv[0]);
- return delete_ref(argv[0], NULL, REF_NODEREF);
+ return delete_ref(NULL, argv[0], NULL, REF_NODEREF);
}
switch (argc) {
diff --git a/builtin/tag.c b/builtin/tag.c
index e40c4a9676..bdf1e88e93 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -22,7 +22,7 @@
static const char * const git_tag_usage[] = {
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]"),
N_("git tag -d <tagname>..."),
- N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]"
+ N_("git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]"
"\n\t\t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]"),
N_("git tag -v [--format=<format>] <tagname>..."),
NULL
@@ -45,11 +45,11 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
if (!format) {
if (filter->lines) {
to_free = xstrfmt("%s %%(contents:lines=%d)",
- "%(align:15)%(refname:strip=2)%(end)",
+ "%(align:15)%(refname:lstrip=2)%(end)",
filter->lines);
format = to_free;
} else
- format = "%(refname:strip=2)";
+ format = "%(refname:lstrip=2)";
}
verify_ref_format(format);
@@ -72,32 +72,29 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
const void *cb_data)
{
const char **p;
- char ref[PATH_MAX];
+ struct strbuf ref = STRBUF_INIT;
int had_error = 0;
unsigned char sha1[20];
for (p = argv; *p; p++) {
- if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
- >= sizeof(ref)) {
- error(_("tag name too long: %.*s..."), 50, *p);
- had_error = 1;
- continue;
- }
- if (read_ref(ref, sha1)) {
+ strbuf_reset(&ref);
+ strbuf_addf(&ref, "refs/tags/%s", *p);
+ if (read_ref(ref.buf, sha1)) {
error(_("tag '%s' not found."), *p);
had_error = 1;
continue;
}
- if (fn(*p, ref, sha1, cb_data))
+ if (fn(*p, ref.buf, sha1, cb_data))
had_error = 1;
}
+ strbuf_release(&ref);
return had_error;
}
static int delete_tag(const char *name, const char *ref,
const unsigned char *sha1, const void *cb_data)
{
- if (delete_ref(ref, sha1, 0))
+ if (delete_ref(NULL, ref, sha1, 0))
return 1;
printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(sha1, DEFAULT_ABBREV));
return 0;
@@ -231,26 +228,22 @@ static void create_tag(const unsigned char *object, const char *tag,
unsigned char *prev, unsigned char *result)
{
enum object_type type;
- char header_buf[1024];
- int header_len;
+ struct strbuf header = STRBUF_INIT;
char *path = NULL;
type = sha1_object_info(object, NULL);
if (type <= OBJ_NONE)
die(_("bad object type."));
- header_len = snprintf(header_buf, sizeof(header_buf),
- "object %s\n"
- "type %s\n"
- "tag %s\n"
- "tagger %s\n\n",
- sha1_to_hex(object),
- typename(type),
- tag,
- git_committer_info(IDENT_STRICT));
-
- if (header_len > sizeof(header_buf) - 1)
- die(_("tag header too big."));
+ strbuf_addf(&header,
+ "object %s\n"
+ "type %s\n"
+ "tag %s\n"
+ "tagger %s\n\n",
+ sha1_to_hex(object),
+ typename(type),
+ tag,
+ git_committer_info(IDENT_STRICT));
if (!opt->message_given) {
int fd;
@@ -288,7 +281,8 @@ static void create_tag(const unsigned char *object, const char *tag,
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
- strbuf_insert(buf, 0, header_buf, header_len);
+ strbuf_insert(buf, 0, header.buf, header.len);
+ strbuf_release(&header);
if (build_tag_object(buf, opt->sign, result) < 0) {
if (path)
@@ -302,6 +296,54 @@ static void create_tag(const unsigned char *object, const char *tag,
}
}
+static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb)
+{
+ enum object_type type;
+ struct commit *c;
+ char *buf;
+ unsigned long size;
+ int subject_len = 0;
+ const char *subject_start;
+
+ char *rla = getenv("GIT_REFLOG_ACTION");
+ if (rla) {
+ strbuf_addstr(sb, rla);
+ } else {
+ strbuf_addstr(sb, "tag: tagging ");
+ strbuf_add_unique_abbrev(sb, sha1, DEFAULT_ABBREV);
+ }
+
+ strbuf_addstr(sb, " (");
+ type = sha1_object_info(sha1, NULL);
+ switch (type) {
+ default:
+ strbuf_addstr(sb, "object of unknown type");
+ break;
+ case OBJ_COMMIT:
+ if ((buf = read_sha1_file(sha1, &type, &size)) != NULL) {
+ subject_len = find_commit_subject(buf, &subject_start);
+ strbuf_insert(sb, sb->len, subject_start, subject_len);
+ } else {
+ strbuf_addstr(sb, "commit object");
+ }
+ free(buf);
+
+ if ((c = lookup_commit_reference(sha1)) != NULL)
+ strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
+ break;
+ case OBJ_TREE:
+ strbuf_addstr(sb, "tree object");
+ break;
+ case OBJ_BLOB:
+ strbuf_addstr(sb, "blob object");
+ break;
+ case OBJ_TAG:
+ strbuf_addstr(sb, "other tag object");
+ break;
+ }
+ strbuf_addch(sb, ')');
+}
+
struct msg_arg {
int given;
struct strbuf buf;
@@ -335,6 +377,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
struct strbuf ref = STRBUF_INIT;
+ struct strbuf reflog_msg = STRBUF_INIT;
unsigned char object[20], prev[20];
const char *object_ref, *tag;
struct create_tag_options opt;
@@ -375,20 +418,25 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_GROUP(N_("Tag listing options")),
OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
OPT_CONTAINS(&filter.with_commit, N_("print only tags that contain the commit")),
+ OPT_NO_CONTAINS(&filter.no_commit, N_("print only tags that don't contain the commit")),
OPT_WITH(&filter.with_commit, N_("print only tags that contain the commit")),
+ OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")),
OPT_MERGED(&filter, N_("print only tags that are merged")),
OPT_NO_MERGED(&filter, N_("print only tags that are not merged")),
OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
N_("field name to sort on"), &parse_opt_ref_sorting),
{
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
- N_("print only tags of the object"), 0, parse_opt_object_name
+ N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
+ parse_opt_object_name, (intptr_t) "HEAD"
},
OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
OPT_END()
};
+ setup_ref_filter_porcelain_msg();
+
git_config(git_tag_config, sorting_tail);
memset(&opt, 0, sizeof(opt));
@@ -403,8 +451,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
}
create_tag_object = (opt.sign || annotate || msg.given || msgfile);
- if (argc == 0 && !cmdmode)
- cmdmode = 'l';
+ if (!cmdmode) {
+ if (argc == 0)
+ cmdmode = 'l';
+ else if (filter.with_commit || filter.no_commit ||
+ filter.points_at.nr || filter.merge_commit ||
+ filter.lines != -1)
+ cmdmode = 'l';
+ }
if ((create_tag_object || force) && (cmdmode != 0))
usage_with_options(git_tag_usage, options);
@@ -434,13 +488,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
return ret;
}
if (filter.lines != -1)
- die(_("-n option is only allowed with -l."));
+ die(_("-n option is only allowed in list mode"));
if (filter.with_commit)
- die(_("--contains option is only allowed with -l."));
+ die(_("--contains option is only allowed in list mode"));
+ if (filter.no_commit)
+ die(_("--no-contains option is only allowed in list mode"));
if (filter.points_at.nr)
- die(_("--points-at option is only allowed with -l."));
+ die(_("--points-at option is only allowed in list mode"));
if (filter.merge_commit)
- die(_("--merged and --no-merged option are only allowed with -l"));
+ die(_("--merged and --no-merged options are only allowed in list mode"));
if (cmdmode == 'd')
return for_each_tag_name(argv, delete_tag, NULL);
if (cmdmode == 'v') {
@@ -494,6 +550,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
else
die(_("Invalid cleanup mode %s"), cleanup_arg);
+ create_reflog_msg(object, &reflog_msg);
+
if (create_tag_object) {
if (force_sign_annotate && !annotate)
opt.sign = 1;
@@ -504,7 +562,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (!transaction ||
ref_transaction_update(transaction, ref.buf, object, prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
- NULL, &err) ||
+ reflog_msg.buf, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
@@ -514,5 +572,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
strbuf_release(&err);
strbuf_release(&buf);
strbuf_release(&ref);
+ strbuf_release(&reflog_msg);
return 0;
}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index d530e89368..ebfc09faa0 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -125,12 +125,16 @@ static int test_if_untracked_cache_is_supported(void)
struct stat st;
struct stat_data base;
int fd, ret = 0;
+ char *cwd;
strbuf_addstr(&mtime_dir, "mtime-test-XXXXXX");
if (!mkdtemp(mtime_dir.buf))
die_errno("Could not make temporary directory");
- fprintf(stderr, _("Testing mtime in '%s' "), xgetcwd());
+ cwd = xgetcwd();
+ fprintf(stderr, _("Testing mtime in '%s' "), cwd);
+ free(cwd);
+
atexit(remove_test_directory);
xstat_mtime_dir(&st);
fill_stat_data(&base, &st);
@@ -1099,17 +1103,20 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
}
if (split_index > 0) {
- init_split_index(&the_index);
- the_index.cache_changed |= SPLIT_INDEX_ORDERED;
- } else if (!split_index && the_index.split_index) {
- /*
- * can't discard_split_index(&the_index); because that
- * will destroy split_index->base->cache[], which may
- * be shared with the_index.cache[]. So yeah we're
- * leaking a bit here.
- */
- the_index.split_index = NULL;
- the_index.cache_changed |= SOMETHING_CHANGED;
+ if (git_config_get_split_index() == 0)
+ warning(_("core.splitIndex is set to false; "
+ "remove or change it, if you really want to "
+ "enable split index"));
+ if (the_index.split_index)
+ the_index.cache_changed |= SPLIT_INDEX_ORDERED;
+ else
+ add_split_index(&the_index);
+ } else if (!split_index) {
+ if (git_config_get_split_index() == 1)
+ warning(_("core.splitIndex is set to true; "
+ "remove or change it, if you really want to "
+ "disable split index"));
+ remove_split_index(&the_index);
}
switch (untracked_cache) {
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 7f30d3a76f..0b2ecf41ae 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -433,7 +433,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
* For purposes of backwards compatibility, we treat
* NULL_SHA1 as "don't care" here:
*/
- return delete_ref(refname,
+ return delete_ref(msg, refname,
(oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL,
flags);
else
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 831fe058a5..ff5dfd2b10 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -24,6 +24,7 @@ struct add_opts {
int force;
int detach;
int checkout;
+ int keep_locked;
const char *new_branch;
int force_new_branch;
};
@@ -106,8 +107,7 @@ static void prune_worktrees(void)
printf("%s\n", reason.buf);
if (show_only)
continue;
- strbuf_reset(&path);
- strbuf_addstr(&path, git_path("worktrees/%s", d->d_name));
+ git_path_buf(&path, "worktrees/%s", d->d_name);
ret = remove_dir_recursively(&path, 0);
if (ret < 0 && errno == ENOTDIR)
ret = unlink(path.buf);
@@ -215,8 +215,7 @@ static int add_worktree(const char *path, const char *refname,
}
name = worktree_basename(path, &len);
- strbuf_addstr(&sb_repo,
- git_path("worktrees/%.*s", (int)(path + len - name), name));
+ git_path_buf(&sb_repo, "worktrees/%.*s", (int)(path + len - name), name);
len = sb_repo.len;
if (safe_create_leading_directories_const(sb_repo.buf))
die_errno(_("could not create leading directories of '%s'"),
@@ -242,7 +241,10 @@ static int add_worktree(const char *path, const char *refname,
* after the preparation is over.
*/
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
- write_file(sb.buf, "initializing");
+ if (!opts->keep_locked)
+ write_file(sb.buf, "initializing");
+ else
+ write_file(sb.buf, "added with --lock");
strbuf_addf(&sb_git, "%s/.git", path);
if (safe_create_leading_directories_const(sb_git.buf))
@@ -303,9 +305,11 @@ static int add_worktree(const char *path, const char *refname,
junk_git_dir = NULL;
done:
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/locked", sb_repo.buf);
- unlink_or_warn(sb.buf);
+ if (ret || !opts->keep_locked) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+ unlink_or_warn(sb.buf);
+ }
argv_array_clear(&child_env);
strbuf_release(&sb);
strbuf_release(&symref);
@@ -318,7 +322,8 @@ static int add(int ac, const char **av, const char *prefix)
{
struct add_opts opts;
const char *new_branch_force = NULL;
- const char *path, *branch;
+ char *path;
+ const char *branch;
struct option options[] = {
OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -327,6 +332,7 @@ static int add(int ac, const char **av, const char *prefix)
N_("create or reset a branch")),
OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
+ OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
OPT_END()
};
@@ -338,7 +344,7 @@ static int add(int ac, const char **av, const char *prefix)
if (ac < 1 || ac > 2)
usage_with_options(worktree_usage, options);
- path = prefix_filename(prefix, strlen(prefix), av[0]);
+ path = prefix_filename(prefix, av[0]);
branch = ac < 2 ? "HEAD" : av[1];
if (!strcmp(branch, "-"))
@@ -408,9 +414,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
- else if (wt->head_ref)
- strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
- else
+ else if (wt->head_ref) {
+ char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
+ strbuf_addf(&sb, "[%s]", ref);
+ free(ref);
+ } else
strbuf_addstr(&sb, "(error)");
}
printf("%s\n", sb.buf);