diff -c -p: do not die on submodules
The combine diff logic knew only about blobs (and their checked-out form in the work tree, either regular files or symlinks), and barfed when fed submodules. This "externalizes" gitlinks in the same way as the normal patch generation codepath does (i.e. "Subproject commit Xxx\n") to fix the issue. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Apr 29, 2009 at 12:49 UTC
7dae8b21c2fe39a59661c709f0dc17090dafa5a4
2 files changed
+65
-12
combine-diff.c
+26
-12
@@ -6,6 +6,7 @@
6
#include "quote.h"
7
#include "xdiff-interface.h"
8
#include "log-tree.h"
9
+#include "refs.h"
10
11
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
12
{
@@ -90,18 +91,24 @@ struct sline {
91
unsigned long *p_lno;
92
};
93
93
-static char *grab_blob(const unsigned char *sha1, unsigned long *size)
94
+static char *grab_blob(const unsigned char *sha1, unsigned int mode, unsigned long *size)
95
{
96
char *blob;
97
enum object_type type;
97
- if (is_null_sha1(sha1)) {
98
+
99
+ if (S_ISGITLINK(mode)) {
100
+ blob = xmalloc(100);
101
+ *size = snprintf(blob, 100,
102
+ "Subproject commit %s\n", sha1_to_hex(sha1));
103
+ } else if (is_null_sha1(sha1)) {
104
/* deleted blob */
105
*size = 0;
106
return xcalloc(1, 1);
107
+ } else {
108
+ blob = read_sha1_file(sha1, &type, size);
109
+ if (type != OBJ_BLOB)
110
+ die("object '%s' is not a blob!", sha1_to_hex(sha1));
111
}
102
- blob = read_sha1_file(sha1, &type, size);
103
- if (type != OBJ_BLOB)
104
- die("object '%s' is not a blob!", sha1_to_hex(sha1));
112
return blob;
113
}
114
@@ -197,7 +204,8 @@ static void consume_line(void *state_, char *line, unsigned long len)
204
}
205
}
206
200
-static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
207
+static void combine_diff(const unsigned char *parent, unsigned int mode,
208
+ mmfile_t *result_file,
209
struct sline *sline, unsigned int cnt, int n,
210
int num_parent)
211
{
@@ -213,7 +221,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
221
if (!cnt)
222
return; /* result deleted */
223
216
- parent_file.ptr = grab_blob(parent, &sz);
224
+ parent_file.ptr = grab_blob(parent, mode, &sz);
225
parent_file.size = sz;
226
xpp.flags = XDF_NEED_MINIMAL;
227
memset(&xecfg, 0, sizeof(xecfg));
@@ -692,7 +700,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
700
context = opt->context;
701
/* Read the result of merge first */
702
if (!working_tree_file)
695
- result = grab_blob(elem->sha1, &result_size);
703
+ result = grab_blob(elem->sha1, elem->mode, &result_size);
704
else {
705
/* Used by diff-tree to read from the working tree */
706
struct stat st;
@@ -712,9 +720,13 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
720
}
721
result[len] = 0;
722
elem->mode = canon_mode(st.st_mode);
715
- }
716
- else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
717
- !fstat(fd, &st)) {
723
+ } else if (S_ISDIR(st.st_mode)) {
724
+ unsigned char sha1[20];
725
+ if (resolve_gitlink_ref(elem->path, "HEAD", sha1) < 0)
726
+ result = grab_blob(elem->sha1, elem->mode, &result_size);
727
+ else
728
+ result = grab_blob(sha1, elem->mode, &result_size);
729
+ } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
730
size_t len = xsize_t(st.st_size);
731
ssize_t done;
732
int is_file, i;
@@ -807,7 +819,9 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
819
}
820
}
821
if (i <= j)
810
- combine_diff(elem->parent[i].sha1, &result_file, sline,
822
+ combine_diff(elem->parent[i].sha1,
823
+ elem->parent[i].mode,
824
+ &result_file, sline,
825
cnt, i, num_parent);
826
if (elem->parent[i].mode != elem->mode)
827
mode_differs = 1;
t/t4027-diff-submodule.sh
+39
@@ -57,4 +57,43 @@ test_expect_success 'git diff (empty submodule dir)' '
57
test_cmp empty actual.empty
58
'
59
60
+test_expect_success 'conflicted submodule setup' '
61
+
62
+ # 39 efs
63
+ c=fffffffffffffffffffffffffffffffffffffff
64
+ (
65
+ echo "000000 $_z40 0 sub"
66
+ echo "160000 1$c 1 sub"
67
+ echo "160000 2$c 2 sub"
68
+ echo "160000 3$c 3 sub"
69
+ ) | git update-index --index-info &&
70
+ echo >expect.nosub '\''diff --cc sub
71
+index 2ffffff,3ffffff..0000000
72
+--- a/sub
73
++++ b/sub
74
+@@@ -1,1 -1,1 +1,1 @@@
75
+- Subproject commit 2fffffffffffffffffffffffffffffffffffffff
76
+ -Subproject commit 3fffffffffffffffffffffffffffffffffffffff
77
+++Subproject commit 0000000000000000000000000000000000000000'\'' &&
78
+
79
+ hh=$(git rev-parse HEAD) &&
80
+ sed -e "s/$_z40/$hh/" expect.nosub >expect.withsub
81
+
82
+'
83
+
84
+test_expect_success 'combined (empty submodule)' '
85
+ rm -fr sub && mkdir sub &&
86
+ git diff >actual &&
87
+ test_cmp expect.nosub actual
88
+'
89
+
90
+test_expect_success 'combined (with submodule)' '
91
+ rm -fr sub &&
92
+ git clone --no-checkout . sub &&
93
+ git diff >actual &&
94
+ test_cmp expect.withsub actual
95
+'
96
+
97
+
98
+
99
test_done