git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 13/25] shallow.c: implement a generic shallow boundary finder based on rev-list

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Feb 23, 2016, 13:44 UTC
Message-ID
<1456235103-26317-14-git-send-email-pclouds@gmail.com>
In-Reply-To
<1456235103-26317-1-git-send-email-pclouds@gmail.com>

Instead of a custom commit walker like get_shallow_commits(), this new function uses rev-list to mark NOT_SHALLOW to all reachable commits, except borders. The definition of reachable is to be defined by the protocol later. This makes it more flexible to define shallow boundary.

The way we find find border is paint all reachable commits NOT_SHALLOW. Any of them that "touches" commits without NOT_SHALLOW flag are considered shallow (e.g. zero parents via grafting mechanism). Shallow commits and their true parents are all marked SHALLOW. Then NOT_SHALLOW is removed from shallow commits at the end.

There is an interesting observation. With a generic walker, we can produce all kinds of shallow cutting. In the following graph, every commit but "x" is reachable. "b" is a parent of "a".

           x -- a -- o
          /    /
    x -- c -- b -- o

After this function is run, "a" and "c" are both considered shallow commits. After grafting occurs at the client side, what we see is

                a -- o
                    /
         c -- b -- o

Notice that because of grafting, "a" has zero parents, so "b" is no longer a parent of "a".

This is unfortunate and may be solved in two ways. The first is change the way shallow grafting works and keep "a -- b" connection if "b" exists and always ends at shallow commits (iow, no loose ends). This is hard to detect, or at least not cheap to do.

The second way is mark one "x" as shallow commit instead of "a" and produce this graph at client side:

           x -- a -- o
               /    /
         c -- b -- o
More commits, but simpler grafting rules.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 commit.h  |  2 ++
 shallow.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)
diff --git a/commit.h b/commit.h
index 5d58be0..b717be1 100644
--- a/commit.h
+++ b/commit.h
@@ -258,6 +258,8 @@ extern int for_each_commit_graft(each_commit_graft_fn, void *);
 extern int is_repository_shallow(void);
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
 		int depth, int shallow_flag, int not_shallow_flag);
+extern struct commit_list *get_shallow_commits_by_rev_list(
+		int ac, const char **av, int shallow_flag, int not_shallow_flag);
 extern void set_alternate_shallow_file(const char *path, int override);
 extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
 				 const struct sha1_array *extra);
diff --git a/shallow.c b/shallow.c
index 60f1505..5dca743 100644
--- a/shallow.c
+++ b/shallow.c
@@ -10,6 +10,8 @@
 #include "diff.h"
 #include "revision.h"
 #include "commit-slab.h"
+#include "revision.h"
+#include "list-objects.h"
 
 static int is_shallow = -1;
 static struct stat_validity shallow_stat;
@@ -137,6 +139,81 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
 	return result;
 }
 
