builtin/diff-pairs: allow explicit diff queue flush

The diffs queued from git-diff-pairs(1) are flushed when stdin is closed. To enable greater flexibility, allow control over when the diff queue is flushed by writing a single NUL byte on stdin between input file pairs. Diff output between flushes is separated by a single NUL byte. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Justin Tobler committed Feb 28, 2025 at 15:33 UTC cf15095ec52f1e997ec9eef42bdf275d2a68fe66
3 files changed +27
Documentation/git-diff-pairs.adoc
+4
@@ -17,6 +17,10 @@ in the NUL-terminated raw output format as generated by commands such as `git
17 diff-tree -z -r --raw`. By default, the outputted diffs are computed and shown
18 in the patch format when stdin closes.
19
20 +A single NUL byte may be written to stdin between raw input lines to compute
21 +file pair diffs up to that point instead of waiting for stdin to close. A NUL
22 +byte is also written to the output to delimit between these batches of diffs.
23 +
24 Usage of this command enables the traditional diff pipeline to be broken up
25 into separate stages where `diff-pairs` acts as the output phase. Other
26 commands, such as `diff-tree`, may serve as a frontend to compute the raw
builtin/diff-pairs.c
+14
@@ -57,6 +57,7 @@ int cmd_diff_pairs(int argc, const char **argv, const char *prefix,
57 show_usage_with_options_if_asked(argc, argv, builtin_diff_pairs_usage, parseopts);
58
59 repo_config(repo, git_diff_basic_config, NULL);
60 + revs.diffopt.no_free = 1;
61 revs.disable_stdin = 1;
62 revs.abbrev = 0;
63 revs.diff = 1;
@@ -106,6 +107,18 @@ int cmd_diff_pairs(int argc, const char **argv, const char *prefix,
107 break;
108
109 p = meta.buf;
110 + if (!*p) {
111 + diffcore_std(&revs.diffopt);
112 + diff_flush(&revs.diffopt);
113 + /*
114 + * When the diff queue is explicitly flushed, append a
115 + * NUL byte to separate batches of diffs.
116 + */
117 + fputc('\0', revs.diffopt.file);
118 + fflush(revs.diffopt.file);
119 + continue;
120 + }
121 +
122 if (*p != ':')
123 die(_("invalid raw diff input"));
124 p++;
@@ -179,6 +192,7 @@ int cmd_diff_pairs(int argc, const char **argv, const char *prefix,
192 }
193 }
194
195 + revs.diffopt.no_free = 0;
196 diffcore_std(&revs.diffopt);
197 diff_flush(&revs.diffopt);
198 ret = diff_result_code(&revs);
t/t4070-diff-pairs.sh
+9
@@ -78,4 +78,13 @@ test_expect_success 'diff-pairs does not support pathspec arguments' '
78 test_cmp expect err
79 '
80
81 +test_expect_success 'diff-pairs explicit queue flush' '
82 + git diff-tree -r -M -C -C -z base new >expect &&
83 + printf "\0" >>expect &&
84 + git diff-tree -r -M -C -C -z base new >>expect &&
85 +
86 + git diff-pairs --raw -z <expect >actual &&
87 + test_cmp expect actual
88 +'
89 +
90 test_done