a6cbf44f443bf5dffb29576e1f426a252cc9eba9
[git.git] / diff.c
1 /*
2  * Copyright (C) 2005 Junio C Hamano
3  */
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 #include <signal.h>
7 #include <limits.h>
8 #include "cache.h"
9 #include "diff.h"
10 #include "diffcore.h"
11
12 static const char *diff_opts = "-pu";
13 static unsigned char null_sha1[20] = { 0, };
14
15 static int reverse_diff;
16 static int generate_patch;
17 static int line_termination = '\n';
18 static int inter_name_termination = '\t';
19 static const char **pathspec;
20 static int speccnt;
21
22 static const char *external_diff(void)
23 {
24         static const char *external_diff_cmd = NULL;
25         static int done_preparing = 0;
26
27         if (done_preparing)
28                 return external_diff_cmd;
29
30         /*
31          * Default values above are meant to match the
32          * Linux kernel development style.  Examples of
33          * alternative styles you can specify via environment
34          * variables are:
35          *
36          * GIT_DIFF_OPTS="-c";
37          */
38         if (gitenv("GIT_EXTERNAL_DIFF"))
39                 external_diff_cmd = gitenv("GIT_EXTERNAL_DIFF");
40
41         /* In case external diff fails... */
42         diff_opts = gitenv("GIT_DIFF_OPTS") ? : diff_opts;
43
44         done_preparing = 1;
45         return external_diff_cmd;
46 }
47
48 /* Help to copy the thing properly quoted for the shell safety.
49  * any single quote is replaced with '\'', and the caller is
50  * expected to enclose the result within a single quote pair.
51  *
52  * E.g.
53  *  original     sq_expand     result
54  *  name     ==> name      ==> 'name'
55  *  a b      ==> a b       ==> 'a b'
56  *  a'b      ==> a'\''b    ==> 'a'\''b'
57  */
58 static char *sq_expand(const char *src)
59 {
60         static char *buf = NULL;
61         int cnt, c;
62         const char *cp;
63         char *bp;
64
65         /* count bytes needed to store the quoted string. */
66         for (cnt = 1, cp = src; *cp; cnt++, cp++)
67                 if (*cp == '\'')
68                         cnt += 3;
69
70         buf = xmalloc(cnt);
71         bp = buf;
72         while ((c = *src++)) {
73                 if (c != '\'')
74                         *bp++ = c;
75                 else {
76                         bp = strcpy(bp, "'\\''");
77                         bp += 4;
78                 }
79         }
80         *bp = 0;
81         return buf;
82 }
83
84 static struct diff_tempfile {
85         const char *name; /* filename external diff should read from */
86         char hex[41];
87         char mode[10];
88         char tmp_path[50];
89 } diff_temp[2];
90
91 static void builtin_diff(const char *name_a,
92                          const char *name_b,
93                          struct diff_tempfile *temp,
94                          const char *xfrm_msg)
95 {
96         int i, next_at, cmd_size;
97         const char *diff_cmd = "diff -L'%s%s' -L'%s%s'";
98         const char *diff_arg  = "'%s' '%s'||:"; /* "||:" is to return 0 */
99         const char *input_name_sq[2];
100         const char *path0[2];
101         const char *path1[2];
102         const char *name_sq[2];
103         char *cmd;
104
105         name_sq[0] = sq_expand(name_a);
106         name_sq[1] = sq_expand(name_b);
107
108         /* diff_cmd and diff_arg have 6 %s in total which makes
109          * the sum of these strings 12 bytes larger than required.
110          * we use 2 spaces around diff-opts, and we need to count
111          * terminating NUL, so we subtract 9 here.
112          */
113         cmd_size = (strlen(diff_cmd) + strlen(diff_opts) +
114                         strlen(diff_arg) - 9);
115         for (i = 0; i < 2; i++) {
116                 input_name_sq[i] = sq_expand(temp[i].name);
117                 if (!strcmp(temp[i].name, "/dev/null")) {
118                         path0[i] = "/dev/null";
119                         path1[i] = "";
120                 } else {
121                         path0[i] = i ? "b/" : "a/";
122                         path1[i] = name_sq[i];
123                 }
124                 cmd_size += (strlen(path0[i]) + strlen(path1[i]) +
125                              strlen(input_name_sq[i]));
126         }
127
128         cmd = xmalloc(cmd_size);
129
130         next_at = 0;
131         next_at += snprintf(cmd+next_at, cmd_size-next_at,
132                             diff_cmd,
133                             path0[0], path1[0], path0[1], path1[1]);
134         next_at += snprintf(cmd+next_at, cmd_size-next_at,
135                             " %s ", diff_opts);
136         next_at += snprintf(cmd+next_at, cmd_size-next_at,
137                             diff_arg, input_name_sq[0], input_name_sq[1]);
138
139         printf("diff --git a/%s b/%s\n", name_a, name_b);
140         if (!path1[0][0])
141                 printf("new file mode %s\n", temp[1].mode);
142         else if (!path1[1][0])
143                 printf("deleted file mode %s\n", temp[0].mode);
144         else {
145                 if (strcmp(temp[0].mode, temp[1].mode)) {
146                         printf("old mode %s\n", temp[0].mode);
147                         printf("new mode %s\n", temp[1].mode);
148                 }
149                 if (xfrm_msg && xfrm_msg[0])
150                         fputs(xfrm_msg, stdout);
151
152                 if (strncmp(temp[0].mode, temp[1].mode, 3))
153                         /* we do not run diff between different kind
154                          * of objects.
155                          */
156                         exit(0);
157         }
158         fflush(NULL);
159         execlp("/bin/sh","sh", "-c", cmd, NULL);
160 }
161
162 struct diff_filespec *alloc_filespec(const char *path)
163 {
164         int namelen = strlen(path);
165         struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
166         spec->path = (char *)(spec + 1);
167         strcpy(spec->path, path);
168         spec->should_free = spec->should_munmap = 0;
169         spec->xfrm_flags = 0;
170         spec->size = 0;
171         spec->data = 0;
172         spec->mode = 0;
173         memset(spec->sha1, 0, 20);
174         return spec;
175 }
176
177 void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
178                    unsigned short mode)
179 {
180         if (mode) { /* just playing defensive */
181                 spec->mode = mode;
182                 memcpy(spec->sha1, sha1, 20);
183                 spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
184         }
185 }
186
187 /*
188  * Given a name and sha1 pair, if the dircache tells us the file in
189  * the work tree has that object contents, return true, so that
190  * prepare_temp_file() does not have to inflate and extract.
191  */
192 static int work_tree_matches(const char *name, const unsigned char *sha1)
193 {
194         struct cache_entry *ce;
195         struct stat st;
196         int pos, len;
197
198         /* We do not read the cache ourselves here, because the
199          * benchmark with my previous version that always reads cache
200          * shows that it makes things worse for diff-tree comparing
201          * two linux-2.6 kernel trees in an already checked out work
202          * tree.  This is because most diff-tree comparisons deal with
203          * only a small number of files, while reading the cache is
204          * expensive for a large project, and its cost outweighs the
205          * savings we get by not inflating the object to a temporary
206          * file.  Practically, this code only helps when we are used
207          * by diff-cache --cached, which does read the cache before
208          * calling us.
209          */
210         if (!active_cache)
211                 return 0;
212
213         len = strlen(name);
214         pos = cache_name_pos(name, len);
215         if (pos < 0)
216                 return 0;
217         ce = active_cache[pos];
218         if ((lstat(name, &st) < 0) ||
219             !S_ISREG(st.st_mode) || /* careful! */
220             ce_match_stat(ce, &st) ||
221             memcmp(sha1, ce->sha1, 20))
222                 return 0;
223         /* we return 1 only when we can stat, it is a regular file,
224          * stat information matches, and sha1 recorded in the cache
225          * matches.  I.e. we know the file in the work tree really is
226          * the same as the <name, sha1> pair.
227          */
228         return 1;
229 }
230
231 /*
232  * While doing rename detection and pickaxe operation, we may need to
233  * grab the data for the blob (or file) for our own in-core comparison.
234  * diff_filespec has data and size fields for this purpose.
235  */
236 int diff_populate_filespec(struct diff_filespec *s)
237 {
238         int err = 0;
239         if (!DIFF_FILE_VALID(s))
240                 die("internal error: asking to populate invalid file.");
241         if (S_ISDIR(s->mode))
242                 return -1;
243
244         if (s->data)
245                 return err;
246         if (!s->sha1_valid ||
247             work_tree_matches(s->path, s->sha1)) {
248                 struct stat st;
249                 int fd;
250                 if (lstat(s->path, &st) < 0) {
251                         if (errno == ENOENT) {
252                         err_empty:
253                                 err = -1;
254                         empty:
255                                 s->data = "";
256                                 s->size = 0;
257                                 return err;
258                         }
259                 }
260                 s->size = st.st_size;
261                 if (!s->size)
262                         goto empty;
263                 if (S_ISLNK(st.st_mode)) {
264                         int ret;
265                         s->data = xmalloc(s->size);
266                         s->should_free = 1;
267                         ret = readlink(s->path, s->data, s->size);
268                         if (ret < 0) {
269                                 free(s->data);
270                                 goto err_empty;
271                         }
272                         return 0;
273                 }
274                 fd = open(s->path, O_RDONLY);
275                 if (fd < 0)
276                         goto err_empty;
277                 s->data = mmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
278                 s->should_munmap = 1;
279                 close(fd);
280         }
281         else {
282                 char type[20];
283                 s->data = read_sha1_file(s->sha1, type, &s->size);
284                 s->should_free = 1;
285         }
286         return 0;
287 }
288
289 void diff_free_filespec_data(struct diff_filespec *s)
290 {
291         if (s->should_free)
292                 free(s->data);
293         else if (s->should_munmap)
294                 munmap(s->data, s->size);
295         s->should_free = s->should_munmap = 0;
296         s->data = 0;
297 }
298
299 static void prep_temp_blob(struct diff_tempfile *temp,
300                            void *blob,
301                            unsigned long size,
302                            unsigned char *sha1,
303                            int mode)
304 {
305         int fd;
306
307         strcpy(temp->tmp_path, ".diff_XXXXXX");
308         fd = mkstemp(temp->tmp_path);
309         if (fd < 0)
310                 die("unable to create temp-file");
311         if (write(fd, blob, size) != size)
312                 die("unable to write temp-file");
313         close(fd);
314         temp->name = temp->tmp_path;
315         strcpy(temp->hex, sha1_to_hex(sha1));
316         temp->hex[40] = 0;
317         sprintf(temp->mode, "%06o", mode);
318 }
319
320 static void prepare_temp_file(const char *name,
321                               struct diff_tempfile *temp,
322                               struct diff_filespec *one)
323 {
324         if (!DIFF_FILE_VALID(one)) {
325         not_a_valid_file:
326                 /* A '-' entry produces this for file-2, and
327                  * a '+' entry produces this for file-1.
328                  */
329                 temp->name = "/dev/null";
330                 strcpy(temp->hex, ".");
331                 strcpy(temp->mode, ".");
332                 return;
333         }
334
335         if (!one->sha1_valid ||
336             work_tree_matches(name, one->sha1)) {
337                 struct stat st;
338                 if (lstat(name, &st) < 0) {
339                         if (errno == ENOENT)
340                                 goto not_a_valid_file;
341                         die("stat(%s): %s", name, strerror(errno));
342                 }
343                 if (S_ISLNK(st.st_mode)) {
344                         int ret;
345                         char *buf, buf_[1024];
346                         buf = ((sizeof(buf_) < st.st_size) ?
347                                xmalloc(st.st_size) : buf_);
348                         ret = readlink(name, buf, st.st_size);
349                         if (ret < 0)
350                                 die("readlink(%s)", name);
351                         prep_temp_blob(temp, buf, st.st_size,
352                                        (one->sha1_valid ?
353                                         one->sha1 : null_sha1),
354                                        (one->sha1_valid ?
355                                         one->mode : S_IFLNK));
356                 }
357                 else {
358                         /* we can borrow from the file in the work tree */
359                         temp->name = name;
360                         if (!one->sha1_valid)
361                                 strcpy(temp->hex, sha1_to_hex(null_sha1));
362                         else
363                                 strcpy(temp->hex, sha1_to_hex(one->sha1));
364                         sprintf(temp->mode, "%06o",
365                                 S_IFREG |ce_permissions(st.st_mode));
366                 }
367                 return;
368         }
369         else {
370                 if (diff_populate_filespec(one))
371                         die("cannot read data blob for %s", one->path);
372                 prep_temp_blob(temp, one->data, one->size,
373                                one->sha1, one->mode);
374         }
375 }
376
377 static void remove_tempfile(void)
378 {
379         int i;
380
381         for (i = 0; i < 2; i++)
382                 if (diff_temp[i].name == diff_temp[i].tmp_path) {
383                         unlink(diff_temp[i].name);
384                         diff_temp[i].name = NULL;
385                 }
386 }
387
388 static void remove_tempfile_on_signal(int signo)
389 {
390         remove_tempfile();
391 }
392
393 static int matches_pathspec(const char *name)
394 {
395         int i;
396         int namelen;
397
398         if (speccnt == 0)
399                 return 1;
400
401         namelen = strlen(name);
402         for (i = 0; i < speccnt; i++) {
403                 int speclen = strlen(pathspec[i]);
404                 if (! strncmp(pathspec[i], name, speclen) &&
405                     speclen <= namelen &&
406                     (name[speclen] == 0 || name[speclen] == '/'))
407                         return 1;
408         }
409         return 0;
410 }
411
412 /* An external diff command takes:
413  *
414  * diff-cmd name infile1 infile1-sha1 infile1-mode \
415  *               infile2 infile2-sha1 infile2-mode [ rename-to ]
416  *
417  */
418 static void run_external_diff(const char *name,
419                               const char *other,
420                               struct diff_filespec *one,
421                               struct diff_filespec *two,
422                               const char *xfrm_msg)
423 {
424         struct diff_tempfile *temp = diff_temp;
425         pid_t pid;
426         int status;
427         static int atexit_asked = 0;
428
429         if (!matches_pathspec(name) && (!other || !matches_pathspec(other)))
430                 return;
431
432         if (one && two) {
433                 prepare_temp_file(name, &temp[0], one);
434                 prepare_temp_file(other ? : name, &temp[1], two);
435                 if (! atexit_asked &&
436                     (temp[0].name == temp[0].tmp_path ||
437                      temp[1].name == temp[1].tmp_path)) {
438                         atexit_asked = 1;
439                         atexit(remove_tempfile);
440                 }
441                 signal(SIGINT, remove_tempfile_on_signal);
442         }
443
444         fflush(NULL);
445         pid = fork();
446         if (pid < 0)
447                 die("unable to fork");
448         if (!pid) {
449                 const char *pgm = external_diff();
450                 if (pgm) {
451                         if (one && two) {
452                                 const char *exec_arg[10];
453                                 const char **arg = &exec_arg[0];
454                                 *arg++ = pgm;
455                                 *arg++ = name;
456                                 *arg++ = temp[0].name;
457                                 *arg++ = temp[0].hex;
458                                 *arg++ = temp[0].mode;
459                                 *arg++ = temp[1].name;
460                                 *arg++ = temp[1].hex;
461                                 *arg++ = temp[1].mode;
462                                 if (other) {
463                                         *arg++ = other;
464                                         *arg++ = xfrm_msg;
465                                 }
466                                 *arg = 0;
467                                 execvp(pgm, (char *const*) exec_arg);
468                         }
469                         else
470                                 execlp(pgm, pgm, name, NULL);
471                 }
472                 /*
473                  * otherwise we use the built-in one.
474                  */
475                 if (one && two)
476                         builtin_diff(name, other ? : name, temp, xfrm_msg);
477                 else
478                         printf("* Unmerged path %s\n", name);
479                 exit(0);
480         }
481         if (waitpid(pid, &status, 0) < 0 ||
482             !WIFEXITED(status) || WEXITSTATUS(status)) {
483                 /* Earlier we did not check the exit status because
484                  * diff exits non-zero if files are different, and
485                  * we are not interested in knowing that.  It was a
486                  * mistake which made it harder to quit a diff-*
487                  * session that uses the git-apply-patch-script as
488                  * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
489                  * should also exit non-zero only when it wants to
490                  * abort the entire diff-* session.
491                  */
492                 remove_tempfile();
493                 fprintf(stderr, "external diff died, stopping at %s.\n", name);
494                 exit(1);
495         }
496         remove_tempfile();
497 }
498
499 int diff_scoreopt_parse(const char *opt)
500 {
501         int diglen, num, scale, i;
502         if (opt[0] != '-' || (opt[1] != 'M' && opt[1] != 'C'))
503                 return -1; /* that is not a -M nor -C option */
504         diglen = strspn(opt+2, "0123456789");
505         if (diglen == 0 || strlen(opt+2) != diglen)
506                 return 0; /* use default */
507         sscanf(opt+2, "%d", &num);
508         for (i = 0, scale = 1; i < diglen; i++)
509                 scale *= 10;
510
511         /* user says num divided by scale and we say internally that
512          * is MAX_SCORE * num / scale.
513          */
514         return MAX_SCORE * num / scale;
515 }
516
517 void diff_setup(int reverse_diff_, int diff_output_style)
518 {
519         reverse_diff = reverse_diff_;
520         generate_patch = 0;
521         switch (diff_output_style) {
522         case DIFF_FORMAT_HUMAN:
523                 line_termination = '\n';
524                 inter_name_termination = '\t';
525                 break;
526         case DIFF_FORMAT_MACHINE:
527                 line_termination = inter_name_termination = 0;
528                 break;
529         case DIFF_FORMAT_PATCH:
530                 generate_patch = 1;
531                 break;
532         }
533 }
534
535 struct diff_queue_struct diff_queued_diff;
536
537 struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
538                                   struct diff_filespec *one,
539                                   struct diff_filespec *two)
540 {
541         struct diff_filepair *dp = xmalloc(sizeof(*dp));
542         dp->one = one;
543         dp->two = two;
544         dp->xfrm_msg = 0;
545         dp->orig_order = queue->nr;
546         dp->xfrm_work = 0;
547         if (queue->alloc <= queue->nr) {
548                 queue->alloc = alloc_nr(queue->alloc);
549                 queue->queue = xrealloc(queue->queue,
550                                        sizeof(dp) * queue->alloc);
551         }
552         queue->queue[queue->nr++] = dp;
553         return dp;
554 }
555
556 static void diff_flush_raw(struct diff_filepair *p)
557 {
558         /*
559          * We used to reject rename/copy but new diff-raw can express them.
560          */
561         printf(":%06o %06o %s ",
562                p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
563         printf("%s%c%s%c%s%c",
564                sha1_to_hex(p->two->sha1), inter_name_termination,
565                p->one->path, inter_name_termination,
566                p->two->path, line_termination);
567 }
568
569 static void diff_flush_patch(struct diff_filepair *p)
570 {
571         const char *name, *other;
572
573         name = p->one->path;
574         other = (strcmp(name, p->two->path) ? p->two->path : NULL);
575         if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
576             (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
577                 return; /* no tree diffs in patch format */ 
578
579         run_external_diff(name, other, p->one, p->two, p->xfrm_msg);
580 }
581
582 static int identical(struct diff_filespec *one, struct diff_filespec *two)
583 {
584         /* This function is written stricter than necessary to support
585          * the currently implemented transformers, but the idea is to
586          * let transformers to produce diff_filepairs any way they want,
587          * and filter and clean them up here before producing the output.
588          */
589
590         if (!DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two))
591                 return 1; /* not interesting */
592
593         /* deletion, addition, mode change and renames are all interesting. */
594         if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
595             (one->mode != two->mode) ||
596             strcmp(one->path, two->path))
597                 return 0;
598
599         /* both are valid and point at the same path.  that is, we are
600          * dealing with a change.
601          */
602         if (one->sha1_valid && two->sha1_valid &&
603             !memcmp(one->sha1, two->sha1, sizeof(one->sha1)))
604                 return 1; /* no change */
605         if (!one->sha1_valid && !two->sha1_valid)
606                 return 1; /* both look at the same file on the filesystem. */
607         return 0;
608 }
609
610 static void diff_flush_one(struct diff_filepair *p)
611 {
612         if (identical(p->one, p->two))
613                 return;
614         if (generate_patch)
615                 diff_flush_patch(p);
616         else
617                 diff_flush_raw(p);
618 }
619
620 int diff_queue_is_empty(void)
621 {
622         struct diff_queue_struct *q = &diff_queued_diff;
623         int i;
624
625         for (i = 0; i < q->nr; i++) {
626                 struct diff_filepair *p = q->queue[i];
627                 if (!identical(p->one, p->two))
628                         return 0;
629         }
630         return 1;
631 }
632
633 void diff_flush(const char **pathspec_, int speccnt_)
634 {
635         struct diff_queue_struct *q = &diff_queued_diff;
636         int i;
637
638         pathspec = pathspec_;
639         speccnt = speccnt_;
640
641         for (i = 0; i < q->nr; i++)
642                 diff_flush_one(q->queue[i]);
643
644         for (i = 0; i < q->nr; i++) {
645                 struct diff_filepair *p = q->queue[i];
646                 diff_free_filespec_data(p->one);
647                 diff_free_filespec_data(p->two);
648                 free(p->xfrm_msg);
649                 free(p);
650         }
651         free(q->queue);
652         q->queue = NULL;
653         q->nr = q->alloc = 0;
654 }
655
656 void diff_addremove(int addremove, unsigned mode,
657                     const unsigned char *sha1,
658                     const char *base, const char *path)
659 {
660         char concatpath[PATH_MAX];
661         struct diff_filespec *one, *two;
662
663         /* This may look odd, but it is a preparation for
664          * feeding "there are unchanged files which should
665          * not produce diffs, but when you are doing copy
666          * detection you would need them, so here they are"
667          * entries to the diff-core.  They will be prefixed
668          * with something like '=' or '*' (I haven't decided
669          * which but should not make any difference).
670          * Feeding the same new and old to diff_change() should
671          * also have the same effect.  diff_flush() should
672          * filter the identical ones out at the final output
673          * stage.
674          */
675         if (reverse_diff)
676                 addremove = (addremove == '+' ? '-' :
677                              addremove == '-' ? '+' : addremove);
678
679         if (!path) path = "";
680         sprintf(concatpath, "%s%s", base, path);
681         one = alloc_filespec(concatpath);
682         two = alloc_filespec(concatpath);
683
684         if (addremove != '+')
685                 fill_filespec(one, sha1, mode);
686         if (addremove != '-')
687                 fill_filespec(two, sha1, mode);
688
689         diff_queue(&diff_queued_diff, one, two);
690 }
691
692 void diff_guif(unsigned old_mode,
693                unsigned new_mode,
694                const unsigned char *old_sha1,
695                const unsigned char *new_sha1,
696                const char *old_path,
697                const char *new_path)
698 {
699         struct diff_filespec *one, *two;
700
701         if (reverse_diff) {
702                 unsigned tmp;
703                 const unsigned char *tmp_c;
704                 tmp = old_mode; old_mode = new_mode; new_mode = tmp;
705                 tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
706         }
707         one = alloc_filespec(old_path);
708         two = alloc_filespec(new_path);
709         if (old_mode)
710                 fill_filespec(one, old_sha1, old_mode);
711         if (new_mode)
712                 fill_filespec(two, new_sha1, new_mode);
713         diff_queue(&diff_queued_diff, one, two);
714 }
715
716 void diff_change(unsigned old_mode, unsigned new_mode,
717                  const unsigned char *old_sha1,
718                  const unsigned char *new_sha1,
719                  const char *base, const char *path) 
720 {
721         char concatpath[PATH_MAX];
722         struct diff_filespec *one, *two;
723
724         if (reverse_diff) {
725                 unsigned tmp;
726                 const unsigned char *tmp_c;
727                 tmp = old_mode; old_mode = new_mode; new_mode = tmp;
728                 tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
729         }
730         if (!path) path = "";
731         sprintf(concatpath, "%s%s", base, path);
732         one = alloc_filespec(concatpath);
733         two = alloc_filespec(concatpath);
734         fill_filespec(one, old_sha1, old_mode);
735         fill_filespec(two, new_sha1, new_mode);
736
737         diff_queue(&diff_queued_diff, one, two);
738 }
739
740 void diff_unmerge(const char *path)
741 {
742         if (generate_patch)
743                 run_external_diff(path, NULL, NULL, NULL, NULL);
744         else
745                 printf("U %s%c", path, line_termination);
746 }