Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 22b6b82

Browse files
committed
Add status flags to force output sort order
Files in status will, be default, be sorted according to the case insensitivity of the filesystem that we're running on. However, in some cases, this is not desirable. Even on case insensitive file systems, 'git status' at the command line will generally use a case sensitive sort (like 'ls'). Some GUIs prefer to display a list of file case insensitively even on case-sensitive platforms. This adds two new flags: GIT_STATUS_OPT_SORT_CASE_SENSITIVELY and GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY that will override the default sort order of the status output and give the user control. This includes tests for exercising these new options and makes the examples/status.c program emulate core Git and always use a case sensitive sort.
1 parent cf300bb commit 22b6b82

File tree

11 files changed

+126
-16
lines changed

11 files changed

+126
-16
lines changed

examples/status.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ int main(int argc, char *argv[])
203203

204204
opt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
205205
opt.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
206-
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX;
206+
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
207+
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
207208

208209
for (i = 1; i < argc; ++i) {
209210
if (argv[i][0] != '-') {

include/git2/status.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ typedef enum {
111111
* - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates tha rename
112112
* detection should be run between the index and the working directory
113113
* and enabled GIT_STATUS_WT_RENAMED as a possible status flag.
114+
* - GIT_STATUS_OPT_SORT_CASE_SENSITIVELY overrides the native case
115+
* sensitivity for the file system and forces the output to be in
116+
* case-sensitive order
117+
* - GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY overrides the native case
118+
* sensitivity for the file system and forces the output to be in
119+
* case-insensitive order
114120
*
115121
* Calling `git_status_foreach()` is like calling the extended version
116122
* with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
@@ -127,6 +133,8 @@ typedef enum {
127133
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS = (1u << 6),
128134
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX = (1u << 7),
129135
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR = (1u << 8),
136+
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY = (1u << 9),
137+
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY = (1u << 10),
130138
} git_status_opt_t;
131139

132140
#define GIT_STATUS_OPT_DEFAULTS \

src/attr_file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ int git_attr_assignment__parse(
498498

499499
assert(assigns && !assigns->length);
500500

501-
assigns->_cmp = sort_by_hash_and_name;
501+
git_vector_set_cmp(assigns, sort_by_hash_and_name);
502502

503503
while (*scan && *scan != '\n') {
504504
const char *name_start, *value_start;

src/diff.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ static git_diff_list *diff_list_alloc(
365365
diff->pfxcomp = git__prefixcmp_icase;
366366
diff->entrycomp = git_index_entry__cmp_icase;
367367

368-
diff->deltas._cmp = git_diff_delta__casecmp;
368+
git_vector_set_cmp(&diff->deltas, git_diff_delta__casecmp);
369369
}
370370

371371
return diff;
@@ -1165,7 +1165,7 @@ int git_diff_tree_to_index(
11651165
d->pfxcomp = git__prefixcmp_icase;
11661166
d->entrycomp = git_index_entry__cmp_icase;
11671167

1168-
d->deltas._cmp = git_diff_delta__casecmp;
1168+
git_vector_set_cmp(&d->deltas, git_diff_delta__casecmp);
11691169
git_vector_sort(&d->deltas);
11701170
}
11711171
}
@@ -1266,10 +1266,10 @@ int git_diff__paired_foreach(
12661266
/* force case-sensitive delta sort */
12671267
if (icase_mismatch) {
12681268
if (head2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) {
1269-
head2idx->deltas._cmp = git_diff_delta__cmp;
1269+
git_vector_set_cmp(&head2idx->deltas, git_diff_delta__cmp);
12701270
git_vector_sort(&head2idx->deltas);
12711271
} else {
1272-
idx2wd->deltas._cmp = git_diff_delta__cmp;
1272+
git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__cmp);
12731273
git_vector_sort(&idx2wd->deltas);
12741274
}
12751275
}
@@ -1301,10 +1301,10 @@ int git_diff__paired_foreach(
13011301
/* restore case-insensitive delta sort */
13021302
if (icase_mismatch) {
13031303
if (head2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) {
1304-
head2idx->deltas._cmp = git_diff_delta__casecmp;
1304+
git_vector_set_cmp(&head2idx->deltas, git_diff_delta__casecmp);
13051305
git_vector_sort(&head2idx->deltas);
13061306
} else {
1307-
idx2wd->deltas._cmp = git_diff_delta__casecmp;
1307+
git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__casecmp);
13081308
git_vector_sort(&idx2wd->deltas);
13091309
}
13101310
}

src/index.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -290,16 +290,16 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case)
290290
{
291291
index->ignore_case = ignore_case;
292292

293-
index->entries._cmp = ignore_case ? index_icmp : index_cmp;
294293
index->entries_cmp_path = ignore_case ? index_icmp_path : index_cmp_path;
295294
index->entries_search = ignore_case ? index_isrch : index_srch;
296295
index->entries_search_path = ignore_case ? index_isrch_path : index_srch_path;
297-
index->entries.sorted = 0;
296+
297+
git_vector_set_cmp(&index->entries, ignore_case ? index_icmp : index_cmp);
298298
git_vector_sort(&index->entries);
299299

300-
index->reuc._cmp = ignore_case ? reuc_icmp : reuc_cmp;
301300
index->reuc_search = ignore_case ? reuc_isrch : reuc_srch;
302-
index->reuc.sorted = 0;
301+
302+
git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
303303
git_vector_sort(&index->reuc);
304304
}
305305

@@ -2024,7 +2024,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
20242024

20252025
git_vector_sort(&index->entries);
20262026

2027-
entries._cmp = index->entries._cmp;
2027+
git_vector_set_cmp(&entries, index->entries._cmp);
20282028
git_vector_swap(&entries, &index->entries);
20292029

20302030
git_index_clear(index);

src/status.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,16 @@ int git_status_list_new(
335335
status->head2idx, status->idx2wd, status_collect, status)) < 0)
336336
goto done;
337337

338-
if ((flags & GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX) != 0 ||
339-
(flags & GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR) != 0)
338+
if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY)
339+
git_vector_set_cmp(&status->paired, status_entry_cmp);
340+
if (flags & GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)
341+
git_vector_set_cmp(&status->paired, status_entry_icmp);
342+
343+
if ((flags &
344+
(GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
345+
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR |
346+
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY |
347+
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)) != 0)
340348
git_vector_sort(&status->paired);
341349