+static void show_commit(struct commit *commit, void *data)
+{
+	commit_list_insert(commit, data);
+}
+
+/*
+ * Given rev-list arguments, run rev-list. All reachable commits
+ * except border ones are marked with not_shallow_flag. Border commits
+ * are marked with shallow_flag. The list of border/shallow commits
+ * are also returned.
+ */
+struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av,
+						    int shallow_flag,
+						    int not_shallow_flag)
+{
+	struct commit_list *result = NULL, *p;
+	struct commit_list *not_shallow_list = NULL;
+	struct rev_info revs;
+	int both_flags = shallow_flag | not_shallow_flag;
+
+	/*
+	 * SHALLOW (excluded) and NOT_SHALLOW (included) should not be
+	 * set at this point. But better be safe than sorry.
+	 */
+	clear_object_flags(both_flags);
+
+	is_repository_shallow(); /* make sure shallows are read */
+
+	init_revisions(&revs, NULL);
+	save_commit_buffer = 0;
+	setup_revisions(ac, av, &revs, NULL);
+
+	if (prepare_revision_walk(&revs))
+		die("revision walk setup failed");
+	traverse_commit_list(&revs, show_commit, NULL, &not_shallow_list);
+
+	/* Mark all reachable commits as NOT_SHALLOW */
+	for (p = not_shallow_list; p; p = p->next)
+		p->item->object.flags |= not_shallow_flag;
+
+	/*
+	 * mark border commits SHALLOW + NOT_SHALLOW.
+	 * We cannot clear NOT_SHALLOW right now. Imagine border
+	 * 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.
+	 */
+	for (p = not_shallow_list; p; p = p->next) {
+		struct commit *c = p->item;
+
+		if (parse_commit(c))
+			die("unable to parse commit %s",
+			    oid_to_hex(&c->object.oid));
+
+		for (p = c->parents; p; p = p->next)
+			if (!(p->item->object.flags & not_shallow_flag)) {
+				c->object.flags |= shallow_flag;
+				commit_list_insert(c, &result);
+				break;
+			}
+	}
+	free_commit_list(not_shallow_list);
+
+	/*
+	 * Now we can clean up NOT_SHALLOW on border commits. Having
+	 * both flags set can confuse the caller.
+	 */
+	for (p = result; p; p = p->next) {
+		struct object *o = &p->item->object;
+		if ((o->flags & both_flags) == both_flags)
+			o->flags &= ~not_shallow_flag;
+	}
+	return result;
+}
+
 static void check_shallow_file_for_update(void)
 {
 	if (is_shallow == -1)
-- 
2.7.1.532.gd9e3aaa
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 14 of 26 in “More flexibility in making shallow clones”
  1. 00/25 More flexibility in making shallow clonesNguyễn Thái Ngọc Duy, Feb 23, 2016
  2. 01/25 remote-curl.c: convert fetch_git() to use argv_arrayNguyễn Thái Ngọc Duy, Feb 23, 2016
  3. 02/25 transport-helper.c: refactor set_helper_option()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  4. 03/25 upload-pack: move shallow deepen code out of receive_needs()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  5. 04/25 upload-pack: move "shallow" sending code out of deepen()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  6. 05/25 upload-pack: remove unused variable "backup"Nguyễn Thái Ngọc Duy, Feb 23, 2016
  7. 06/25 upload-pack: move "unshallow" sending code out of deepen()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  8. 07/25 upload-pack: use skip_prefix() instead of starts_with()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  9. 08/25 upload-pack: tighten number parsing at "deepen" linesNguyễn Thái Ngọc Duy, Feb 23, 2016
  10. 09/25 upload-pack: move rev-list code out of check_non_tip()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  11. 10/25 fetch-pack: use skip_prefix() instead of starts_with()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  12. 11/25 fetch-pack: use a common function for verbose printingNguyễn Thái Ngọc Duy, Feb 23, 2016
  13. 12/25 fetch-pack: use a separate flag for fetch in deepening modeNguyễn Thái Ngọc Duy, Feb 23, 2016
  14. 13/25 shallow.c: implement a generic shallow boundary finder based on rev-listNguyễn Thái Ngọc Duy, Feb 23, 2016
  15. 14/25 upload-pack: add deepen-since to cut shallow repos based on timeNguyễn Thái Ngọc Duy, Feb 23, 2016
  16. 15/25 fetch: define shallow boundary with --shallow-sinceNguyễn Thái Ngọc Duy, Feb 23, 2016
  17. 16/25 clone: define shallow clone boundary based on time with --shallow-sinceNguyễn Thái Ngọc Duy, Feb 23, 2016
  18. 17/25 t5500, t5539: tests for shallow depth since a specific dateNguyễn Thái Ngọc Duy, Feb 23, 2016
  19. 18/25 refs: add expand_ref()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  20. 19/25 upload-pack: support define shallow boundary by excluding revisionsNguyễn Thái Ngọc Duy, Feb 23, 2016
  21. 20/25 fetch: define shallow boundary with --shallow-excludeNguyễn Thái Ngọc Duy, Feb 23, 2016
  22. 21/25 clone: define shallow clone boundary with --shallow-excludeNguyễn Thái Ngọc Duy, Feb 23, 2016
  23. 22/25 t5500, t5539: tests for shallow depth excluding a refNguyễn Thái Ngọc Duy, Feb 23, 2016
  24. 23/25 upload-pack: split check_unreachable() in two, prep for get_reachable_list()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  25. 24/25 upload-pack: add get_reachable_list()Nguyễn Thái Ngọc Duy, Feb 23, 2016
  26. 25/25 fetch, upload-pack: --deepen=N extends shallow boundary by N commitsNguyễn Thái Ngọc Duy, Feb 23, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.