Skip to content

Commit 4130b99

Browse files
Junio C HamanoLinus Torvalds
authored andcommitted
[PATCH] Diff updates to express type changes
With the introduction of type 'T' in the diff-raw output, and the "apply-patch" program Linus has been quietly working on without much advertisement, it started to make sense to emit usable information in the "diff --git" patch output format as well. Earlier built-in diff driver punted and did not say anything about a symbolic link changing into a file or vice versa, but this version represents it as a pair of deletion and creation. It also fixes a minor problem dealing with old archive created with ancient git. The earlier code was reporting file mode change between 100664 and 100644 (we shouldn't). The linux-2.6 git tree has a good example that exposes this problem. A good test case is commit ce1dc02. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
1 parent a577284 commit 4130b99

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

diff.c

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ struct diff_filespec *alloc_filespec(const char *path)
171171
void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
172172
unsigned short mode)
173173
{
174-
if (mode) { /* just playing defensive */
175-
spec->mode = mode;
174+
if (mode) {
175+
spec->mode = DIFF_FILE_CANON_MODE(mode);
176176
memcpy(spec->sha1, sha1, 20);
177177
spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
178178
}
@@ -390,7 +390,8 @@ static void remove_tempfile_on_signal(int signo)
390390
* infile2 infile2-sha1 infile2-mode [ rename-to ]
391391
*
392392
*/
393-
static void run_external_diff(const char *name,
393+
static void run_external_diff(const char *pgm,
394+
const char *name,
394395
const char *other,
395396
struct diff_filespec *one,
396397
struct diff_filespec *two,
@@ -418,7 +419,6 @@ static void run_external_diff(const char *name,
418419
if (pid < 0)
419420
die("unable to fork");
420421
if (!pid) {
421-
const char *pgm = external_diff();
422422
if (pgm) {
423423
if (one && two) {
424424
const char *exec_arg[10];
@@ -468,6 +468,30 @@ static void run_external_diff(const char *name,
468468
remove_tempfile();
469469
}
470470

471+
static void run_diff(const char *name,
472+
const char *other,
473+
struct diff_filespec *one,
474+
struct diff_filespec *two,
475+
const char *xfrm_msg)
476+
{
477+
const char *pgm = external_diff();
478+
if (!pgm &&
479+
DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
480+
(S_IFMT & one->mode) != (S_IFMT & two->mode)) {
481+
/* a filepair that changes between file and symlink
482+
* needs to be split into deletion and creation.
483+
*/
484+
struct diff_filespec *null = alloc_filespec(two->path);
485+
run_external_diff(NULL, name, other, one, null, xfrm_msg);
486+
free(null);
487+
null = alloc_filespec(one->path);
488+
run_external_diff(NULL, name, other, null, two, xfrm_msg);
489+
free(null);
490+
}
491+
else
492+
run_external_diff(pgm, name, other, one, two, xfrm_msg);
493+
}
494+
471495
void diff_setup(int reverse_diff_)
472496
{
473497
reverse_diff = reverse_diff_;
@@ -553,9 +577,11 @@ int diff_unmodified_pair(struct diff_filepair *p)
553577
one = p->one;
554578
two = p->two;
555579

556-
/* deletion, addition, mode change and renames are all interesting. */
580+
/* deletion, addition, mode or type change
581+
* and rename are all interesting.
582+
*/
557583
if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
558-
(one->mode != two->mode) ||
584+
DIFF_PAIR_MODE_CHANGED(p) ||
559585
strcmp(one->path, two->path))
560586
return 0;
561587

@@ -608,9 +634,9 @@ static void diff_flush_patch(struct diff_filepair *p)
608634
}
609635

610636
if (DIFF_PAIR_UNMERGED(p))
611-
run_external_diff(name, NULL, NULL, NULL, NULL);
637+
run_diff(name, NULL, NULL, NULL, NULL);
612638
else
613-
run_external_diff(name, other, p->one, p->two, msg);
639+
run_diff(name, other, p->one, p->two, msg);
614640
}
615641

616642
int diff_needs_to_stay(struct diff_queue_struct *q, int i,
@@ -775,7 +801,8 @@ void diff_flush(int diff_output_style, int resolve_rename_copy)
775801

776802
for (i = 0; i < q->nr; i++) {
777803
struct diff_filepair *p = q->queue[i];
778-
if (p->status == 'X')
804+
if ((diff_output_style == DIFF_FORMAT_NO_OUTPUT) ||
805+
(p->status == 'X'))
779806
continue;
780807
if (p->status == 0)
781808
die("internal error in diff-resolve-rename-copy");

diffcore.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ struct diff_filepair {
4848
#define DIFF_PAIR_TYPE_CHANGED(p) \
4949
((S_IFMT & (p)->one->mode) != (S_IFMT & (p)->two->mode))
5050

51+
#define DIFF_PAIR_MODE_CHANGED(p) ((p)->one->mode != (p)->two->mode)
52+
53+
#define DIFF_FILE_CANON_MODE(mode) \
54+
(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
55+
S_ISLNK(mode) ? S_IFLNK : S_IFDIR)
56+
5157
extern int diff_unmodified_pair(struct diff_filepair *);
5258

5359
struct diff_queue_struct {

0 commit comments

Comments
 (0)