From 945c92a5cf1f73d56d0d2f06776f3181ed5b5548 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 31 Mar 2014 12:26:46 -0700 Subject: [PATCH 1/4] Add faster git_submodule__is_submodule check --- src/submodule.c | 15 +++++++++++++++ src/submodule.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/submodule.c b/src/submodule.c index e1500b847..fdcc2251a 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -135,6 +135,21 @@ static int submodule_lookup( * PUBLIC APIS */ +bool git_submodule__is_submodule(git_repository *repo, const char *name) +{ + git_strmap *map; + + if (load_submodule_config(repo, false) < 0) { + giterr_clear(); + return false; + } + + if (!(map = repo->submodules)) + return false; + + return git_strmap_valid_index(map, git_strmap_lookup_index(map, name)); +} + int git_submodule_lookup( git_submodule **out, /* NULL if user only wants to test existence */ git_repository *repo, diff --git a/src/submodule.h b/src/submodule.h index 053cb61e0..8199eb1da 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -119,6 +119,9 @@ enum { #define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \ ((S) & ~(0xFFFFFFFFu << 20)) +/* Internal submodule check does not attempt to refresh cached data */ +bool git_submodule__is_submodule(git_repository *repo, const char *name); + /* Internal status fn returns status and optionally the various OIDs */ extern int git_submodule__status( unsigned int *out_status, From c856f8c503a59ab6c8cc974d467aa2fcf509fd9b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 31 Mar 2014 12:27:05 -0700 Subject: [PATCH 2/4] Fix submodule sorting in workdir iterator With the changes to how git_path_dirload_with_stat handles things that look like submodules, submodules could end up sorted in the wrong order with the workdir iterator. This moves the submodule check earlier in the iterator processing of a new directory so that the submodule name updates will happen immediately and the sort order will be correct. --- src/iterator.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index e9ec65250..1276903a7 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1275,14 +1275,38 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) static int workdir_iterator__enter_dir(fs_iterator *fi) { + fs_iterator_frame *ff = fi->stack; + size_t pos; + git_path_with_stat *entry; + bool found_submodules = false; + /* only push new ignores if this is not top level directory */ - if (fi->stack->next != NULL) { + if (ff->next != NULL) { workdir_iterator *wi = (workdir_iterator *)fi; ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); } + /* convert submodules to GITLINK and remove trailing slashes */ + git_vector_foreach(&ff->entries, pos, entry) { + if (S_ISDIR(entry->st.st_mode) && + git_submodule__is_submodule(fi->base.repo, entry->path)) + { + entry->st.st_mode = GIT_FILEMODE_COMMIT; + entry->path_len--; + entry->path[entry->path_len] = '\0'; + found_submodules = true; + } + } + + /* if we renamed submodules, re-sort and re-seek to start */ + if (found_submodules) { + git_vector_set_sorted(&ff->entries, 0); + git_vector_sort(&ff->entries); + fs_iterator__seek_frame_start(fi, ff); + } + return 0; } @@ -1295,7 +1319,6 @@ static int workdir_iterator__leave_dir(fs_iterator *fi) static int workdir_iterator__update_entry(fs_iterator *fi) { - int error = 0; workdir_iterator *wi = (workdir_iterator *)fi; /* skip over .git entries */ @@ -1305,20 +1328,6 @@ static int workdir_iterator__update_entry(fs_iterator *fi) /* reset is_ignored since we haven't checked yet */ wi->is_ignored = -1; - /* check if apparent tree entries are actually submodules */ - if (fi->entry.mode != GIT_FILEMODE_TREE) - return 0; - - error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path); - if (error < 0) - giterr_clear(); - - /* mark submodule as GITLINK and remove slash */ - if (!error) { - fi->entry.mode = S_IFGITLINK; - fi->entry.path[strlen(fi->entry.path) - 1] = '\0'; - } - return 0; } From 7dcd42a55f5fdc61e8e8de472ec54ccc0613e23c Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 31 Mar 2014 13:31:01 -0700 Subject: [PATCH 3/4] Cleanups --- src/iterator.c | 2 +- src/merge_file.c | 4 ++-- src/submodule.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index 1276903a7..a7a44914c 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -10,7 +10,7 @@ #include "index.h" #include "ignore.h" #include "buffer.h" -#include "git2/submodule.h" +#include "submodule.h" #include #define ITERATOR_SET_CB(P,NAME_LC) do { \ diff --git a/src/merge_file.c b/src/merge_file.c index ab9ca4168..ff0364432 100644 --- a/src/merge_file.c +++ b/src/merge_file.c @@ -117,7 +117,7 @@ static int git_merge_file__from_inputs( memset(out, 0x0, sizeof(git_merge_file_result)); - merge_file_normalize_opts(&options, given_opts); + merge_file_normalize_opts(&options, given_opts); memset(&xmparam, 0x0, sizeof(xmparam_t)); @@ -165,7 +165,7 @@ static int git_merge_file__from_inputs( } out->automergeable = (xdl_result == 0); - out->ptr = (unsigned char *)mmbuffer.ptr; + out->ptr = (const char *)mmbuffer.ptr; out->len = mmbuffer.size; out->mode = merge_file_best_mode(ancestor, ours, theirs); diff --git a/src/submodule.h b/src/submodule.h index 8199eb1da..1c41897e3 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -120,7 +120,7 @@ enum { ((S) & ~(0xFFFFFFFFu << 20)) /* Internal submodule check does not attempt to refresh cached data */ -bool git_submodule__is_submodule(git_repository *repo, const char *name); +extern bool git_submodule__is_submodule(git_repository *repo, const char *name); /* Internal status fn returns status and optionally the various OIDs */ extern int git_submodule__status( From b76b5d34275fe33192358d4eaa1ae98e31efc2a1 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 31 Mar 2014 13:33:11 -0700 Subject: [PATCH 4/4] Improve test of submodule name sorting --- tests/diff/submodules.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/diff/submodules.c b/tests/diff/submodules.c index ead5c71b6..2881f74be 100644 --- a/tests/diff/submodules.c +++ b/tests/diff/submodules.c @@ -182,6 +182,8 @@ void test_diff_submodules__submod2_index_to_wd(void) "", /* not */ "diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */ "diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */ + "", /* sm_changed_head- */ + "", /* sm_changed_head_ */ "diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */ "diff --git a/sm_changed_untracked_file b/sm_changed_untracked_file\nindex 4800958..4800958 160000\n--- a/sm_changed_untracked_file\n+++ b/sm_changed_untracked_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_untracked_file */ "diff --git a/sm_missing_commits b/sm_missing_commits\nindex 4800958..5e49635 160000\n--- a/sm_missing_commits\n+++ b/sm_missing_commits\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 5e4963595a9774b90524d35a807169049de8ccad\n", /* sm_missing_commits */ @@ -190,6 +192,10 @@ void test_diff_submodules__submod2_index_to_wd(void) g_repo = setup_fixture_submod2(); + /* bracket existing submodule with similarly named items */ + cl_git_mkfile("submod2/sm_changed_head-", "hello"); + cl_git_mkfile("submod2/sm_changed_head_", "hello"); + opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; opts.old_prefix = "a"; opts.new_prefix = "b";