summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/checkout.h16
-rw-r--r--src/attr_file.c12
-rw-r--r--src/hash.h2
-rw-r--r--src/hash/hash_win32.c15
-rw-r--r--src/hash/hash_win32.h15
-rw-r--r--src/util.c29
-rw-r--r--src/util.h5
-rw-r--r--src/xdiff/xdiffi.c2
-rw-r--r--tests/attr/ignore.c25
9 files changed, 70 insertions, 51 deletions
diff --git a/include/git2/checkout.h b/include/git2/checkout.h
index 3fb3fc127..e49111c5d 100644
--- a/include/git2/checkout.h
+++ b/include/git2/checkout.h
@@ -106,10 +106,22 @@ GIT_BEGIN_DECL
typedef enum {
GIT_CHECKOUT_NONE = 0, /**< default is a dry run, no actual updates */
- /** Allow safe updates that cannot overwrite uncommitted data */
+ /**
+ * Allow safe updates that cannot overwrite uncommitted data.
+ * If the uncommitted changes don't conflict with the checked out files,
+ * the checkout will still proceed, leaving the changes intact.
+ *
+ * Mutually exclusive with GIT_CHECKOUT_FORCE.
+ * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE.
+ */
GIT_CHECKOUT_SAFE = (1u << 0),
- /** Allow all updates to force working directory to look like index */
+ /**
+ * Allow all updates to force working directory to look like index.
+ *
+ * Mutually exclusive with GIT_CHECKOUT_SAFE.
+ * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE.
+ */
GIT_CHECKOUT_FORCE = (1u << 1),
diff --git a/src/attr_file.c b/src/attr_file.c
index 40c72ea04..8619647a3 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -429,18 +429,6 @@ bool git_attr_fnmatch__match(
return (p_fnmatch(match->pattern, relpath, flags) != FNM_NOMATCH);
}
- /* if path is a directory prefix of a negated pattern, then match */
- if ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) && path->is_dir) {
- size_t pathlen = strlen(relpath);
- bool prefixed = (pathlen <= match->length) &&
- ((match->flags & GIT_ATTR_FNMATCH_ICASE) ?
- !strncasecmp(match->pattern, relpath, pathlen) :
- !strncmp(match->pattern, relpath, pathlen));
-
- if (prefixed && git_path_at_end_of_segment(&match->pattern[pathlen]))
- return true;
- }
-
return (p_fnmatch(match->pattern, filename, flags) != FNM_NOMATCH);
}
diff --git a/src/hash.h b/src/hash.h
index 0502e352e..bd3e3b5de 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -31,8 +31,6 @@ void git_hash_ctx_cleanup(git_hash_ctx *ctx);
# include "hash/hash_generic.h"
#endif
-int git_hash_global_init(void);
-
typedef struct {
void *data;
size_t len;
diff --git a/src/hash/hash_win32.c b/src/hash/hash_win32.c
index 4b6830358..792298f39 100644
--- a/src/hash/hash_win32.c
+++ b/src/hash/hash_win32.c
@@ -109,21 +109,6 @@ static void git_hash_global_shutdown(void)
hash_cryptoapi_prov_shutdown();
}
-int git_hash_global_init(void)
-{
- int error = 0;
-
- if (hash_prov.type != INVALID)
- return 0;
-
- if ((error = hash_cng_prov_init()) < 0)
- error = hash_cryptoapi_prov_init();
-
- git__on_shutdown(git_hash_global_shutdown);
-
- return error;
-}
-
/* CryptoAPI: available in Windows XP and newer */
GIT_INLINE(int) hash_ctx_cryptoapi_init(git_hash_ctx *ctx)
diff --git a/src/hash/hash_win32.h b/src/hash/hash_win32.h
index 9704204e2..6cddcaa72 100644
--- a/src/hash/hash_win32.h
+++ b/src/hash/hash_win32.h
@@ -138,4 +138,19 @@ struct git_hash_ctx {
} ctx;
};
+GIT_INLINE(int) git_hash_global_init(void)
+{
+ int error = 0;
+
+ if (hash_prov.type != INVALID)
+ return 0;
+
+ if ((error = hash_cng_prov_init()) < 0)
+ error = hash_cryptoapi_prov_init();
+
+ git__on_shutdown(git_hash_global_shutdown);
+
+ return error;
+}
+
#endif
diff --git a/src/util.c b/src/util.c
index a49269b98..508dce504 100644
--- a/src/util.c
+++ b/src/util.c
@@ -204,13 +204,6 @@ int git__strntol32(int32_t *result, const char *nptr, size_t nptr_len, const cha
return error;
}
-int git__strcmp(const char *a, const char *b)
-{
- while (*a && *b && *a == *b)
- ++a, ++b;
- return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b);
-}
-
int git__strcasecmp(const char *a, const char *b)
{
while (*a && *b && git__tolower(*a) == git__tolower(*b))
@@ -240,15 +233,6 @@ int git__strcasesort_cmp(const char *a, const char *b)
return cmp;
}
-int git__strncmp(const char *a, const char *b, size_t sz)
-{
- while (sz && *a && *b && *a == *b)
- --sz, ++a, ++b;
- if (!sz)
- return 0;
- return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b);
-}
-
int git__strncasecmp(const char *a, const char *b, size_t sz)
{
int al, bl;
@@ -301,7 +285,18 @@ GIT_INLINE(int) prefixcmp(const char *str, size_t str_n, const char *prefix, boo
int git__prefixcmp(const char *str, const char *prefix)
{
- return prefixcmp(str, SIZE_MAX, prefix, false);
+ unsigned char s, p;
+
+ while (1) {
+ p = *prefix++;
+ s = *str++;
+
+ if (!p)
+ return 0;
+
+ if (s != p)
+ return s - p;
+ }
}
int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
diff --git a/src/util.h b/src/util.h
index 4314295f1..d4fe6eee7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -150,12 +150,13 @@ extern int git__bsearch_r(
void *payload,
size_t *position);
+#define git__strcmp strcmp
+#define git__strncmp strncmp
+
extern int git__strcmp_cb(const void *a, const void *b);
extern int git__strcasecmp_cb(const void *a, const void *b);
-extern int git__strcmp(const char *a, const char *b);
extern int git__strcasecmp(const char *a, const char *b);
-extern int git__strncmp(const char *a, const char *b, size_t sz);
extern int git__strncasecmp(const char *a, const char *b, size_t sz);
extern int git__strcasesort_cmp(const char *a, const char *b);
diff --git a/src/xdiff/xdiffi.c b/src/xdiff/xdiffi.c
index 9a7f53808..916295b44 100644
--- a/src/xdiff/xdiffi.c
+++ b/src/xdiff/xdiffi.c
@@ -36,7 +36,7 @@
#elif defined(__GNUC__)
# define XDL_INLINE(type) static __inline__ type
#else
-#define XDG_INLINE(type) static type
+# define XDL_INLINE(type) static type
#endif
typedef struct s_xdpsplit {
diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c
index 165e2ba09..110304a81 100644
--- a/tests/attr/ignore.c
+++ b/tests/attr/ignore.c
@@ -372,3 +372,28 @@ void test_attr_ignore__case_sensitive_unignore_does_nothing(void)
assert_is_ignored(true, "case/file");
}
+
+void test_attr_ignore__ignored_subdirfiles_with_subdir_rule(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "dir/*\n"
+ "!dir/sub1/sub2/**\n");
+
+ assert_is_ignored(true, "dir/a.test");
+ assert_is_ignored(true, "dir/sub1/a.test");
+ assert_is_ignored(true, "dir/sub1/sub2");
+}
+
+void test_attr_ignore__ignored_subdirfiles_with_negations(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "dir/*\n"
+ "!dir/a.test\n");
+
+ assert_is_ignored(false, "dir/a.test");
+ assert_is_ignored(true, "dir/b.test");
+ assert_is_ignored(true, "dir/sub1/c.test");
+}
+