]> git.ipfire.org Git - thirdparty/git.git/blame - negotiator/default.c
Merge branch 'jk/clone-allow-bare-and-o-together'
[thirdparty/git.git] / negotiator / default.c
CommitLineData
ec062838
JT
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"
8
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)
14
15static int marked;
16
17struct negotiation_state {
18 struct prio_queue rev_list;
19 int non_common_revs;
20};
21
22static void rev_list_push(struct negotiation_state *ns,
23 struct commit *commit, int mark)
24{
25 if (!(commit->object.flags & mark)) {
26 commit->object.flags |= mark;
27
28 if (parse_commit(commit))
29 return;
30
31 prio_queue_put(&ns->rev_list, commit);
32
33 if (!(commit->object.flags & COMMON))
34 ns->non_common_revs++;
35 }
36}
37
38static int clear_marks(const char *refname, const struct object_id *oid,
5cf88fd8
ÆAB
39 int flag UNUSED,
40 void *cb_data UNUSED)
ec062838 41{
3a2a1dc1 42 struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
ec062838
JT
43
44 if (o && o->type == OBJ_COMMIT)
45 clear_commit_marks((struct commit *)o,
46 COMMON | COMMON_REF | SEEN | POPPED);
47 return 0;
48}
49
50/*
51 * This function marks a rev and its ancestors as common.
52 * In some cases, it is desirable to mark only the ancestors (for example
53 * when only the server does not yet know that they are common).
54 */
55static void mark_common(struct negotiation_state *ns, struct commit *commit,
56 int ancestors_only, int dont_parse)
57{
58 if (commit != NULL && !(commit->object.flags & COMMON)) {
59 struct object *o = (struct object *)commit;
60
61 if (!ancestors_only)
62 o->flags |= COMMON;
63
64 if (!(o->flags & SEEN))
65 rev_list_push(ns, commit, SEEN);
66 else {
67 struct commit_list *parents;
68
69 if (!ancestors_only && !(o->flags & POPPED))
70 ns->non_common_revs--;
71 if (!o->parsed && !dont_parse)
72 if (parse_commit(commit))
73 return;
74
75 for (parents = commit->parents;
76 parents;
77 parents = parents->next)
78 mark_common(ns, parents->item, 0,
79 dont_parse);
80 }
81 }
82}
83
84/*
85 * Get the next rev to send, ignoring the common.
86 */
87static const struct object_id *get_rev(struct negotiation_state *ns)
88{
89 struct commit *commit = NULL;
90
91 while (commit == NULL) {
92 unsigned int mark;
93 struct commit_list *parents;
94
95 if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
96 return NULL;
97
98 commit = prio_queue_get(&ns->rev_list);
99 parse_commit(commit);
100 parents = commit->parents;
101
102 commit->object.flags |= POPPED;
103 if (!(commit->object.flags & COMMON))
104 ns->non_common_revs--;
105
106 if (commit->object.flags & COMMON) {
107 /* do not send "have", and ignore ancestors */
108 commit = NULL;
109 mark = COMMON | SEEN;
110 } else if (commit->object.flags & COMMON_REF)
111 /* send "have", and ignore ancestors */
112 mark = COMMON | SEEN;
113 else
114 /* send "have", also for its ancestors */
115 mark = SEEN;
116
117 while (parents) {
118 if (!(parents->item->object.flags & SEEN))
119 rev_list_push(ns, parents->item, mark);
120 if (mark & COMMON)
121 mark_common(ns, parents->item, 1, 0);
122 parents = parents->next;
123 }
124 }
125
126 return &commit->object.oid;
127}
128
129static void known_common(struct fetch_negotiator *n, struct commit *c)
130{
131 if (!(c->object.flags & SEEN)) {
132 rev_list_push(n->data, c, COMMON_REF | SEEN);
133 mark_common(n->data, c, 1, 1);
134 }
135}
136
137static void add_tip(struct fetch_negotiator *n, struct commit *c)
138{
139 n->known_common = NULL;
140 rev_list_push(n->data, c, SEEN);
141}
142
143static const struct object_id *next(struct fetch_negotiator *n)
144{
145 n->known_common = NULL;
146 n->add_tip = NULL;
147 return get_rev(n->data);
148}
149
150static int ack(struct fetch_negotiator *n, struct commit *c)
151{
152 int known_to_be_common = !!(c->object.flags & COMMON);
153 mark_common(n->data, c, 0, 1);
154 return known_to_be_common;
155}
156
157static void release(struct fetch_negotiator *n)
158{
159 clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
160 FREE_AND_NULL(n->data);
161}
162
163void default_negotiator_init(struct fetch_negotiator *negotiator)
164{
165 struct negotiation_state *ns;
166 negotiator->known_common = known_common;
167 negotiator->add_tip = add_tip;
168 negotiator->next = next;
169 negotiator->ack = ack;
170 negotiator->release = release;
ca56dadb 171 negotiator->data = CALLOC_ARRAY(ns, 1);
ec062838
JT
172 ns->rev_list.compare = compare_commits_by_commit_date;
173
174 if (marked)
175 for_each_ref(clear_marks, NULL);
176 marked = 1;
177}