sparse-checkout: improve OS ls compatibility
[git.git] / negotiator / default.c
blob4b78f6bf36a0479a55934a6e4ac4c288775217f5
1 #include "cache.h"
2 #include "default.h"
3 #include "../commit.h"
4 #include "../fetch-negotiator.h"
5 #include "../prio-queue.h"
6 #include "../refs.h"
7 #include "../tag.h"
9 /* Remember to update object flag allocation in object.h */
10 #define COMMON (1U << 2)
11 #define COMMON_REF (1U << 3)
12 #define SEEN (1U << 4)
13 #define POPPED (1U << 5)
15 static int marked;
17 struct negotiation_state {
18 struct prio_queue rev_list;
19 int non_common_revs;
22 static void rev_list_push(struct negotiation_state *ns,
23 struct commit *commit, int mark)
25 if (!(commit->object.flags & mark)) {
26 commit->object.flags |= mark;
28 if (parse_commit(commit))
29 return;
31 prio_queue_put(&ns->rev_list, commit);
33 if (!(commit->object.flags & COMMON))
34 ns->non_common_revs++;
38 static int clear_marks(const char *refname, const struct object_id *oid,
39 int flag, void *cb_data)
41 struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
43 if (o && o->type == OBJ_COMMIT)
44 clear_commit_marks((struct commit *)o,
45 COMMON | COMMON_REF | SEEN | POPPED);
46 return 0;
50 * This function marks a rev and its ancestors as common.
51 * In some cases, it is desirable to mark only the ancestors (for example
52 * when only the server does not yet know that they are common).
54 static void mark_common(struct negotiation_state *ns, struct commit *commit,
55 int ancestors_only, int dont_parse)
57 if (commit != NULL && !(commit->object.flags & COMMON)) {
58 struct object *o = (struct object *)commit;
60 if (!ancestors_only)
61 o->flags |= COMMON;
63 if (!(o->flags & SEEN))
64 rev_list_push(ns, commit, SEEN);
65 else {
66 struct commit_list *parents;
68 if (!ancestors_only && !(o->flags & POPPED))
69 ns->non_common_revs--;
70 if (!o->parsed && !dont_parse)
71 if (parse_commit(commit))
72 return;
74 for (parents = commit->parents;
75 parents;
76 parents = parents->next)
77 mark_common(ns, parents->item, 0,
78 dont_parse);
84 * Get the next rev to send, ignoring the common.
86 static const struct object_id *get_rev(struct negotiation_state *ns)
88 struct commit *commit = NULL;
90 while (commit == NULL) {
91 unsigned int mark;
92 struct commit_list *parents;
94 if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
95 return NULL;
97 commit = prio_queue_get(&ns->rev_list);
98 parse_commit(commit);
99 parents = commit->parents;
101 commit->object.flags |= POPPED;
102 if (!(commit->object.flags & COMMON))
103 ns->non_common_revs--;
105 if (commit->object.flags & COMMON) {
106 /* do not send "have", and ignore ancestors */
107 commit = NULL;
108 mark = COMMON | SEEN;
109 } else if (commit->object.flags & COMMON_REF)
110 /* send "have", and ignore ancestors */
111 mark = COMMON | SEEN;
112 else
113 /* send "have", also for its ancestors */
114 mark = SEEN;
116 while (parents) {
117 if (!(parents->item->object.flags & SEEN))
118 rev_list_push(ns, parents->item, mark);
119 if (mark & COMMON)
120 mark_common(ns, parents->item, 1, 0);
121 parents = parents->next;
125 return &commit->object.oid;
128 static void known_common(struct fetch_negotiator *n, struct commit *c)
130 if (!(c->object.flags & SEEN)) {
131 rev_list_push(n->data, c, COMMON_REF | SEEN);
132 mark_common(n->data, c, 1, 1);
136 static void add_tip(struct fetch_negotiator *n, struct commit *c)
138 n->known_common = NULL;
139 rev_list_push(n->data, c, SEEN);
142 static const struct object_id *next(struct fetch_negotiator *n)
144 n->known_common = NULL;
145 n->add_tip = NULL;
146 return get_rev(n->data);
149 static int ack(struct fetch_negotiator *n, struct commit *c)
151 int known_to_be_common = !!(c->object.flags & COMMON);
152 mark_common(n->data, c, 0, 1);
153 return known_to_be_common;
156 static void release(struct fetch_negotiator *n)
158 clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
159 FREE_AND_NULL(n->data);
162 void default_negotiator_init(struct fetch_negotiator *negotiator)
164 struct negotiation_state *ns;
165 negotiator->known_common = known_common;
166 negotiator->add_tip = add_tip;
167 negotiator->next = next;
168 negotiator->ack = ack;
169 negotiator->release = release;
170 negotiator->data = ns = xcalloc(1, sizeof(*ns));
171 ns->rev_list.compare = compare_commits_by_commit_date;
173 if (marked)
174 for_each_ref(clear_marks, NULL);
175 marked = 1;