aboutsummaryrefslogtreecommitdiff
path: root/git2d/cmd_ref.c
blob: f4bae4a61d6784fdcfd9fbab7cf55ef8779dd88e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

/*-
 * SPDX-License-Identifier: AGPL-3.0-only
 * SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
 */

#include "x.h"

static int write_oid(struct bare_writer *writer, const git_oid *oid)
{
	return bare_put_data(writer, oid->id, GIT_OID_RAWSZ) == BARE_ERROR_NONE ? 0 : -1;
}

int cmd_resolve_ref(git_repository *repo, struct bare_reader *reader, struct bare_writer *writer)
{
	char type[32] = { 0 };
	char name[4096] = { 0 };
	if (bare_get_data(reader, (uint8_t *) type, sizeof(type) - 1) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		return -1;
	}
	if (bare_get_data(reader, (uint8_t *) name, sizeof(name) - 1) != BARE_ERROR_NONE) {
		bare_put_uint(writer, 11);
		return -1;
	}

	git_oid oid = { 0 };
	int err = 0;

	if (type[0] == '\0') {
		git_object *obj = NULL;
		err = git_revparse_single(&obj, repo, "HEAD^{commit}");
		if (err != 0) {
			bare_put_uint(writer, 12);
			return -1;
		}
		git_commit *c = (git_commit *) obj;
		git_oid_cpy(&oid, git_commit_id(c));
		git_commit_free(c);
	} else if (strcmp(type, "commit") == 0) {
		err = git_oid_fromstr(&oid, name);
		if (err != 0) {
			bare_put_uint(writer, 12);
			return -1;
		}
	} else if (strcmp(type, "branch") == 0) {
		char fullref[4608];
		snprintf(fullref, sizeof(fullref), "refs/heads/%s", name);
		git_object *obj = NULL;
		err = git_revparse_single(&obj, repo, fullref);
		if (err != 0) {
			bare_put_uint(writer, 12);
			return -1;
		}
		git_commit *c = (git_commit *) obj;
		git_oid_cpy(&oid, git_commit_id(c));
		git_commit_free(c);
	} else if (strcmp(type, "tag") == 0) {
		char spec[4608];
		snprintf(spec, sizeof(spec), "refs/tags/%s^{commit}", name);
		git_object *obj = NULL;
		err = git_revparse_single(&obj, repo, spec);
		if (err != 0) {
			bare_put_uint(writer, 12);
			return -1;
		}
		git_commit *c = (git_commit *) obj;
		git_oid_cpy(&oid, git_commit_id(c));
		git_commit_free(c);
	} else {
		bare_put_uint(writer, 12);
		return -1;
	}

	bare_put_uint(writer, 0);
	return write_oid(writer, &oid);
}

int cmd_list_branches(git_repository *repo, struct bare_writer *writer)
{
	git_branch_iterator *it = NULL;
	int err = git_branch_iterator_new(&it, repo, GIT_BRANCH_LOCAL);
	if (err != 0) {
		bare_put_uint(writer, 13);
		return -1;
	}
	size_t count = 0;
	git_reference *ref;
	git_branch_t type;
	while (git_branch_next(&ref, &type, it) == 0) {
		count++;
		git_reference_free(ref);
	}
	git_branch_iterator_free(it);

	err = git_branch_iterator_new(&it, repo, GIT_BRANCH_LOCAL);
	if (err != 0) {
		bare_put_uint(writer, 13);
		return -1;
	}

	bare_put_uint(writer, 0);
	bare_put_uint(writer, count);
	while (git_branch_next(&ref, &type, it) == 0) {
		const char *name = NULL;
		git_branch_name(&name, ref);
		if (name == NULL)
			name = "";
		bare_put_data(writer, (const uint8_t *)name, strlen(name));
		git_reference_free(ref);
	}
	git_branch_iterator_free(it);
	return 0;
}