* 2006 Junio Hamano
*/
#include "cache.h"
+#include "config.h"
#include "refs.h"
#include "color.h"
#include "commit.h"
#include "version.h"
#include "mailmap.h"
#include "gpg-interface.h"
+#include "progress.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
struct string_list args;
};
-static int parse_decoration_style(const char *var, const char *value)
+static int auto_decoration_style(void)
{
- switch (git_config_maybe_bool(var, value)) {
+ return (isatty(1) || pager_in_use()) ? DECORATE_SHORT_REFS : 0;
+}
+
+static int parse_decoration_style(const char *value)
+{
+ switch (git_parse_maybe_bool(value)) {
case 1:
return DECORATE_SHORT_REFS;
case 0:
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;
}
if (unset)
decoration_style = 0;
else if (arg)
- decoration_style = parse_decoration_style("command line", arg);
+ decoration_style = parse_decoration_style(arg);
else
decoration_style = DECORATE_SHORT_REFS;
{
init_grep_defaults();
init_diff_ui_defaults();
+
+ decoration_style = auto_decoration_style();
}
static void cmd_log_init_defaults(struct rev_info *rev)
*/
rev->max_count++;
if (!rev->reflog_info) {
- /* we allow cycles in reflog ancestry */
+ /*
+ * We may show a given commit multiple times when
+ * walking the reflogs.
+ */
free_commit_buffer(commit);
+ free_commit_list(commit->parents);
+ commit->parents = NULL;
}
- free_commit_list(commit->parents);
- commit->parents = NULL;
if (saved_nrl < rev->diffopt.needed_rename_limit)
saved_nrl = rev->diffopt.needed_rename_limit;
if (rev->diffopt.degraded_cc_to_c)
if (!strcmp(var, "log.date"))
return git_config_string(&default_date_mode, var, value);
if (!strcmp(var, "log.decorate")) {
- decoration_style = parse_decoration_style(var, value);
+ decoration_style = parse_decoration_style(value);
if (decoration_style < 0)
decoration_style = 0; /* maybe warn? */
return 0;
strbuf_release(&out);
}
-static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, const char *obj_name)
+static int show_blob_object(const struct object_id *oid, struct rev_info *rev, const char *obj_name)
{
- unsigned char sha1c[20];
+ struct object_id oidc;
struct object_context obj_context;
char *buf;
unsigned long size;
fflush(rev->diffopt.file);
if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
!DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
- return stream_blob_to_fd(1, sha1, NULL, 0);
+ return stream_blob_to_fd(1, oid, NULL, 0);
- if (get_sha1_with_context(obj_name, 0, sha1c, &obj_context))
+ if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+ &oidc, &obj_context))
die(_("Not a valid object name %s"), obj_name);
- if (!obj_context.path[0] ||
- !textconv_object(obj_context.path, obj_context.mode, sha1c, 1, &buf, &size))
- return stream_blob_to_fd(1, sha1, NULL, 0);
+ if (!obj_context.path ||
+ !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) {
+ free(obj_context.path);
+ return stream_blob_to_fd(1, oid, NULL, 0);
+ }
if (!buf)
die(_("git show %s: bad file"), obj_name);
write_or_die(1, buf, size);
+ free(obj_context.path);
return 0;
}
-static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
+static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
{
unsigned long size;
enum object_type type;
- char *buf = read_sha1_file(sha1, &type, &size);
+ char *buf = read_sha1_file(oid->hash, &type, &size);
int offset = 0;
if (!buf)
- return error(_("Could not read object %s"), sha1_to_hex(sha1));
+ return error(_("Could not read object %s"), oid_to_hex(oid));
assert(type == OBJ_TAG);
while (offset < size && buf[offset] != '\n') {
const char *name = objects[i].name;
switch (o->type) {
case OBJ_BLOB:
- ret = show_blob_object(o->oid.hash, &rev, name);
+ ret = show_blob_object(&o->oid, &rev, name);
break;
case OBJ_TAG: {
struct tag *t = (struct tag *)o;
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
t->tag,
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
- ret = show_tag_object(o->oid.hash, &rev);
+ ret = show_tag_object(&o->oid, &rev);
rev.shown_one = 1;
if (ret)
break;
- o = parse_object(t->tagged->oid.hash);
+ o = parse_object(&t->tagged->oid);
if (!o)
ret = error(_("Could not read object %s"),
oid_to_hex(&t->tagged->oid));
return 0;
}
if (!strcmp(var, "format.from")) {
- int b = git_config_maybe_bool(var, value);
+ int b = git_parse_maybe_bool(value);
free(from);
if (b < 0)
from = xstrdup(value);
if (output_directory) {
strbuf_addstr(&filename, output_directory);
if (filename.len >=
- PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
+ PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) {
+ strbuf_release(&filename);
return error(_("name of output directory is too long"));
+ }
strbuf_complete(&filename, '/');
}
if (!quiet)
printf("%s\n", filename.buf + outdir_offset);
- if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL)
- return error(_("Cannot open patch file %s"), filename.buf);
+ if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) {
+ error_errno(_("Cannot open patch file %s"), filename.buf);
+ strbuf_release(&filename);
+ return -1;
+ }
strbuf_release(&filename);
return 0;
o2 = rev->pending.objects[1].item;
flags1 = o1->flags;
flags2 = o2->flags;
- c1 = lookup_commit_reference(o1->oid.hash);
- c2 = lookup_commit_reference(o2->oid.hash);
+ c1 = lookup_commit_reference(&o1->oid);
+ c2 = lookup_commit_reference(&o2->oid);
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die(_("Not a range."));
static void gen_message_id(struct rev_info *info, char *base)
{
struct strbuf buf = STRBUF_INIT;
- strbuf_addf(&buf, "%s.%lu.git.%s", base,
- (unsigned long) time(NULL),
+ strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
+ (timestamp_t) time(NULL),
git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));
info->message_id = strbuf_detach(&buf, NULL);
}
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);
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);
diff_setup_done(&opts);
- diff_tree_sha1(origin->tree->object.oid.hash,
- head->tree->object.oid.hash,
- "", &opts);
+ diff_tree_oid(&origin->tree->object.oid,
+ &head->tree->object.oid,
+ "", &opts);
diffcore_std(&opts);
diff_flush(&opts);
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[] = {
return 0;
}
+static int rfc_callback(const struct option *opt, const char *arg, int unset)
+{
+ return subject_prefix_callback(opt, "RFC PATCH", unset);
+}
+
static int numbered_cmdline_opt = 0;
static int numbered_callback(const struct option *opt, const char *arg,
if (upstream) {
struct commit_list *base_list;
struct commit *commit;
- unsigned char sha1[20];
+ struct object_id oid;
- if (get_sha1(upstream, sha1))
+ if (get_oid(upstream, &oid))
die(_("Failed to resolve '%s' as a valid ref."), upstream);
- commit = lookup_commit_or_die(sha1, "upstream base");
+ commit = lookup_commit_or_die(&oid, "upstream base");
base_list = get_merge_bases_many(commit, total, list);
/* There should be one and only one merge base. */
if (!base_list || base_list->next)
if (rev_nr % 2)
rev[i] = rev[2 * i];
- rev_nr = (rev_nr + 1) / 2;
+ rev_nr = DIV_ROUND_UP(rev_nr, 2);
}
if (!in_merge_bases(base, rev[0]))
* and stuff them in bases structure.
*/
while ((commit = get_revision(&revs)) != NULL) {
- unsigned char sha1[20];
+ struct object_id oid;
struct object_id *patch_id;
if (commit->util)
continue;
- if (commit_patch_id(commit, &diffopt, sha1, 0))
+ if (commit_patch_id(commit, &diffopt, &oid, 0))
die(_("cannot get patch id"));
ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
patch_id = bases->patch_id + bases->nr_patch_id;
- hashcpy(patch_id->hash, sha1);
+ oidcpy(patch_id, &oid);
bases->nr_patch_id++;
}
}
char *branch_name = NULL;
char *base_commit = NULL;
struct base_tree_info bases;
+ int show_progress = 0;
+ struct progress *progress = NULL;
const struct option builtin_format_patch_options[] = {
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
N_("start numbering patches at <n> instead of 1")),
OPT_INTEGER('v', "reroll-count", &reroll_count,
N_("mark the series as Nth re-roll")),
+ { OPTION_CALLBACK, 0, "rfc", &rev, NULL,
+ N_("Use [RFC PATCH] instead of [PATCH]"),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback },
{ OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
N_("Use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback },
OPT_FILENAME(0, "signature-file", &signature_file,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
+ OPT_BOOL(0, "progress", &show_progress,
+ N_("show progress while generating patches")),
OPT_END()
};
if (numbered && keep_subject)
die (_("-n and -k are mutually exclusive."));
if (keep_subject && subject_prefix)
- die (_("--subject-prefix and -k are mutually exclusive."));
+ die (_("--subject-prefix/--rfc and -k are mutually exclusive."));
rev.preserve_subject = keep_subject;
argc = setup_revisions(argc, argv, &rev, &s_r_opt);
check_head = 1;
if (check_head) {
- unsigned char sha1[20];
const char *ref, *v;
ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- sha1, NULL);
+ NULL, NULL);
if (ref && skip_prefix(ref, "refs/heads/", &v))
branch_name = xstrdup(v);
else
/* nothing to do */
return 0;
total = nr;
- if (!keep_subject && auto_number && total > 1)
- numbered = 1;
- if (numbered)
- rev.total = total + start_number - 1;
if (cover_letter == -1) {
if (config_cover_letter == COVER_AUTO)
cover_letter = (total > 1);
else
cover_letter = (config_cover_letter == COVER_ON);
}
+ if (!keep_subject && auto_number && (total > 1 || cover_letter))
+ numbered = 1;
+ if (numbered)
+ rev.total = total + start_number - 1;
if (!signature) {
; /* --no-signature inhibits all signatures */
start_number--;
}
rev.add_signoff = do_signoff;
+
+ if (show_progress)
+ progress = start_delayed_progress(_("Generating patches"), total);
while (0 <= --nr) {
int shown;
+ display_progress(progress, total - nr);
commit = list[nr];
rev.nr = total - nr + (start_number - 1);
/* Make the second and subsequent mails replies to the first */
if (!use_stdout)
fclose(rev.diffopt.file);
}
+ stop_progress(&progress);
free(list);
free(branch_name);
string_list_clear(&extra_to, 0);
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
{
- unsigned char sha1[20];
- if (get_sha1(arg, sha1) == 0) {
- struct commit *commit = lookup_commit_reference(sha1);
+ struct object_id oid;
+ if (get_oid(arg, &oid) == 0) {
+ struct commit *commit = lookup_commit_reference(&oid);
if (commit) {
commit->object.flags |= flags;
add_pending_object(revs, &commit->object, arg);