format-patch: add --range-diff option to embed diff in cover letter
[gitweb.git] / builtin / log.c
index 8078a43d14f014885cc4331cd516efbd5bff6524..4b65673f12978d78b1819c410417278670a7ff20 100644 (file)
@@ -30,7 +30,9 @@
 #include "gpg-interface.h"
 #include "progress.h"
 #include "commit-slab.h"
+#include "repository.h"
 #include "interdiff.h"
+#include "range-diff.h"
 
 #define MAIL_DEFAULT_WRAP 72
 
@@ -620,7 +622,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                        rev.shown_one = 1;
                        if (ret)
                                break;
-                       o = parse_object(&t->tagged->oid);
+                       o = parse_object(the_repository, &t->tagged->oid);
                        if (!o)
                                ret = error(_("Could not read object %s"),
                                            oid_to_hex(&t->tagged->oid));
@@ -907,8 +909,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
        o2 = rev->pending.objects[1].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
-       c1 = lookup_commit_reference(&o1->oid);
-       c2 = lookup_commit_reference(&o2->oid);
+       c1 = lookup_commit_reference(the_repository, &o1->oid);
+       c2 = lookup_commit_reference(the_repository, &o2->oid);
 
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
                die(_("Not a range."));
@@ -1088,6 +1090,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
                fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
                show_interdiff(rev, 0);
        }
+
+       if (rev->rdiff1) {
+               fprintf_ln(rev->diffopt.file, "%s", _("Range-diff:"));
+               show_range_diff(rev->rdiff1, rev->rdiff2,
+                               rev->creation_factor, 1, &rev->diffopt);
+       }
 }
 
 static const char *clean_message_id(const char *msg_id)
@@ -1437,6 +1445,17 @@ static const char *diff_title(struct strbuf *sb, int reroll_count,
        return sb->buf;
 }
 
+static void infer_range_diff_ranges(struct strbuf *r1,
+                                   struct strbuf *r2,
+                                   const char *prev,
+                                   struct commit *head)
+{
+       const char *head_oid = oid_to_hex(&head->object.oid);
+
+       strbuf_addf(r1, "%s..%s", head_oid, prev);
+       strbuf_addf(r2, "%s..%s", prev, head_oid);
+}
+
 int cmd_format_patch(int argc, const char **argv, const char *prefix)
 {
        struct commit *commit;
@@ -1466,6 +1485,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        struct progress *progress = NULL;
        struct oid_array idiff_prev = OID_ARRAY_INIT;
        struct strbuf idiff_title = STRBUF_INIT;
+       const char *rdiff_prev = NULL;
+       struct strbuf rdiff1 = STRBUF_INIT;
+       struct strbuf rdiff2 = STRBUF_INIT;
 
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
@@ -1540,8 +1562,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "progress", &show_progress,
                         N_("show progress while generating patches")),
                OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
-                            N_("show changes against <rev> in cover letter"),
+                            N_("show changes against <rev> in cover letter or single patch"),
                             parse_opt_object_name),
+               OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"),
+                          N_("show changes against <refspec> in cover letter")),
                OPT_END()
        };
 
@@ -1765,8 +1789,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                rev.total = total + start_number - 1;
 
        if (idiff_prev.nr) {
-               if (!cover_letter)
-                       die(_("--interdiff requires --cover-letter"));
+               if (!cover_letter && total != 1)
+                       die(_("--interdiff requires --cover-letter or single patch"));
                rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1];
                rev.idiff_oid2 = get_commit_tree_oid(list[0]);
                rev.idiff_title = diff_title(&idiff_title, reroll_count,
@@ -1774,6 +1798,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                                             _("Interdiff against v%d:"));
        }
 
+       if (rdiff_prev) {
+               if (!cover_letter)
+                       die(_("--range-diff requires --cover-letter"));
+
+               infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev, list[0]);
+               rev.rdiff1 = rdiff1.buf;
+               rev.rdiff2 = rdiff2.buf;
+               rev.creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
+       }
+
        if (!signature) {
                ; /* --no-signature inhibits all signatures */
        } else if (signature && signature != git_version_string) {
@@ -1811,6 +1845,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                print_signature(rev.diffopt.file);
                total++;
                start_number--;
+               /* interdiff in cover-letter; omit from patches */
+               rev.idiff_oid1 = NULL;
        }
        rev.add_signoff = do_signoff;
 
@@ -1895,6 +1931,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 done:
        oid_array_clear(&idiff_prev);
        strbuf_release(&idiff_title);
+       strbuf_release(&rdiff1);
+       strbuf_release(&rdiff2);
        return 0;
 }
 
@@ -1902,7 +1940,8 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
 {
        struct object_id oid;
        if (get_oid(arg, &oid) == 0) {
-               struct commit *commit = lookup_commit_reference(&oid);
+               struct commit *commit = lookup_commit_reference(the_repository,
+                                                               &oid);
                if (commit) {
                        commit->object.flags |= flags;
                        add_pending_object(revs, &commit->object, arg);