summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/branch.h4
-rw-r--r--include/git2/object.h11
-rw-r--r--include/git2/refs.h48
-rw-r--r--include/git2/reset.h2
-rw-r--r--src/branch.c28
-rw-r--r--src/object.c51
-rw-r--r--src/refs.c108
-rw-r--r--src/reset.c30
-rw-r--r--src/revwalk.c20
-rw-r--r--src/tag.c17
-rw-r--r--tests-clar/object/peel.c16
-rw-r--r--tests-clar/refs/normalize.c346
-rw-r--r--tests-clar/revwalk/basic.c8
13 files changed, 430 insertions, 259 deletions
diff --git a/include/git2/branch.h b/include/git2/branch.h
index 81105d6e2..bbbdf1c4a 100644
--- a/include/git2/branch.h
+++ b/include/git2/branch.h
@@ -55,8 +55,10 @@ GIT_EXTERN(int) git_branch_create(
/**
* Delete an existing branch reference.
*
- * @param branch A valid reference representing a branch
+ * If the branch is successfully deleted, the passed reference
+ * object will be freed and invalidated.
*
+ * @param branch A valid reference representing a branch
* @return 0 on success, or an error code.
*/
GIT_EXTERN(int) git_branch_delete(git_reference *branch);
diff --git a/include/git2/object.h b/include/git2/object.h
index 722434dec..fd6ae95c1 100644
--- a/include/git2/object.h
+++ b/include/git2/object.h
@@ -168,11 +168,14 @@ GIT_EXTERN(int) git_object_typeisloose(git_otype type);
GIT_EXTERN(size_t) git_object__size(git_otype type);
/**
- * Recursively peel an object until an object of the specified
- * type is met
+ * Recursively peel an object until an object of the specified type is met.
*
- * The retrieved `peeled` object is owned by the repository
- * and should be closed with the `git_object_free` method.
+ * The retrieved `peeled` object is owned by the repository and should be
+ * closed with the `git_object_free` method.
+ *
+ * If you pass `GIT_OBJ_ANY` as the target type, then the object will be
+ * peeled until the type changes (e.g. a tag will be chased until the
+ * referenced object is no longer a tag).
*
* @param peeled Pointer to the peeled git_object
* @param object The object to be processed
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 975da553d..660b48b5f 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -386,6 +386,54 @@ GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
*/
GIT_EXTERN(int) git_reference_is_remote(git_reference *ref);
+enum {
+ GIT_REF_FORMAT_NORMAL = 0,
+
+ /**
+ * Control whether one-level refnames are accepted
+ * (i.e., refnames that do not contain multiple /-separated
+ * components)
+ */
+ GIT_REF_FORMAT_ALLOW_ONELEVEL = (1 << 0),
+
+ /**
+ * Interpret the provided name as a reference pattern for a
+ * refspec (as used with remote repositories). If this option
+ * is enabled, the name is allowed to contain a single * (<star>)
+ * in place of a one full pathname component
+ * (e.g., foo/<star>/bar but not foo/bar<star>).
+ */
+ GIT_REF_FORMAT_REFSPEC_PATTERN = (1 << 1),
+};
+
+/**
+ * Normalize the reference name by removing any leading
+ * slash (/) characters and collapsing runs of adjacent slashes
+ * between name components into a single slash.
+ *
+ * Once normalized, if the reference name is valid, it will be
+ * returned in the user allocated buffer.
+ *
+ * TODO: Implement handling of GIT_REF_FORMAT_REFSPEC_PATTERN
+ *
+ * @param buffer_out The user allocated buffer where the
+ * normalized name will be stored.
+ *
+ * @param buffer_size buffer_out size
+ *
+ * @param name name to be checked.
+ *
+ * @param flags Flags to determine the options to be applied while
+ * checking the validatity of the name.
+ *
+ * @return 0 or an error code.
+ */
+GIT_EXTERN(int) git_reference_normalize_name(
+ char *buffer_out,
+ size_t buffer_size,
+ const char *name,
+ unsigned int flags);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/reset.h b/include/git2/reset.h
index 125178748..cd263fa99 100644
--- a/include/git2/reset.h
+++ b/include/git2/reset.h
@@ -37,7 +37,7 @@ GIT_BEGIN_DECL
*
* @return GIT_SUCCESS or an error code
*/
-GIT_EXTERN(int) git_reset(git_repository *repo, const git_object *target, git_reset_type reset_type);
+GIT_EXTERN(int) git_reset(git_repository *repo, git_object *target, git_reset_type reset_type);
/** @} */
GIT_END_DECL
diff --git a/src/branch.c b/src/branch.c
index da2042740..cd5c10ede 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -63,7 +63,6 @@ int git_branch_create(
const git_object *target,
int force)
{
- git_otype target_type = GIT_OBJ_BAD;
git_object *commit = NULL;
git_reference *branch = NULL;
git_buf canonical_branch_name = GIT_BUF_INIT;
@@ -72,27 +71,8 @@ int git_branch_create(
assert(branch_name && target && ref_out);
assert(git_object_owner(target) == repository);
- target_type = git_object_type(target);
-
- switch (target_type)
- {
- case GIT_OBJ_TAG:
- if (git_tag_peel(&commit, (git_tag *)target) < 0)
- goto cleanup;
-
- if (git_object_type(commit) != GIT_OBJ_COMMIT) {
- create_error_invalid("The given target does not resolve to a commit");
- goto cleanup;
- }
- break;
-
- case GIT_OBJ_COMMIT:
- commit = (git_object *)target;
- break;
-
- default:
- return create_error_invalid("Only git_tag and git_commit objects are valid targets.");
- }
+ if (git_object_peel(&commit, (git_object *)target, GIT_OBJ_COMMIT) < 0)
+ return create_error_invalid("The given target does not resolve to a commit");
if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
goto cleanup;
@@ -105,9 +85,7 @@ int git_branch_create(
error = 0;
cleanup:
- if (target_type == GIT_OBJ_TAG)
- git_object_free(commit);
-
+ git_object_free(commit);
git_buf_free(&canonical_branch_name);
return error;
}
diff --git a/src/object.c b/src/object.c
index 227774047..5130d97ac 100644
--- a/src/object.c
+++ b/src/object.c
@@ -334,6 +334,12 @@ int git_object__resolve_to_type(git_object **obj, git_otype type)
return error;
}
+static int peel_error(int error, const char* msg)
+{
+ giterr_set(GITERR_INVALID, "The given object cannot be peeled - %s", msg);
+ return error;
+}
+
static int dereference_object(git_object **dereferenced, git_object *obj)
{
git_otype type = git_object_type(obj);
@@ -341,48 +347,36 @@ static int dereference_object(git_object **dereferenced, git_object *obj)
switch (type) {
case GIT_OBJ_COMMIT:
return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj);
- break;
case GIT_OBJ_TAG:
return git_tag_target(dereferenced, (git_tag*)obj);
- break;
+
+ case GIT_OBJ_BLOB:
+ return peel_error(GIT_ERROR, "cannot dereference blob");
+
+ case GIT_OBJ_TREE:
+ return peel_error(GIT_ERROR, "cannot dereference tree");
default:
- return GIT_ENOTFOUND;
- break;
+ return peel_error(GIT_ENOTFOUND, "unexpected object type encountered");
}
}
-static int peel_error(int error, const char* msg)
-{
- giterr_set(GITERR_INVALID, "The given object cannot be peeled - %s", msg);
- return error;
-}
-
int git_object_peel(
- git_object **peeled,
- git_object *object,
- git_otype target_type)
+ git_object **peeled,
+ git_object *object,
+ git_otype target_type)
{
git_object *source, *deref = NULL;
- assert(object);
+ assert(object && peeled);
if (git_object_type(object) == target_type)
return git_object__dup(peeled, object);
- if (target_type == GIT_OBJ_BLOB
- || target_type == GIT_OBJ_ANY)
- return peel_error(GIT_EAMBIGUOUS, "Ambiguous target type");
-
- if (git_object_type(object) == GIT_OBJ_BLOB)
- return peel_error(GIT_ERROR, "A blob cannot be dereferenced");
-
source = object;
- while (true) {
- if (dereference_object(&deref, source) < 0)
- goto cleanup;
+ while (!dereference_object(&deref, source)) {
if (source != object)
git_object_free(source);
@@ -392,13 +386,20 @@ int git_object_peel(
return 0;
}
+ if (target_type == GIT_OBJ_ANY &&
+ git_object_type(deref) != git_object_type(object))
+ {
+ *peeled = deref;
+ return 0;
+ }
+
source = deref;
deref = NULL;
}
-cleanup:
if (source != object)
git_object_free(source);
+
git_object_free(deref);
return -1;
}
diff --git a/src/refs.c b/src/refs.c
index f153a30fd..eb8af5863 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -68,11 +68,6 @@ static int reference_path_available(git_repository *repo,
static int reference_delete(git_reference *ref);
static int reference_lookup(git_reference *ref);
-/* name normalization */
-static int normalize_name(char *buffer_out, size_t out_size,
- const char *name, int is_oid_ref);
-
-
void git_reference_free(git_reference *reference)
{
if (reference == NULL)
@@ -1099,9 +1094,12 @@ int git_reference_lookup_resolved(
scan->name = git__calloc(GIT_REFNAME_MAX + 1, sizeof(char));
GITERR_CHECK_ALLOC(scan->name);
- if ((result = normalize_name(scan->name, GIT_REFNAME_MAX, name, 0)) < 0) {
- git_reference_free(scan);
- return result;
+ if ((result = git_reference__normalize_name(
+ scan->name,
+ GIT_REFNAME_MAX,
+ name)) < 0) {
+ git_reference_free(scan);
+ return result;
}
scan->target.symbolic = git__strdup(scan->name);
@@ -1198,8 +1196,11 @@ int git_reference_create_symbolic(
char normalized[GIT_REFNAME_MAX];
git_reference *ref = NULL;
- if (normalize_name(normalized, sizeof(normalized), name, 0) < 0)
- return -1;
+ if (git_reference__normalize_name(
+ normalized,
+ sizeof(normalized),
+ name) < 0)
+ return -1;
if (reference_can_write(repo, normalized, NULL, force) < 0)
return -1;
@@ -1234,8 +1235,11 @@ int git_reference_create_oid(
git_reference *ref = NULL;
char normalized[GIT_REFNAME_MAX];
- if (normalize_name(normalized, sizeof(normalized), name, 1) < 0)
- return -1;
+ if (git_reference__normalize_name_oid(
+ normalized,
+ sizeof(normalized),
+ name) < 0)
+ return -1;
if (reference_can_write(repo, normalized, NULL, force) < 0)
return -1;
@@ -1314,8 +1318,11 @@ int git_reference_set_target(git_reference *ref, const char *target)
return -1;
}
- if (normalize_name(normalized, sizeof(normalized), target, 0))
- return -1;
+ if (git_reference__normalize_name(
+ normalized,
+ sizeof(normalized),
+ target))
+ return -1;
git__free(ref->target.symbolic);
ref->target.symbolic = git__strdup(normalized);
@@ -1327,15 +1334,23 @@ int git_reference_set_target(git_reference *ref, const char *target)
int git_reference_rename(git_reference *ref, const char *new_name, int force)
{
int result;
+ unsigned int normalization_flags;
git_buf aux_path = GIT_BUF_INIT;
char normalized[GIT_REFNAME_MAX];
const char *head_target = NULL;
git_reference *head = NULL;
- if (normalize_name(normalized, sizeof(normalized),
- new_name, ref->flags & GIT_REF_OID) < 0)
- return -1;
+ normalization_flags = ref->flags & GIT_REF_SYMBOLIC ?
+ GIT_REF_FORMAT_ALLOW_ONELEVEL
+ : GIT_REF_FORMAT_NORMAL;
+
+ if (git_reference_normalize_name(
+ normalized,
+ sizeof(normalized),
+ new_name,
+ normalization_flags) < 0)
+ return -1;
if (reference_can_write(ref->owner, normalized, ref->name, force) < 0)
return -1;
@@ -1565,11 +1580,11 @@ static int is_valid_ref_char(char ch)
}
}
-static int normalize_name(
+int git_reference_normalize_name(
char *buffer_out,
- size_t out_size,
+ size_t buffer_size,
const char *name,
- int is_oid_ref)
+ unsigned int flags)
{
const char *name_end, *buffer_out_start;
const char *current;
@@ -1577,12 +1592,17 @@ static int normalize_name(
assert(name && buffer_out);
+ if (flags & GIT_REF_FORMAT_REFSPEC_PATTERN) {
+ giterr_set(GITERR_INVALID, "Unimplemented");
+ return -1;
+ }
+
buffer_out_start = buffer_out;
current = name;
name_end = name + strlen(name);
/* Terminating null byte */
- out_size--;
+ buffer_size--;
/* A refname can not be empty */
if (name_end == name)
@@ -1592,7 +1612,7 @@ static int normalize_name(
if (*(name_end - 1) == '.' || *(name_end - 1) == '/')
goto invalid_name;
- while (current < name_end && out_size) {
+ while (current < name_end && buffer_size > 0) {
if (!is_valid_ref_char(*current))
goto invalid_name;
@@ -1615,19 +1635,29 @@ static int normalize_name(
}
if (*current == '/')
- contains_a_slash = 1;
+ if (buffer_out > buffer_out_start)
+ contains_a_slash = 1;
+ else {
+ current++;
+ continue;
+ }
+
*buffer_out++ = *current++;
- out_size--;
+ buffer_size--;
}
- if (!out_size)
- goto invalid_name;
+ if (current < name_end) {
+ giterr_set(
+ GITERR_REFERENCE,
+ "The provided buffer is too short to hold the normalization of '%s'", name);
+ return GIT_EBUFS;
+ }
/* Object id refname have to contain at least one slash, except
* for HEAD in a detached state or MERGE_HEAD if we're in the
* middle of a merge */
- if (is_oid_ref &&
+ if (!(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL) &&
!contains_a_slash &&
strcmp(name, GIT_HEAD_FILE) != 0 &&
strcmp(name, GIT_MERGE_HEAD_FILE) != 0 &&
@@ -1640,18 +1670,12 @@ static int normalize_name(
*buffer_out = '\0';
- /*
- * For object id references, name has to start with refs/. Again,
- * we need to allow HEAD to be in a detached state.
- */
- if (is_oid_ref && !(git__prefixcmp(buffer_out_start, GIT_REFS_DIR) ||
- strcmp(buffer_out_start, GIT_HEAD_FILE)))
- goto invalid_name;
-
return 0;
invalid_name:
- giterr_set(GITERR_REFERENCE, "The given reference name is not valid");
+ giterr_set(
+ GITERR_REFERENCE,
+ "The given reference name '%s' is not valid", name);
return -1;
}
@@ -1660,7 +1684,11 @@ int git_reference__normalize_name(
size_t out_size,
const char *name)
{
- return normalize_name(buffer_out, out_size, name, 0);
+ return git_reference_normalize_name(
+ buffer_out,
+ out_size,
+ name,
+ GIT_REF_FORMAT_ALLOW_ONELEVEL);
}
int git_reference__normalize_name_oid(
@@ -1668,7 +1696,11 @@ int git_reference__normalize_name_oid(
size_t out_size,
const char *name)
{
- return normalize_name(buffer_out, out_size, name, 1);
+ return git_reference_normalize_name(
+ buffer_out,
+ out_size,
+ name,
+ GIT_REF_FORMAT_NORMAL);
}
#define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC)
diff --git a/src/reset.c b/src/reset.c
index 1379f6442..f9e16f7c6 100644
--- a/src/reset.c
+++ b/src/reset.c
@@ -20,10 +20,9 @@ static int reset_error_invalid(const char *msg)
int git_reset(
git_repository *repo,
- const git_object *target,
+ git_object *target,
git_reset_type reset_type)
{
- git_otype target_type = GIT_OBJ_BAD;
git_object *commit = NULL;
git_index *index = NULL;
git_tree *tree = NULL;
@@ -38,26 +37,9 @@ int git_reset(
if (reset_type == GIT_RESET_MIXED && git_repository_is_bare(repo))
return reset_error_invalid("Mixed reset is not allowed in a bare repository.");
- target_type = git_object_type(target);
-
- switch (target_type)
- {
- case GIT_OBJ_TAG:
- if (git_tag_peel(&commit, (git_tag *)target) < 0)
- goto cleanup;
-
- if (git_object_type(commit) != GIT_OBJ_COMMIT) {
- reset_error_invalid("The given target does not resolve to a commit.");
- goto cleanup;
- }
- break;
-
- case GIT_OBJ_COMMIT:
- commit = (git_object *)target;
- break;
-
- default:
- return reset_error_invalid("Only git_tag and git_commit objects are valid targets.");
+ if (git_object_peel(&commit, target, GIT_OBJ_COMMIT) < 0) {
+ reset_error_invalid("The given target does not resolve to a commit");
+ goto cleanup;
}
//TODO: Check for unmerged entries
@@ -93,9 +75,7 @@ int git_reset(
error = 0;
cleanup:
- if (target_type == GIT_OBJ_TAG)
- git_object_free(commit);
-
+ git_object_free(commit);
git_index_free(index);
git_tree_free(tree);
diff --git a/src/revwalk.c b/src/revwalk.c
index 9dff283f5..8b0e93baf 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -264,12 +264,7 @@ static int commit_parse(git_revwalk *walk, commit_object *commit)
if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0)
return error;
-
- if (obj->raw.type != GIT_OBJ_COMMIT) {
- git_odb_object_free(obj);
- giterr_set(GITERR_INVALID, "Failed to parse commit. Object is no commit object");
- return -1;
- }
+ assert(obj->raw.type == GIT_OBJ_COMMIT);
error = commit_quick_parse(walk, commit, &obj->raw);
git_odb_object_free(obj);
@@ -515,8 +510,21 @@ static int process_commit_parents(git_revwalk *walk, commit_object *commit)
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
{
+ git_object *obj;
+ git_otype type;
commit_object *commit;
+ if (git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY) < 0)
+ return -1;
+
+ type = git_object_type(obj);
+ git_object_free(obj);
+
+ if (type != GIT_OBJ_COMMIT) {
+ giterr_set(GITERR_INVALID, "Object is no commit object");
+ return -1;
+ }
+
commit = commit_lookup(walk, oid);
if (commit == NULL)
return -1; /* error already reported by failed lookup */
diff --git a/src/tag.c b/src/tag.c
index 463619f63..6495d470f 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -445,20 +445,5 @@ int git_tag_list(git_strarray *tag_names, git_repository *repo)
int git_tag_peel(git_object **tag_target, git_tag *tag)
{
- int error;
- git_object *target;
-
- assert(tag_target && tag);
-
- if (git_tag_target(&target, tag) < 0)
- return -1;
-
- if (git_object_type(target) == GIT_OBJ_TAG) {
- error = git_tag_peel(tag_target, (git_tag *)target);
- git_object_free(target);
- return error;
- }
-
- *tag_target = target;
- return 0;
+ return git_object_peel(tag_target, (git_object *)tag, GIT_OBJ_ANY);
}
diff --git a/tests-clar/object/peel.c b/tests-clar/object/peel.c
index f6d2a776f..f4ea1eb0f 100644
--- a/tests-clar/object/peel.c
+++ b/tests-clar/object/peel.c
@@ -65,7 +65,7 @@ void test_object_peel__can_peel_a_commit(void)
void test_object_peel__cannot_peel_a_tree(void)
{
- assert_peel_error(GIT_EAMBIGUOUS, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_BLOB);
+ assert_peel_error(GIT_ERROR, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_BLOB);
}
void test_object_peel__cannot_peel_a_blob(void)
@@ -73,7 +73,17 @@ void test_object_peel__cannot_peel_a_blob(void)
assert_peel_error(GIT_ERROR, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_COMMIT);
}
-void test_object_peel__cannot_target_any_object(void)
+void test_object_peel__target_any_object_for_type_change(void)
{
- assert_peel_error(GIT_EAMBIGUOUS, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_ANY);
+ /* tag to commit */
+ assert_peel("e90810b8df3e80c413d903f631643c716887138d", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_ANY);
+
+ /* commit to tree */
+ assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_ANY);
+
+ /* fail to peel tree */
+ assert_peel_error(GIT_ERROR, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_ANY);
+
+ /* fail to peel blob */
+ assert_peel_error(GIT_ERROR, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_ANY);
}
diff --git a/tests-clar/refs/normalize.c b/tests-clar/refs/normalize.c
index 135d0a9b6..4e80e4b0b 100644
--- a/tests-clar/refs/normalize.c
+++ b/tests-clar/refs/normalize.c
@@ -4,70 +4,111 @@
#include "git2/reflog.h"
#include "reflog.h"
-
// Helpers
-static void ensure_refname_normalized(int is_oid_ref,
+static void ensure_refname_normalized(unsigned int flags,
const char *input_refname,
const char *expected_refname)
{
char buffer_out[GIT_REFNAME_MAX];
- if (is_oid_ref)
- cl_git_pass(git_reference__normalize_name_oid(buffer_out, sizeof(buffer_out), input_refname));
- else
- cl_git_pass(git_reference__normalize_name(buffer_out, sizeof(buffer_out), input_refname));
+ cl_git_pass(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
- if (expected_refname)
- cl_assert(0 == strcmp(buffer_out, expected_refname));
+ cl_assert_equal_i(0, strcmp(buffer_out, expected_refname));
}
-static void ensure_refname_invalid(int is_oid_ref, const char *input_refname)
+static void ensure_refname_invalid(unsigned int flags, const char *input_refname)
{
char buffer_out[GIT_REFNAME_MAX];
- if (is_oid_ref)
- cl_git_fail(git_reference__normalize_name_oid(buffer_out, sizeof(buffer_out), input_refname));
- else
- cl_git_fail(git_reference__normalize_name(buffer_out, sizeof(buffer_out), input_refname));
+ cl_git_fail(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
}
-#define OID_REF 1
-#define SYM_REF 0
-
+void test_refs_normalize__can_normalize_a_direct_reference_name(void)
+{
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/dummy/a", "refs/dummy/a");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/stash", "refs/stash");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/tags/a", "refs/tags/a");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a/b", "refs/heads/a/b");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a./b", "refs/heads/a./b");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "/refs///heads///a", "refs/heads/a");
+}
+void test_refs_normalize__can_normalize_some_specific_one_level_direct_reference_names(void)
+{
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "HEAD", "HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "MERGE_HEAD", "MERGE_HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "FETCH_HEAD", "FETCH_HEAD");
+}
-void test_refs_normalize__direct(void)
+void test_refs_normalize__cannot_normalize_any_direct_reference_name(void)
{
- // normalize a direct (OID) reference name
- ensure_refname_invalid(OID_REF, "a");
- ensure_refname_invalid(OID_REF, "");
- ensure_refname_invalid(OID_REF, "refs/heads/a/");
- ensure_refname_invalid(OID_REF, "refs/heads/a.");
- ensure_refname_invalid(OID_REF, "refs/heads/a.lock");
- ensure_refname_normalized(OID_REF, "refs/dummy/a", NULL);
- ensure_refname_normalized(OID_REF, "refs/stash", NULL);
- ensure_refname_normalized(OID_REF, "refs/tags/a", "refs/tags/a");
- ensure_refname_normalized(OID_REF, "refs/heads/a/b", "refs/heads/a/b");
- ensure_refname_normalized(OID_REF, "refs/heads/a./b", "refs/heads/a./b");
- ensure_refname_invalid(OID_REF, "refs/heads/foo?bar");
- ensure_refname_invalid(OID_REF, "refs/heads\foo");
- ensure_refname_normalized(OID_REF, "refs/heads/v@ation", "refs/heads/v@ation");
- ensure_refname_normalized(OID_REF, "refs///heads///a", "refs/heads/a");
- ensure_refname_invalid(OID_REF, "refs/heads/.a/b");
- ensure_refname_invalid(OID_REF, "refs/heads/foo/../bar");
- ensure_refname_invalid(OID_REF, "refs/heads/foo..bar");
- ensure_refname_invalid(OID_REF, "refs/heads/./foo");
- ensure_refname_invalid(OID_REF, "refs/heads/v@{ation");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "/a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "//a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a/");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a.");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a.lock");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/foo?bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads\foo");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs///heads///a", "refs/heads/a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/.a/b");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/foo/../bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/foo..bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/./foo");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/v@{ation");
}
void test_refs_normalize__symbolic(void)
{
- // normalize a symbolic reference name
- ensure_refname_normalized(SYM_REF, "a", "a");
- ensure_refname_normalized(SYM_REF, "a/b", "a/b");
- ensure_refname_normalized(SYM_REF, "refs///heads///a", "refs/heads/a");
- ensure_refname_invalid(SYM_REF, "");
- ensure_refname_invalid(SYM_REF, "heads\foo");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "heads\foo");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "///");
+
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "a", "a");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "a/b", "a/b");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs///heads///a", "refs/heads/a");
+
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "HEAD", "HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "MERGE_HEAD", "MERGE_HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "FETCH_HEAD", "FETCH_HEAD");
}
/* Ported from JGit, BSD licence.
@@ -77,31 +118,42 @@ void test_refs_normalize__jgit_suite(void)
// tests borrowed from JGit
/* EmptyString */
- ensure_refname_invalid(SYM_REF, "");
- ensure_refname_invalid(SYM_REF, "/");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "/");
/* MustHaveTwoComponents */
- ensure_refname_invalid(OID_REF, "master");
- ensure_refname_normalized(SYM_REF, "heads/master", "heads/master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "master");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "heads/master", "heads/master");
/* ValidHead */
- ensure_refname_normalized(SYM_REF, "refs/heads/master", "refs/heads/master");
- ensure_refname_normalized(SYM_REF, "refs/heads/pu", "refs/heads/pu");
- ensure_refname_normalized(SYM_REF, "refs/heads/z", "refs/heads/z");
- ensure_refname_normalized(SYM_REF, "refs/heads/FoO", "refs/heads/FoO");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master", "refs/heads/master");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/pu", "refs/heads/pu");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/z", "refs/heads/z");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/FoO", "refs/heads/FoO");
/* ValidTag */
- ensure_refname_normalized(SYM_REF, "refs/tags/v1.0", "refs/tags/v1.0");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/tags/v1.0", "refs/tags/v1.0");
/* NoLockSuffix */
- ensure_refname_invalid(SYM_REF, "refs/heads/master.lock");
+ ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master.lock");
/* NoDirectorySuffix */
- ensure_refname_invalid(SYM_REF, "refs/heads/master/");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master/");
/* NoSpace */
- ensure_refname_invalid(SYM_REF, "refs/heads/i haz space");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/i haz space");
/* NoAsciiControlCharacters */
{
@@ -112,89 +164,153 @@ void test_refs_normalize__jgit_suite(void)
strncpy(buffer + 15, (const char *)&c, 1);
strncpy(buffer + 16, "er", 2);
buffer[18 - 1] = '\0';
- ensure_refname_invalid(SYM_REF, buffer);
+ ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, buffer);
}
}
/* NoBareDot */
- ensure_refname_invalid(SYM_REF, "refs/heads/.");
- ensure_refname_invalid(SYM_REF, "refs/heads/..");
- ensure_refname_invalid(SYM_REF, "refs/heads/./master");
- ensure_refname_invalid(SYM_REF, "refs/heads/../master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/..");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/./master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/../master");
/* NoLeadingOrTrailingDot */
- ensure_refname_invalid(SYM_REF, ".");
- ensure_refname_invalid(SYM_REF, "refs/heads/.bar");
- ensure_refname_invalid(SYM_REF, "refs/heads/..bar");
- ensure_refname_invalid(SYM_REF, "refs/heads/bar.");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, ".");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/..bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/bar.");
/* ContainsDot */
- ensure_refname_normalized(SYM_REF, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r");
- ensure_refname_invalid(SYM_REF, "refs/heads/master..pu");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master..pu");
/* NoMagicRefCharacters */
- ensure_refname_invalid(SYM_REF, "refs/heads/master^");
- ensure_refname_invalid(SYM_REF, "refs/heads/^master");
- ensure_refname_invalid(SYM_REF, "^refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master~");
- ensure_refname_invalid(SYM_REF, "refs/heads/~master");
- ensure_refname_invalid(SYM_REF, "~refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master:");
- ensure_refname_invalid(SYM_REF, "refs/heads/:master");
- ensure_refname_invalid(SYM_REF, ":refs/heads/master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master^");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/^master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "^refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master~");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/~master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "~refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master:");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/:master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, ":refs/heads/master");
/* ShellGlob */
- ensure_refname_invalid(SYM_REF, "refs/heads/master?");
- ensure_refname_invalid(SYM_REF, "refs/heads/?master");
- ensure_refname_invalid(SYM_REF, "?refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master[");
- ensure_refname_invalid(SYM_REF, "refs/heads/[master");
- ensure_refname_invalid(SYM_REF, "[refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master*");
- ensure_refname_invalid(SYM_REF, "refs/heads/*master");
- ensure_refname_invalid(SYM_REF, "*refs/heads/master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master?");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/?master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "?refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master[");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/[master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "[refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master*");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/*master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "*refs/heads/master");
/* ValidSpecialCharacters */
- ensure_refname_normalized(SYM_REF, "refs/heads/!", "refs/heads/!");
- ensure_refname_normalized(SYM_REF, "refs/heads/\"", "refs/heads/\"");
- ensure_refname_normalized(SYM_REF, "refs/heads/#", "refs/heads/#");
- ensure_refname_normalized(SYM_REF, "refs/heads/$", "refs/heads/$");
- ensure_refname_normalized(SYM_REF, "refs/heads/%", "refs/heads/%");
- ensure_refname_normalized(SYM_REF, "refs/heads/&", "refs/heads/&");
- ensure_refname_normalized(SYM_REF, "refs/heads/'", "refs/heads/'");
- ensure_refname_normalized(SYM_REF, "refs/heads/(", "refs/heads/(");
- ensure_refname_normalized(SYM_REF, "refs/heads/)", "refs/heads/)");
- ensure_refname_normalized(SYM_REF, "refs/heads/+", "refs/heads/+");
- ensure_refname_normalized(SYM_REF, "refs/heads/,", "refs/heads/,");
- ensure_refname_normalized(SYM_REF, "refs/heads/-", "refs/heads/-");
- ensure_refname_normalized(SYM_REF, "refs/heads/;", "refs/heads/;");
- ensure_refname_normalized(SYM_REF, "refs/heads/<", "refs/heads/<");
- ensure_refname_normalized(SYM_REF, "refs/heads/=", "refs/heads/=");
- ensure_refname_normalized(SYM_REF, "refs/heads/>", "refs/heads/>");
- ensure_refname_normalized(SYM_REF, "refs/heads/@", "refs/heads/@");
- ensure_refname_normalized(SYM_REF, "refs/heads/]", "refs/heads/]");
- ensure_refname_normalized(SYM_REF, "refs/heads/_", "refs/heads/_");
- ensure_refname_normalized(SYM_REF, "refs/heads/`", "refs/heads/`");
- ensure_refname_normalized(SYM_REF, "refs/heads/{", "refs/heads/{");
- ensure_refname_normalized(SYM_REF, "refs/heads/|", "refs/heads/|");
- ensure_refname_normalized(SYM_REF, "refs/heads/}", "refs/heads/}");
+ ensure_refname_normalized
+ (GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/!", "refs/heads/!");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\"", "refs/heads/\"");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/#", "refs/heads/#");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/$", "refs/heads/$");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/%", "refs/heads/%");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/&", "refs/heads/&");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/'", "refs/heads/'");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/(", "refs/heads/(");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/)", "refs/heads/)");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/+", "refs/heads/+");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/,", "refs/heads/,");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/-", "refs/heads/-");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/;", "refs/heads/;");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/<", "refs/heads/<");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/=", "refs/heads/=");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/>", "refs/heads/>");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/@", "refs/heads/@");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/]", "refs/heads/]");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/_", "refs/heads/_");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/`", "refs/heads/`");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/{", "refs/heads/{");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/|", "refs/heads/|");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/}", "refs/heads/}");
// This is valid on UNIX, but not on Windows
// hence we make in invalid due to non-portability
//
- ensure_refname_invalid(SYM_REF, "refs/heads/\\");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\\");
/* UnicodeNames */
/*
* Currently this fails.
- * ensure_refname_normalized(SYM_REF, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m");
+ * ensure_refname_normalized(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m");
*/
/* RefLogQueryIsValidRef */
- ensure_refname_invalid(SYM_REF, "refs/heads/master@{1}");
- ensure_refname_invalid(SYM_REF, "refs/heads/master@{1.hour.ago}");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1}");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1.hour.ago}");
+}
+
+void test_refs_normalize__buffer_has_to_be_big_enough_to_hold_the_normalized_version(void)
+{
+ char buffer_out[21];
+
+ cl_git_pass(git_reference_normalize_name(
+ buffer_out, 21, "//refs//heads/long///name", GIT_REF_FORMAT_NORMAL));
+ cl_git_fail(git_reference_normalize_name(
+ buffer_out, 20, "//refs//heads/long///name", GIT_REF_FORMAT_NORMAL));
}
diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c
index 6f3c1c06d..126ca7d9f 100644
--- a/tests-clar/revwalk/basic.c
+++ b/tests-clar/revwalk/basic.c
@@ -179,3 +179,11 @@ void test_revwalk_basic__push_head_hide_ref_nobase(void)
/* git log HEAD --oneline --not refs/heads/packed | wc -l => 7 */
cl_assert(i == 7);
}
+
+void test_revwalk_basic__disallow_non_commit(void)
+{
+ git_oid oid;
+
+ cl_git_pass(git_oid_fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"));
+ cl_git_fail(git_revwalk_push(_walk, &oid));
+}