#include "builtin.h"
#include "tag.h"
#include "reflog-walk.h"
+#include "patch-ids.h"
+#include "refs.h"
static int default_show_root = 1;
/* this is in builtin-diff.c */
void add_head(struct rev_info *revs);
+static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
+{
+ int plen = strlen(prefix);
+ int nlen = strlen(name);
+ struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen);
+ memcpy(res->name, prefix, plen);
+ memcpy(res->name + plen, name, nlen + 1);
+ res->next = add_decoration(&name_decoration, obj, res);
+}
+
+static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
+{
+ struct object *obj = parse_object(sha1);
+ if (!obj)
+ return 0;
+ add_name_decoration("", refname, obj);
+ while (obj->type == OBJ_TAG) {
+ obj = ((struct tag *)obj)->tagged;
+ if (!obj)
+ break;
+ add_name_decoration("tag: ", refname, obj);
+ }
+ return 0;
+}
+
static void cmd_log_init(int argc, const char **argv, const char *prefix,
struct rev_info *rev)
{
int i;
+ int decorate = 0;
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
git_log_output_encoding = xstrdup(arg);
else
git_log_output_encoding = "";
- }
- else
+ } else if (!strcmp(arg, "--decorate")) {
+ if (!decorate)
+ for_each_ref(add_ref_decoration, NULL);
+ decorate = 1;
+ } else
die("unrecognized argument: %s", arg);
}
}
static FILE *realstdout = NULL;
static const char *output_directory = NULL;
-static int reopen_stdout(struct commit *commit, int nr, int keep_subject)
+static int reopen_stdout(struct commit *commit, int nr, int keep_subject,
+ int numbered_files)
{
char filename[PATH_MAX];
char *sol;
filename[len++] = '/';
}
- sprintf(filename + len, "%04d", nr);
- len = strlen(filename);
-
- sol = strstr(commit->buffer, "\n\n");
- if (sol) {
- int j, space = 1;
-
- sol += 2;
- /* strip [PATCH] or [PATCH blabla] */
- if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
- char *eos = strchr(sol + 6, ']');
- if (eos) {
- while (isspace(*eos))
- eos++;
- sol = eos;
- }
- }
+ if (numbered_files) {
+ sprintf(filename + len, "%d", nr);
+ len = strlen(filename);
- for (j = 0;
- j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
- len < sizeof(filename) - suffix_len &&
- sol[j] && sol[j] != '\n';
- j++) {
- if (istitlechar(sol[j])) {
- if (space) {
- filename[len++] = '-';
- space = 0;
+ } else {
+ sprintf(filename + len, "%04d", nr);
+ len = strlen(filename);
+
+ sol = strstr(commit->buffer, "\n\n");
+ if (sol) {
+ int j, space = 1;
+
+ sol += 2;
+ /* strip [PATCH] or [PATCH blabla] */
+ if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
+ char *eos = strchr(sol + 6, ']');
+ if (eos) {
+ while (isspace(*eos))
+ eos++;
+ sol = eos;
}
- filename[len++] = sol[j];
- if (sol[j] == '.')
- while (sol[j + 1] == '.')
- j++;
- } else
- space = 1;
+ }
+
+ for (j = 0;
+ j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
+ len < sizeof(filename) - suffix_len &&
+ sol[j] && sol[j] != '\n';
+ j++) {
+ if (istitlechar(sol[j])) {
+ if (space) {
+ filename[len++] = '-';
+ space = 0;
+ }
+ filename[len++] = sol[j];
+ if (sol[j] == '.')
+ while (sol[j + 1] == '.')
+ j++;
+ } else
+ space = 1;
+ }
+ while (filename[len - 1] == '.'
+ || filename[len - 1] == '-')
+ len--;
+ filename[len] = 0;
}
- while (filename[len - 1] == '.' || filename[len - 1] == '-')
- len--;
- filename[len] = 0;
+ if (len + suffix_len >= sizeof(filename))
+ return error("Patch pathname too long");
+ strcpy(filename + len, fmt_patch_suffix);
}
- if (len + suffix_len >= sizeof(filename))
- return error("Patch pathname too long");
- strcpy(filename + len, fmt_patch_suffix);
+
fprintf(realstdout, "%s\n", filename);
if (freopen(filename, "w", stdout) == NULL)
return error("Cannot open patch file %s",filename);
- return 0;
+ return 0;
}
-static int get_patch_id(struct commit *commit, struct diff_options *options,
- unsigned char *sha1)
-{
- if (commit->parents)
- diff_tree_sha1(commit->parents->item->object.sha1,
- commit->object.sha1, "", options);
- else
- diff_root_tree_sha1(commit->object.sha1, "", options);
- diffcore_std(options);
- return diff_flush_patch_id(options, sha1);
-}
-
-static void get_patch_ids(struct rev_info *rev, struct diff_options *options, const char *prefix)
+static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix)
{
struct rev_info check_rev;
struct commit *commit;
struct object *o1, *o2;
unsigned flags1, flags2;
- unsigned char sha1[20];
if (rev->pending.nr != 2)
die("Need exactly one range.");
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die("Not a range.");
- diff_setup(options);
- options->recursive = 1;
- if (diff_setup_done(options) < 0)
- die("diff_setup_done failed");
+ init_patch_ids(ids);
/* given a range a..b get all patch ids for b..a */
init_revisions(&check_rev, prefix);
if (commit->parents && commit->parents->next)
continue;
- if (!get_patch_id(commit, options, sha1))
- created_object(sha1, xcalloc(1, sizeof(struct object)));
+ add_commit_patch_id(commit, ids);
}
/* reset for next revision walk */
int numbered = 0;
int start_number = -1;
int keep_subject = 0;
+ int numbered_files = 0; /* _just_ numbers */
+ int subject_prefix = 0;
int ignore_if_in_upstream = 0;
int thread = 0;
const char *in_reply_to = NULL;
- struct diff_options patch_id_opts;
+ struct patch_ids ids;
char *add_signoff = NULL;
char message_id[1024];
char ref_message_id[1024];
/*
* Parse the arguments before setup_revisions(), or something
- * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is
+ * like "git format-patch -o a123 HEAD^.." may fail; a123 is
* possibly a valid SHA1.
*/
for (i = 1, j = 1; i < argc; i++) {
numbered = 1;
else if (!prefixcmp(argv[i], "--start-number="))
start_number = strtol(argv[i] + 15, NULL, 10);
+ else if (!strcmp(argv[i], "--numbered-files"))
+ numbered_files = 1;
else if (!strcmp(argv[i], "--start-number")) {
i++;
if (i == argc)
if (i == argc)
die("Need a Message-Id for --in-reply-to");
in_reply_to = argv[i];
- }
- else if (!prefixcmp(argv[i], "--suffix="))
+ } else if (!prefixcmp(argv[i], "--subject-prefix=")) {
+ subject_prefix = 1;
+ rev.subject_prefix = argv[i] + 17;
+ } else if (!prefixcmp(argv[i], "--suffix="))
fmt_patch_suffix = argv[i] + 9;
else
argv[j++] = argv[i];
start_number = 1;
if (numbered && keep_subject)
die ("-n and -k are mutually exclusive.");
+ if (keep_subject && subject_prefix)
+ die ("--subject-prefix and -k are mutually exclusive.");
+ if (numbered_files && use_stdout)
+ die ("--numbered-files and --stdout are mutually exclusive.");
argc = setup_revisions(argc, argv, &rev, "HEAD");
if (argc > 1)
}
if (ignore_if_in_upstream)
- get_patch_ids(&rev, &patch_id_opts, prefix);
+ get_patch_ids(&rev, &ids, prefix);
if (!use_stdout)
realstdout = fdopen(dup(1), "w");
prepare_revision_walk(&rev);
while ((commit = get_revision(&rev)) != NULL) {
- unsigned char sha1[20];
-
/* ignore merges */
if (commit->parents && commit->parents->next)
continue;
if (ignore_if_in_upstream &&
- !get_patch_id(commit, &patch_id_opts, sha1) &&
- lookup_object(sha1))
+ has_commit_patch_id(commit, &ids))
continue;
nr++;
rev.message_id = message_id;
}
if (!use_stdout)
- if (reopen_stdout(commit, rev.nr, keep_subject))
+ if (reopen_stdout(commit, rev.nr, keep_subject,
+ numbered_files))
die("Failed to create output files");
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
fclose(stdout);
}
free(list);
+ if (ignore_if_in_upstream)
+ free_patch_ids(&ids);
return 0;
}
int cmd_cherry(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
- struct diff_options patch_id_opts;
+ struct patch_ids ids;
struct commit *commit;
struct commit_list *list = NULL;
const char *upstream;
return 0;
}
- get_patch_ids(&revs, &patch_id_opts, prefix);
+ get_patch_ids(&revs, &ids, prefix);
if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
die("Unknown commit %s", limit);
}
while (list) {
- unsigned char sha1[20];
char sign = '+';
commit = list->item;
- if (!get_patch_id(commit, &patch_id_opts, sha1) &&
- lookup_object(sha1))
+ if (has_commit_patch_id(commit, &ids))
sign = '-';
if (verbose) {
list = list->next;
}
+ free_patch_ids(&ids);
return 0;
}