Commit 543864b677704845660085d2b2b2249cabb084a4

Russell Belfer 2012-10-08T15:21:47

Merge pull request #940 from scunz/diff_sm Diff: Show submodule diff

diff --git a/src/diff.c b/src/diff.c
index 77cbc3c..7a0051a 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -448,7 +448,11 @@ static int oid_for_workdir_item(
 		return -1;
 
 	/* calculate OID for file if possible*/
-	if (S_ISLNK(item->mode))
+	if (S_ISGITLINK(item->mode)) {
+		/* Don't bother to figure out an oid for a submodule. We won't use it anyway. */
+		memset(oid, 0, sizeof(*oid));
+		result = 0;
+	} else if (S_ISLNK(item->mode))
 		result = git_odb__hashlink(oid, full_path.ptr);
 	else if (!git__is_sizet(item->file_size)) {
 		giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
@@ -561,8 +565,11 @@ static int maybe_modified(
 			else if (git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
 				status = GIT_DELTA_UNMODIFIED;
 			else {
-				/* TODO: support other GIT_SUBMODULE_IGNORE values */
-				status = GIT_DELTA_UNMODIFIED;
+				unsigned int sm_status = 0;
+				if (git_submodule_status(&sm_status, sub) < 0)
+					return -1;
+				status = GIT_SUBMODULE_STATUS_IS_UNMODIFIED(sm_status)
+						 ? GIT_DELTA_UNMODIFIED : GIT_DELTA_MODIFIED;
 			}
 		}
 	}
diff --git a/src/diff_output.c b/src/diff_output.c
index 8a099a4..f5f6c38 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -7,6 +7,7 @@
 #include "common.h"
 #include "git2/attr.h"
 #include "git2/oid.h"
+#include "git2/submodule.h"
 #include "diff_output.h"
 #include <ctype.h>
 #include "fileops.h"
@@ -212,6 +213,22 @@ static int get_blob_content(
 	if (git_oid_iszero(&file->oid))
 		return 0;
 
+	if (file->mode == GIT_FILEMODE_COMMIT)
+	{
+		char oidstr[GIT_OID_HEXSZ+1];
+		git_buf content = GIT_BUF_INIT;
+
+		git_oid_fmt(oidstr, &file->oid);
+		oidstr[GIT_OID_HEXSZ] = 0;
+		git_buf_printf(&content, "Subproject commit %s\n", oidstr );
+
+		map->data = git_buf_detach(&content);
+		map->len = strlen(map->data);
+
+		file->flags |= GIT_DIFF_FILE_FREE_DATA;
+		return 0;
+	}
+
 	if (!file->size) {
 		git_odb *odb;
 		size_t len;
@@ -250,6 +267,47 @@ static int get_blob_content(
 	return diff_delta_is_binary_by_content(ctxt, delta, file, map);
 }
 
+static int get_workdir_sm_content(
+	diff_context *ctxt,
+	git_diff_file *file,
+	git_map *map)
+{
+	int error = 0;
+	git_buf content = GIT_BUF_INIT;
+	git_submodule* sm = NULL;
+	const git_oid* sm_head = NULL;
+	unsigned int sm_status = 0;
+	const char* sm_status_text = "";
+	char oidstr[GIT_OID_HEXSZ+1];
+
+	if ((error = git_submodule_lookup(&sm, ctxt->repo, file->path)) < 0) {
+		return error;
+	}
+
+	if ((sm_head = git_submodule_head_oid(sm)) == NULL) {
+		giterr_set(GITERR_SUBMODULE, "Cannot find head of submodule '%s'", file->path);
+		return -1;
+	}
+
+	if ((error = git_submodule_status(&sm_status, sm)) < 0) {
+		return -1;
+	}
+	if (!GIT_SUBMODULE_STATUS_IS_UNMODIFIED(sm_status)) {
+		sm_status_text = "-dirty";
+	}
+
+	git_oid_fmt(oidstr, sm_head);
+	oidstr[GIT_OID_HEXSZ] = 0;
+	git_buf_printf(&content, "Subproject commit %s%s\n", oidstr, sm_status_text );
+
+	map->data = git_buf_detach(&content);
+	map->len = strlen(map->data);
+
+	file->flags |= GIT_DIFF_FILE_FREE_DATA;
+
+	return 0;
+}
+
 static int get_workdir_content(
 	diff_context *ctxt,
 	git_diff_delta *delta,
@@ -260,6 +318,9 @@ static int get_workdir_content(
 	git_buf path = GIT_BUF_INIT;
 	const char *wd = git_repository_workdir(ctxt->repo);
 
+	if (file->mode == GIT_FILEMODE_COMMIT)
+		return get_workdir_sm_content(ctxt, file, map);
+
 	if (git_buf_joinpath(&path, wd, file->path) < 0)
 		return -1;
 
@@ -1038,14 +1099,14 @@ static int print_patch_file(
 	if (git_buf_oom(pi->buf))
 		return -1;
 
-    if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+	if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
 	{
 		giterr_clear();
 		return GIT_EUSER;
 	}
 
-    if (delta->binary != 1)
-        return 0;
+	if (delta->binary != 1)
+		return 0;
 
 	git_buf_clear(pi->buf);
 	git_buf_printf(