revwalk: ignore wrong object type in glob pushes Pushing a whole namespace can cause us to attempt to push non-committish objects. Catch this situation and special-case it for ignoring this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h
index 4eac8d4..12829b1 100644
--- a/include/git2/revwalk.h
+++ b/include/git2/revwalk.h
@@ -110,6 +110,9 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *id);
* A leading 'refs/' is implied if not present as well as a trailing
* '/ *' if the glob lacks '?', '*' or '['.
*
+ * Any references matching this glob which do not point to a
+ * committish will be ignored.
+ *
* @param walk the walker being used for the traversal
* @param glob the glob pattern references should match
* @return 0 or an error code
@@ -149,6 +152,9 @@ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *commit_id);
* A leading 'refs/' is implied if not present as well as a trailing
* '/ *' if the glob lacks '?', '*' or '['.
*
+ * Any references matching this glob which do not point to a
+ * committish will be ignored.
+ *
* @param walk the walker being used for the traversal
* @param glob the glob pattern references should match
* @return 0 or an error code
diff --git a/src/revwalk.c b/src/revwalk.c
index 3cc3140..63d78fe 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -110,7 +110,7 @@ static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commi
return error;
}
-static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
+static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob)
{
git_oid commit_id;
int error;
@@ -124,6 +124,10 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
git_object_free(oobj);
if (error == GIT_ENOTFOUND) {
+ /* If this comes from e.g. push_glob("tags"), ignore this */
+ if (from_glob)
+ return 0;
+
giterr_set(GITERR_INVALID, "Object is not a committish");
return -1;
}
@@ -151,24 +155,24 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
{
assert(walk && oid);
- return push_commit(walk, oid, 0);
+ return push_commit(walk, oid, 0, false);
}
int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
{
assert(walk && oid);
- return push_commit(walk, oid, 1);
+ return push_commit(walk, oid, 1, false);
}
-static int push_ref(git_revwalk *walk, const char *refname, int hide)
+static int push_ref(git_revwalk *walk, const char *refname, int hide, int from_glob)
{
git_oid oid;
if (git_reference_name_to_id(&oid, walk->repo, refname) < 0)
return -1;
- return push_commit(walk, &oid, hide);
+ return push_commit(walk, &oid, hide, from_glob);
}
struct push_cb_data {
@@ -179,7 +183,7 @@ struct push_cb_data {
static int push_glob_cb(const char *refname, void *data_)
{
struct push_cb_data *data = (struct push_cb_data *)data_;
- return push_ref(data->walk, refname, data->hide);
+ return push_ref(data->walk, refname, data->hide, true);
}
static int push_glob(git_revwalk *walk, const char *glob, int hide)
@@ -229,19 +233,19 @@ int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
int git_revwalk_push_head(git_revwalk *walk)
{
assert(walk);
- return push_ref(walk, GIT_HEAD_FILE, 0);
+ return push_ref(walk, GIT_HEAD_FILE, 0, false);
}
int git_revwalk_hide_head(git_revwalk *walk)
{
assert(walk);
- return push_ref(walk, GIT_HEAD_FILE, 1);
+ return push_ref(walk, GIT_HEAD_FILE, 1, false);
}
int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
{
assert(walk && refname);
- return push_ref(walk, refname, 0);
+ return push_ref(walk, refname, 0, false);
}
int git_revwalk_push_range(git_revwalk *walk, const char *range)
@@ -258,10 +262,10 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range)
return GIT_EINVALIDSPEC;
}
- if ((error = push_commit(walk, git_object_id(revspec.from), 1)))
+ if ((error = push_commit(walk, git_object_id(revspec.from), 1, false)))
goto out;
- error = push_commit(walk, git_object_id(revspec.to), 0);
+ error = push_commit(walk, git_object_id(revspec.to), 0, false);
out:
git_object_free(revspec.from);
@@ -272,7 +276,7 @@ out:
int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
{
assert(walk && refname);
- return push_ref(walk, refname, 1);
+ return push_ref(walk, refname, 1, false);
}
static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit)
diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c
index 4621ab8..4d6522c 100644
--- a/tests/revwalk/basic.c
+++ b/tests/revwalk/basic.c
@@ -255,10 +255,19 @@ void test_revwalk_basic__push_range(void)
void test_revwalk_basic__push_mixed(void)
{
+ git_oid oid;
+ int i = 0;
+
revwalk_basic_setup_walk(NULL);
git_revwalk_reset(_walk);
git_revwalk_sorting(_walk, 0);
cl_git_pass(git_revwalk_push_glob(_walk, "tags"));
- cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1));
+
+ while (git_revwalk_next(&oid, _walk) == 0) {
+ i++;
+ }
+
+ /* git rev-list --count --glob=tags #=> 9 */
+ cl_assert_equal_i(9, i);
}