342350
done:

src/submodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ int git_submodule_foreach(
151151
int error;
152152
git_submodule *sm;
153153
git_vector seen = GIT_VECTOR_INIT;
154-
seen._cmp = submodule_cmp;
154+
git_vector_set_cmp(&seen, submodule_cmp);
155155

156156
assert(repo && callback);
157157

src/vector.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,13 @@ void git_vector_remove_matching(
7878
int git_vector_resize_to(git_vector *v, size_t new_length);
7979
int git_vector_set(void **old, git_vector *v, size_t position, void *value);
8080

81+
/** Set the comparison function used for sorting the vector */
82+
GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
83+
{
84+
if (cmp != v->_cmp) {
85+
v->_cmp = cmp;
86+
v->sorted = 0;
87+
}
88+
}
89+
8190
#endif

tests-clar/status/status_helpers.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ int cb_status__normal(
66
{
77
status_entry_counts *counts = payload;
88

9+
if (counts->debug)
10+
cb_status__print(path, status_flags, NULL);
11+
912
if (counts->entry_count >= counts->expected_entry_count) {
1013
counts->wrong_status_flags_count++;
1114
goto exit;

tests-clar/status/status_helpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ typedef struct {
88
const unsigned int* expected_statuses;
99
const char** expected_paths;
1010
int expected_entry_count;
11+
bool debug;
1112
} status_entry_counts;
1213

1314
/* cb_status__normal takes payload of "status_entry_counts *" */

tests-clar/status/worktree.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,3 +743,83 @@ void test_status_worktree__simple_delete_indexed(void)
743743
GIT_STATUS_WT_DELETED, git_status_byindex(status, 0)->status);
744744
git_status_list_free(status);
745745
}
746+
747+
static const char *icase_paths[] = { "B", "c", "g", "H" };
748+
static unsigned int icase_statuses[] = {
749+
GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED,
750+
GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED,
751+
};
752+
753+
static const char *case_paths[] = { "B", "H", "c", "g" };
754+
static unsigned int case_statuses[] = {
755+
GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED,
756+
GIT_STATUS_WT_DELETED, GIT_STATUS_WT_MODIFIED,
757+
};
758+
759+
void test_status_worktree__sorting_by_case(void)
760+
{
761+
git_repository *repo = cl_git_sandbox_init("icase");
762+
git_index *index;
763+
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
764+
bool native_ignore_case;
765+
status_entry_counts counts;
766+
767+
cl_git_pass(git_repository_index(&index, repo));
768+
native_ignore_case =
769+
(git_index_caps(index) & GIT_INDEXCAP_IGNORE_CASE) != 0;
770+
git_index_free(index);
771+
772+
memset(&counts, 0, sizeof(counts));
773+
counts.expected_entry_count = 0;
774+
counts.expected_paths = NULL;
775+
counts.expected_statuses = NULL;
776+
cl_git_pass(
777+
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
778+
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
779+
cl_assert_equal_i(0, counts.wrong_status_flags_count);
780+
cl_assert_equal_i(0, counts.wrong_sorted_path);
781+
782+
cl_git_rewritefile("icase/B", "new stuff");
783+
cl_must_pass(p_unlink("icase/c"));
784+
cl_git_rewritefile("icase/g", "new stuff");
785+
cl_must_pass(p_unlink("icase/H"));
786+
787+
memset(&counts, 0, sizeof(counts));
788+
counts.expected_entry_count = 4;
789+
if (native_ignore_case) {
790+
counts.expected_paths = icase_paths;
791+
counts.expected_statuses = icase_statuses;
792+
} else {
793+
counts.expected_paths = case_paths;
794+
counts.expected_statuses = case_statuses;
795+
}
796+
cl_git_pass(
797+
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
798+
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
799+
cl_assert_equal_i(0, counts.wrong_status_flags_count);
800+
cl_assert_equal_i(0, counts.wrong_sorted_path);
801+
802+
opts.flags = GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
803+
804+
memset(&counts, 0, sizeof(counts));
805+
counts.expected_entry_count = 4;
806+
counts.expected_paths = case_paths;
807+
counts.expected_statuses = case_statuses;
808+
cl_git_pass(
809+
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
810+
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
811+
cl_assert_equal_i(0, counts.wrong_status_flags_count);
812+
cl_assert_equal_i(0, counts.wrong_sorted_path);
813+
814+
opts.flags = GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY;
815+
816+
memset(&counts, 0, sizeof(counts));
817+
counts.expected_entry_count = 4;
818+
counts.expected_paths = icase_paths;
819+
counts.expected_statuses = icase_statuses;
820+
cl_git_pass(
821+
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
822+
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
823+
cl_assert_equal_i(0, counts.wrong_status_flags_count);
824+
cl_assert_equal_i(0, counts.wrong_sorted_path);
825+
}

0 commit comments

Comments
 (0)