git

Форк
0
/
default.c 
200 строк · 4.8 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "default.h"
5
#include "../commit.h"
6
#include "../fetch-negotiator.h"
7
#include "../prio-queue.h"
8
#include "../refs.h"
9
#include "../repository.h"
10
#include "../tag.h"
11

12
/* Remember to update object flag allocation in object.h */
13
#define COMMON		(1U << 2)
14
#define COMMON_REF	(1U << 3)
15
#define SEEN		(1U << 4)
16
#define POPPED		(1U << 5)
17

18
static int marked;
19

20
struct negotiation_state {
21
	struct prio_queue rev_list;
22
	int non_common_revs;
23
};
24

25
static void rev_list_push(struct negotiation_state *ns,
26
			  struct commit *commit, int mark)
27
{
28
	if (!(commit->object.flags & mark)) {
29
		commit->object.flags |= mark;
30

31
		if (repo_parse_commit(the_repository, commit))
32
			return;
33

34
		prio_queue_put(&ns->rev_list, commit);
35

36
		if (!(commit->object.flags & COMMON))
37
			ns->non_common_revs++;
38
	}
39
}
40

41
static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
42
		       int flag UNUSED,
43
		       void *cb_data UNUSED)
44
{
45
	struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
46

47
	if (o && o->type == OBJ_COMMIT)
48
		clear_commit_marks((struct commit *)o,
49
				   COMMON | COMMON_REF | SEEN | POPPED);
50
	return 0;
51
}
52

53
/*
54
 * This function marks a rev and its ancestors as common.
55
 * In some cases, it is desirable to mark only the ancestors (for example
56
 * when only the server does not yet know that they are common).
57
 */
58
static void mark_common(struct negotiation_state *ns, struct commit *commit,
59
		int ancestors_only, int dont_parse)
60
{
61
	struct prio_queue queue = { NULL };
62

63
	if (!commit || (commit->object.flags & COMMON))
64
		return;
65

66
	prio_queue_put(&queue, commit);
67
	if (!ancestors_only) {
68
		commit->object.flags |= COMMON;
69

70
		if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
71
			ns->non_common_revs--;
72
	}
73
	while ((commit = prio_queue_get(&queue))) {
74
		struct object *o = (struct object *)commit;
75

76
		if (!(o->flags & SEEN))
77
			rev_list_push(ns, commit, SEEN);
78
		else {
79
			struct commit_list *parents;
80

81
			if (!o->parsed && !dont_parse)
82
				if (repo_parse_commit(the_repository, commit))
83
					continue;
84

85
			for (parents = commit->parents;
86
					parents;
87
					parents = parents->next) {
88
				struct commit *p = parents->item;
89

90
				if (p->object.flags & COMMON)
91
					continue;
92

93
				p->object.flags |= COMMON;
94

95
				if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
96
					ns->non_common_revs--;
97

98
				prio_queue_put(&queue, parents->item);
99
			}
100
		}
101
	}
102

103
	clear_prio_queue(&queue);
104
}
105

106
/*
107
 * Get the next rev to send, ignoring the common.
108
 */
109
static const struct object_id *get_rev(struct negotiation_state *ns)
110
{
111
	struct commit *commit = NULL;
112

113
	while (commit == NULL) {
114
		unsigned int mark;
115
		struct commit_list *parents;
116

117
		if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
118
			return NULL;
119

120
		commit = prio_queue_get(&ns->rev_list);
121
		repo_parse_commit(the_repository, commit);
122
		parents = commit->parents;
123

124
		commit->object.flags |= POPPED;
125
		if (!(commit->object.flags & COMMON))
126
			ns->non_common_revs--;
127

128
		if (commit->object.flags & COMMON) {
129
			/* do not send "have", and ignore ancestors */
130
			commit = NULL;
131
			mark = COMMON | SEEN;
132
		} else if (commit->object.flags & COMMON_REF)
133
			/* send "have", and ignore ancestors */
134
			mark = COMMON | SEEN;
135
		else
136
			/* send "have", also for its ancestors */
137
			mark = SEEN;
138

139
		while (parents) {
140
			if (!(parents->item->object.flags & SEEN))
141
				rev_list_push(ns, parents->item, mark);
142
			if (mark & COMMON)
143
				mark_common(ns, parents->item, 1, 0);
144
			parents = parents->next;
145
		}
146
	}
147

148
	return &commit->object.oid;
149
}
150

151
static void known_common(struct fetch_negotiator *n, struct commit *c)
152
{
153
	if (!(c->object.flags & SEEN)) {
154
		rev_list_push(n->data, c, COMMON_REF | SEEN);
155
		mark_common(n->data, c, 1, 1);
156
	}
157
}
158

159
static void add_tip(struct fetch_negotiator *n, struct commit *c)
160
{
161
	n->known_common = NULL;
162
	rev_list_push(n->data, c, SEEN);
163
}
164

165
static const struct object_id *next(struct fetch_negotiator *n)
166
{
167
	n->known_common = NULL;
168
	n->add_tip = NULL;
169
	return get_rev(n->data);
170
}
171

172
static int ack(struct fetch_negotiator *n, struct commit *c)
173
{
174
	int known_to_be_common = !!(c->object.flags & COMMON);
175
	mark_common(n->data, c, 0, 1);
176
	return known_to_be_common;
177
}
178

179
static void release(struct fetch_negotiator *n)
180
{
181
	clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
182
	FREE_AND_NULL(n->data);
183
}
184

185
void default_negotiator_init(struct fetch_negotiator *negotiator)
186
{
187
	struct negotiation_state *ns;
188
	negotiator->known_common = known_common;
189
	negotiator->add_tip = add_tip;
190
	negotiator->next = next;
191
	negotiator->ack = ack;
192
	negotiator->release = release;
193
	negotiator->data = CALLOC_ARRAY(ns, 1);
194
	ns->rev_list.compare = compare_commits_by_commit_date;
195

196
	if (marked)
197
		refs_for_each_ref(get_main_ref_store(the_repository),
198
				  clear_marks, NULL);
199
	marked = 1;
200
}
201

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.