#include "diff.h"
#include "commit.h"
#include "revision.h"
+#include "run-command.h"
+#include "diffcore.h"
-int add_submodule_odb(const char *path)
+static int add_submodule_odb(const char *path)
{
struct strbuf objects_directory = STRBUF_INIT;
struct alternate_object_database *alt_odb;
+ int ret = 0;
+ const char *git_dir;
- strbuf_addf(&objects_directory, "%s/.git/objects/", path);
- if (!is_directory(objects_directory.buf))
- return -1;
-
+ strbuf_addf(&objects_directory, "%s/.git", path);
+ git_dir = read_gitfile_gently(objects_directory.buf);
+ if (git_dir) {
+ strbuf_reset(&objects_directory);
+ strbuf_addstr(&objects_directory, git_dir);
+ }
+ strbuf_addstr(&objects_directory, "/objects/");
+ if (!is_directory(objects_directory.buf)) {
+ ret = -1;
+ goto done;
+ }
/* avoid adding it twice */
for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
if (alt_odb->name - alt_odb->base == objects_directory.len &&
!strncmp(alt_odb->base, objects_directory.buf,
objects_directory.len))
- return 0;
+ goto done;
alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
alt_odb->next = alt_odb_list;
alt_odb->name[41] = '\0';
alt_odb_list = alt_odb;
prepare_alt_odb();
- return 0;
+done:
+ strbuf_release(&objects_directory);
+ return ret;
+}
+
+void handle_ignore_submodules_arg(struct diff_options *diffopt,
+ const char *arg)
+{
+ if (!strcmp(arg, "all"))
+ DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
+ else if (!strcmp(arg, "untracked"))
+ DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
+ else if (!strcmp(arg, "dirty"))
+ DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);
+ else
+ die("bad --ignore-submodules argument: %s", arg);
}
void show_submodule_summary(FILE *f, const char *path,
unsigned char one[20], unsigned char two[20],
+ unsigned dirty_submodule,
const char *del, const char *add, const char *reset)
{
struct rev_info rev;
message = "(revision walker failed)";
}
+ if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
+ fprintf(f, "Submodule %s contains untracked content\n", path);
+ if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
+ fprintf(f, "Submodule %s contains modified content\n", path);
+
+ if (!hashcmp(one, two)) {
+ strbuf_release(&sb);
+ return;
+ }
+
strbuf_addf(&sb, "Submodule %s %s..", path,
find_unique_abbrev(one, DEFAULT_ABBREV));
if (!fast_backward && !fast_forward)
}
strbuf_release(&sb);
}
+
+unsigned is_submodule_modified(const char *path, int ignore_untracked)
+{
+ ssize_t len;
+ struct child_process cp;
+ const char *argv[] = {
+ "status",
+ "--porcelain",
+ NULL,
+ NULL,
+ };
+ struct strbuf buf = STRBUF_INIT;
+ unsigned dirty_submodule = 0;
+ const char *line, *next_line;
+ const char *git_dir;
+
+ strbuf_addf(&buf, "%s/.git", path);
+ git_dir = read_gitfile_gently(buf.buf);
+ if (!git_dir)
+ git_dir = buf.buf;
+ if (!is_directory(git_dir)) {
+ strbuf_release(&buf);
+ /* The submodule is not checked out, so it is not modified */
+ return 0;
+
+ }
+ strbuf_reset(&buf);
+
+ if (ignore_untracked)
+ argv[2] = "-uno";
+
+ memset(&cp, 0, sizeof(cp));
+ cp.argv = argv;
+ cp.env = local_repo_env;
+ cp.git_cmd = 1;
+ cp.no_stdin = 1;
+ cp.out = -1;
+ cp.dir = path;
+ if (start_command(&cp))
+ die("Could not run git status --porcelain");
+
+ len = strbuf_read(&buf, cp.out, 1024);
+ line = buf.buf;
+ while (len > 2) {
+ if ((line[0] == '?') && (line[1] == '?')) {
+ dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
+ if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
+ break;
+ } else {
+ dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
+ if (ignore_untracked ||
+ (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED))
+ break;
+ }
+ next_line = strchr(line, '\n');
+ if (!next_line)
+ break;
+ next_line++;
+ len -= (next_line - line);
+ line = next_line;
+ }
+ close(cp.out);
+
+ if (finish_command(&cp))
+ die("git status --porcelain failed");
+
+ strbuf_release(&buf);
+ return dirty_submodule;
+}