Subject: [PATCH] Fixed --shallow-since generating descendant borders

From: "Samo Pogačnik via GitGitGadget" <[email-masked]>
Date: Sat, 22 Nov 2025 10:38:34 +0000

From: =?UTF-8?q?Samo=20Poga=C4=8Dnik?= <[email-masked]>

When shallow cloning based on a date, it happens that a list
of commits is received, where some of the list border commits
actually descend one from another. In such cases borders need
to be expanded by additional parents and excluding the child
as border.

Signed-off-by: Samo Pogačnik <[email-masked]>
---
    Fixed --shallow-since generating descendant borders
    
    When shallow cloning based on a date, it happens that a list of commits
    is received, where some of the list border commits actually descend one
    from another. In such cases borders need to be expanded by additional
    parents and excluding the child as border.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2107%2Fspog%2Ffix-shallow-since-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2107/spog/fix-shallow-since-v1
Pull-Request: https://github.com/git/git/pull/2107

 shallow.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/shallow.c b/shallow.c
index 55b9cd9d3f..37079a0bf1 100644
--- a/shallow.c
+++ b/shallow.c
@@ -251,21 +251,50 @@ struct commit_list *get_shallow_commits_by_rev_list(struct strvec *argv,
 	 * commit A is processed first, then commit B, whose parent is
 	 * A, later. If NOT_SHALLOW on A is cleared at step 1, B
 	 * itself is considered border at step 2, which is incorrect.
+	 * We must also consider that B has multiple parents, some of
+	 * them not being in the not_shallow_list, but must be added
+	 * as border commits to the result.
+	 *
+	 * The general processing goes like this:
+	 * 1. Above we've coloured the whole not_shallow_list of commits
+	 *    with 'not_shallow'.
+	 * 2. For each commit from the not_shallow_list (the code below)
+	 *    we colour 'shallow' the commit and its parents, which are not
+	 *    already coloured 'not_shallow'.
+	 * 3. Commits with all parents being coloured only 'shallow' remain
+	 *    shallow and are being added to result list.
+	 * 4. Commits without all parents being coloured only 'shallow' are
+	 *    being excluded as borders, however their parents coloured only
+	 *    'shallow' are being added to the result borders list.
 	 */
 	for (p = not_shallow_list; p; p = p->next) {
 		struct commit *c = p->item;
 		struct commit_list *parent;
+		int must_not_be_shallow = 0;
 
 		if (repo_parse_commit(the_repository, c))
 			die("unable to parse commit %s",
 			    oid_to_hex(&c->object.oid));
 
 		for (parent = c->parents; parent; parent = parent->next)
-			if (!(parent->item->object.flags & not_shallow_flag)) {
+			if (parent->item->object.flags & not_shallow_flag) {
+				must_not_be_shallow = 1;
+			} else {
 				c->object.flags |= shallow_flag;
-				commit_list_insert(c, &result);
-				break;
+				parent->item->object.flags |= shallow_flag;
 			}
+		if (must_not_be_shallow) {
+			c->object.flags &= ~shallow_flag;
+			for (parent = c->parents; parent; parent = parent->next)
+				if (parent->item->object.flags & shallow_flag) {
+					parent->item->object.flags |= not_shallow_flag;
+					commit_list_insert(parent->item, &result);
+				}
+		} else {
+			for (parent = c->parents; parent; parent = parent->next)
+				parent->item->object.flags &= ~shallow_flag;
+			commit_list_insert(c, &result);
+		}
 	}
 	free_commit_list(not_shallow_list);

base-commit: debbc87557487aa9a8ed8a35367d17f8b4081c76
-- 
gitgitgadget