aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shallow.c73
-rw-r--r--shallow.h2
-rwxr-xr-xt/t5500-fetch-pack.sh23
-rw-r--r--upload-pack.c72
4 files changed, 88 insertions, 82 deletions
diff --git a/shallow.c b/shallow.c
index 0409b1354c..7a3dd56795 100644
--- a/shallow.c
+++ b/shallow.c
@@ -130,11 +130,24 @@ static void free_depth_in_slab(int **ptr)
{
FREE_AND_NULL(*ptr);
}
-struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
- int shallow_flag, int not_shallow_flag)
+/*
+ * This is a common internal function that can either return a list of
+ * shallow commits or calculate the current maximum depth of a shallow
+ * repository, depending on the input parameters.
+ *
+ * Depth calculation is triggered by passing the `shallows` parameter.
+ * In this case, the computed depth is stored in `max_cur_depth` (if it is
+ * provided), and the function returns NULL.
+ *
+ * Otherwise, `max_cur_depth` remains unchanged and the function returns
+ * a list of shallow commits.
+ */
+static struct commit_list *get_shallows_or_depth(struct object_array *heads,
+ struct object_array *shallows, int *max_cur_depth,
+ int depth, int shallow_flag, int not_shallow_flag)
{
size_t i = 0;
- int cur_depth = 0;
+ int cur_depth = 0, cur_depth_shallow = 0;
struct commit_list *result = NULL;
struct object_array stack = OBJECT_ARRAY_INIT;
struct commit *commit = NULL;
@@ -168,16 +181,30 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
}
parse_commit_or_die(commit);
cur_depth++;
- if ((depth != INFINITE_DEPTH && cur_depth >= depth) ||
- (is_repository_shallow(the_repository) && !commit->parents &&
- (graft = lookup_commit_graft(the_repository, &commit->object.oid)) != NULL &&
- graft->nr_parent < 0)) {
- commit_list_insert(commit, &result);
- commit->object.flags |= shallow_flag;
- commit = NULL;
- continue;
+ if (shallows) {
+ for (size_t j = 0; j < shallows->nr; j++)
+ if (oideq(&commit->object.oid, &shallows->objects[j].item->oid))
+ if (!cur_depth_shallow || cur_depth < cur_depth_shallow)
+ cur_depth_shallow = cur_depth;
+
+ if ((is_repository_shallow(the_repository) && !commit->parents &&
+ (graft = lookup_commit_graft(the_repository, &commit->object.oid)) != NULL &&
+ graft->nr_parent < 0)) {
+ commit = NULL;
+ continue;
+ }
+ } else {
+ if ((depth != INFINITE_DEPTH && cur_depth >= depth) ||
+ (is_repository_shallow(the_repository) && !commit->parents &&
+ (graft = lookup_commit_graft(the_repository, &commit->object.oid)) != NULL &&
+ graft->nr_parent < 0)) {
+ commit_list_insert(commit, &result);
+ commit->object.flags |= shallow_flag;
+ commit = NULL;
+ continue;
+ }
+ commit->object.flags |= not_shallow_flag;
}
- commit->object.flags |= not_shallow_flag;
for (p = commit->parents, commit = NULL; p; p = p->next) {
int **depth_slot = commit_depth_at(&depths, p->item);
if (!*depth_slot) {
@@ -198,10 +225,32 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
}
}
deep_clear_commit_depth(&depths, free_depth_in_slab);
+ object_array_clear(&stack);
+ if (shallows && max_cur_depth)
+ *max_cur_depth = cur_depth_shallow;
return result;
}
+int get_shallows_depth(struct object_array *heads, struct object_array *shallows)
+{
+ int max_cur_depth = 0;
+ get_shallows_or_depth(heads, shallows, &max_cur_depth, 0, 0, 0);
+ return max_cur_depth;
+
+}
+
+struct commit_list *get_shallow_commits(struct object_array *heads,
+ struct object_array *shallows, int deepen_relative,
+ int depth, int shallow_flag, int not_shallow_flag)
+{
+ if (shallows && deepen_relative) {
+ depth += get_shallows_depth(heads, shallows);
+ }
+ return get_shallows_or_depth(heads, NULL, NULL,
+ depth, shallow_flag, not_shallow_flag);
+}
+
static void show_commit(struct commit *commit, void *data)
{
commit_list_insert(commit, data);
diff --git a/shallow.h b/shallow.h
index 1c0787de1d..e20ca4c21b 100644
--- a/shallow.h
+++ b/shallow.h
@@ -36,7 +36,9 @@ int commit_shallow_file(struct repository *r, struct shallow_lock *lk);
/* rollback $GIT_DIR/shallow and reset stat-validity checks */
void rollback_shallow_file(struct repository *r, struct shallow_lock *lk);
+int get_shallows_depth(struct object_array *heads, struct object_array *shallows);
struct commit_list *get_shallow_commits(struct object_array *heads,
+ struct object_array *shallows, int deepen_relative,
int depth, int shallow_flag, int not_shallow_flag);
struct commit_list *get_shallow_commits_by_rev_list(struct strvec *argv,
int shallow_flag, int not_shallow_flag);
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 4bb56c167a..c0278ef732 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -960,6 +960,29 @@ test_expect_success 'fetching deepen' '
)
'
+test_expect_success 'fetching deepen beyond merged branch' '
+ test_create_repo shallow-deepen-merged &&
+ (
+ cd shallow-deepen-merged &&
+ git commit --allow-empty -m one &&
+ git commit --allow-empty -m two &&
+ git commit --allow-empty -m three &&
+ git switch -c branch &&
+ git commit --allow-empty -m four &&
+ git commit --allow-empty -m five &&
+ git switch main &&
+ git merge --no-ff branch &&
+ cd - &&
+ git clone --bare --depth 3 "file://$(pwd)/shallow-deepen-merged" deepen.git &&
+ git -C deepen.git fetch origin --deepen=1 &&
+ git -C deepen.git rev-list --all >actual &&
+ for commit in $(sed "/^$/d" deepen.git/shallow)
+ do
+ test_grep "$commit" actual || exit 1
+ done
+ )
+'
+
test_negotiation_algorithm_default () {
test_when_finished rm -rf clientv0 clientv2 &&
rm -rf server client &&
diff --git a/upload-pack.c b/upload-pack.c
index 2d2b70cbf2..88dac1b65c 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -704,56 +704,6 @@ error:
return -1;
}
-static int get_reachable_list(struct upload_pack_data *data,
- struct object_array *reachable)
-{
- struct child_process cmd = CHILD_PROCESS_INIT;
- int i;
- struct object *o;
- char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */
- const unsigned hexsz = the_hash_algo->hexsz;
- int ret;
-
- if (do_reachable_revlist(&cmd, &data->shallows, reachable,
- data->allow_uor) < 0) {
- ret = -1;
- goto out;
- }
-
- while ((i = read_in_full(cmd.out, namebuf, hexsz + 1)) == hexsz + 1) {
- struct object_id oid;
- const char *p;
-
- if (parse_oid_hex(namebuf, &oid, &p) || *p != '\n')
- break;
-
- o = lookup_object(the_repository, &oid);
- if (o && o->type == OBJ_COMMIT) {
- o->flags &= ~TMP_MARK;
- }
- }
- for (i = get_max_object_index(the_repository); 0 < i; i--) {
- o = get_indexed_object(the_repository, i - 1);
- if (o && o->type == OBJ_COMMIT &&
- (o->flags & TMP_MARK)) {
- add_object_array(o, NULL, reachable);
- o->flags &= ~TMP_MARK;
- }
- }
- close(cmd.out);
-
- if (finish_command(&cmd)) {
- ret = -1;
- goto out;
- }
-
- ret = 0;
-
-out:
- child_process_clear(&cmd);
- return ret;
-}
-
static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
{
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -881,29 +831,11 @@ static void deepen(struct upload_pack_data *data, int depth)
struct object *object = data->shallows.objects[i].item;
object->flags |= NOT_SHALLOW;
}
- } else if (data->deepen_relative) {
- struct object_array reachable_shallows = OBJECT_ARRAY_INIT;
- struct commit_list *result;
-
- /*
- * Checking for reachable shallows requires that our refs be
- * marked with OUR_REF.
- */
- refs_head_ref_namespaced(get_main_ref_store(the_repository),
- check_ref, data);
- for_each_namespaced_ref_1(check_ref, data);
-
- get_reachable_list(data, &reachable_shallows);
- result = get_shallow_commits(&reachable_shallows,
- depth + 1,
- SHALLOW, NOT_SHALLOW);
- send_shallow(data, result);
- free_commit_list(result);
- object_array_clear(&reachable_shallows);
} else {
struct commit_list *result;
- result = get_shallow_commits(&data->want_obj, depth,
+ result = get_shallow_commits(&data->want_obj, &data->shallows,
+ data->deepen_relative, depth,
SHALLOW, NOT_SHALLOW);
send_shallow(data, result);
free_commit_list(result);