Merge branch 'jl/submodule-diff'
authorJunio C Hamano <gitster@pobox.com>
Sat, 23 Jan 2010 00:08:10 +0000 (16:08 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 23 Jan 2010 00:08:10 +0000 (16:08 -0800)
* jl/submodule-diff:
Performance optimization for detection of modified submodules
git status: Show uncommitted submodule changes too when enabled
Teach diff that modified submodule directory is dirty
Show submodules as modified when they contain a dirty work tree

1  2 
diff.c
revision.c
submodule.c
wt-status.c
diff --combined diff.c
index 5d713145879d88339a3ea6bef207129f3cac3fef,8986873c0e9b1cd949a11dd1e59a85df080520d3..160dbfd7186ebaa34764a40dc7ba7d2338244a73
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -2029,9 -2029,14 +2029,14 @@@ static int populate_from_stdin(struct d
  static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
  {
        int len;
-       char *data = xmalloc(100);
+       char *data = xmalloc(100), *dirty = "";
+       /* Are we looking at the work tree? */
+       if (!s->sha1_valid && s->dirty_submodule)
+               dirty = "-dirty";
        len = snprintf(data, 100,
-               "Subproject commit %s\n", sha1_to_hex(s->sha1));
+                      "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty);
        s->data = data;
        s->size = len;
        s->should_free = 1;
@@@ -2294,7 -2299,7 +2299,7 @@@ static void run_external_diff(const cha
        }
        *arg = NULL;
        fflush(NULL);
 -      retval = run_command_v_opt(spawn_arg, 0);
 +      retval = run_command_v_opt(spawn_arg, RUN_USING_SHELL);
        remove_tempfile();
        if (retval) {
                fprintf(stderr, "external diff died, stopping at %s.\n", name);
@@@ -3714,7 -3719,7 +3719,7 @@@ int diff_result_code(struct diff_option
  void diff_addremove(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
-                   const char *concatpath)
+                   const char *concatpath, unsigned dirty_submodule)
  {
        struct diff_filespec *one, *two;
  
  
        if (addremove != '+')
                fill_filespec(one, sha1, mode);
-       if (addremove != '-')
+       if (addremove != '-') {
                fill_filespec(two, sha1, mode);
+               two->dirty_submodule = dirty_submodule;
+       }
  
        diff_queue(&diff_queued_diff, one, two);
        if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
@@@ -3758,7 -3765,8 +3765,8 @@@ void diff_change(struct diff_options *o
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
-                const char *concatpath)
+                const char *concatpath,
+                unsigned old_dirty_submodule, unsigned new_dirty_submodule)
  {
        struct diff_filespec *one, *two;
  
                const unsigned char *tmp_c;
                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
                tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
+               tmp = old_dirty_submodule; old_dirty_submodule = new_dirty_submodule;
+                       new_dirty_submodule = tmp;
        }
  
        if (options->prefix &&
        two = alloc_filespec(concatpath);
        fill_filespec(one, old_sha1, old_mode);
        fill_filespec(two, new_sha1, new_mode);
+       one->dirty_submodule = old_dirty_submodule;
+       two->dirty_submodule = new_dirty_submodule;
  
        diff_queue(&diff_queued_diff, one, two);
        if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
@@@ -3818,7 -3830,6 +3830,7 @@@ static char *run_textconv(const char *p
        *arg = NULL;
  
        memset(&child, 0, sizeof(child));
 +      child.use_shell = 1;
        child.argv = argv;
        child.out = -1;
        if (start_command(&child) != 0 ||
diff --combined revision.c
index f3b82d97bc76fbf5cb29373971366723d4467384,769cfd42514a7a6ea4e528d84e8ce8dee8820fe2..4e1a299bfb822caa3eec94baca375de301a4cd73
@@@ -268,7 -268,7 +268,7 @@@ static int tree_difference = REV_TREE_S
  static void file_add_remove(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
-                   const char *fullpath)
+                   const char *fullpath, unsigned dirty_submodule)
  {
        int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD;
  
@@@ -281,7 -281,8 +281,8 @@@ static void file_change(struct diff_opt
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
-                const char *fullpath)
+                const char *fullpath,
+                unsigned old_dirty_submodule, unsigned new_dirty_submodule)
  {
        tree_difference = REV_TREE_DIFFERENT;
        DIFF_OPT_SET(options, HAS_CHANGES);
@@@ -1161,22 -1162,13 +1162,22 @@@ static int handle_revision_opt(struct r
                revs->verbose_header = 1;
        } else if (!strcmp(arg, "--pretty")) {
                revs->verbose_header = 1;
 +              revs->pretty_given = 1;
                get_commit_format(arg+8, revs);
        } else if (!prefixcmp(arg, "--pretty=") || !prefixcmp(arg, "--format=")) {
                revs->verbose_header = 1;
 +              revs->pretty_given = 1;
                get_commit_format(arg+9, revs);
 +      } else if (!strcmp(arg, "--show-notes")) {
 +              revs->show_notes = 1;
 +              revs->show_notes_given = 1;
 +      } else if (!strcmp(arg, "--no-notes")) {
 +              revs->show_notes = 0;
 +              revs->show_notes_given = 1;
        } else if (!strcmp(arg, "--oneline")) {
                revs->verbose_header = 1;
                get_commit_format("oneline", revs);
 +              revs->pretty_given = 1;
                revs->abbrev_commit = 1;
        } else if (!strcmp(arg, "--graph")) {
                revs->topo_order = 1;
diff --combined submodule.c
index 3007f7d5a6279c14a7c29efdc752dbbc41218c76,3f851deb6afad564a786912a7bb4f9069d697ec7..f657bee379a6bc0fc7d6bd263c32e1b7e3e61efc
@@@ -4,8 -4,9 +4,9 @@@
  #include "diff.h"
  #include "commit.h"
  #include "revision.h"
+ #include "run-command.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;
@@@ -112,3 -113,51 +113,51 @@@ void show_submodule_summary(FILE *f, co
        }
        strbuf_release(&sb);
  }
+ int is_submodule_modified(const char *path)
+ {
+       int len;
+       struct child_process cp;
+       const char *argv[] = {
+               "status",
+               "--porcelain",
+               NULL,
+       };
+       char *env[3];
+       struct strbuf buf = STRBUF_INIT;
+       strbuf_addf(&buf, "%s/.git/", path);
+       if (!is_directory(buf.buf)) {
+               strbuf_release(&buf);
+               /* The submodule is not checked out, so it is not modified */
+               return 0;
+       }
+       strbuf_reset(&buf);
+       strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
+       env[0] = strbuf_detach(&buf, NULL);
+       strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
+       env[1] = strbuf_detach(&buf, NULL);
+       env[2] = NULL;
+       memset(&cp, 0, sizeof(cp));
+       cp.argv = argv;
+       cp.env = (const char *const *)env;
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+       cp.out = -1;
+       if (start_command(&cp))
+               die("Could not run git status --porcelain");
+       len = strbuf_read(&buf, cp.out, 1024);
+       close(cp.out);
+       if (finish_command(&cp))
+               die("git status --porcelain failed");
+       free(env[0]);
+       free(env[1]);
+       strbuf_release(&buf);
+       return len != 0;
+ }
diff --combined wt-status.c
index 65feb29f2ee87b85a21907c5087cfcdd6c3be756,deaac93d1784ebe51ff63b25804b6b90acc427b9..5807fc3211a3aa8f886694776fe8c86b5bc5eb59
@@@ -343,7 -343,7 +343,7 @@@ static void wt_status_collect_untracked
                        DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
        setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, NULL);
 +      fill_directory(&dir, s->pathspec);
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
                if (!cache_name_is_other(ent->name, ent->len))
@@@ -459,7 -459,7 +459,7 @@@ static void wt_status_print_changed(str
        wt_status_print_trailer(s);
  }
  
- static void wt_status_print_submodule_summary(struct wt_status *s)
+ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted)
  {
        struct child_process sm_summary;
        char summary_limit[64];
        const char *argv[] = {
                "submodule",
                "summary",
-               "--cached",
+               uncommitted ? "--files" : "--cached",
                "--for-status",
                "--summary-limit",
                summary_limit,
-               s->amend ? "HEAD^" : "HEAD",
+               uncommitted ? NULL : (s->amend ? "HEAD^" : "HEAD"),
                NULL
        };
  
@@@ -580,8 -580,10 +580,10 @@@ void wt_status_print(struct wt_status *
        wt_status_print_updated(s);
        wt_status_print_unmerged(s);
        wt_status_print_changed(s);
-       if (s->submodule_summary)
-               wt_status_print_submodule_summary(s);
+       if (s->submodule_summary) {
+               wt_status_print_submodule_summary(s, 0);  /* staged */
+               wt_status_print_submodule_summary(s, 1);  /* unstaged */
+       }
        if (s->show_untracked_files)
                wt_status_print_untracked(s);
        else if (s->commitable)