]> git.proxmox.com Git - libgit2.git/blob - src/reflog.c
1834a27362080052078b6fe86acfd9c052c42fc1
[libgit2.git] / src / reflog.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8 #include "reflog.h"
9
10 #include "repository.h"
11 #include "filebuf.h"
12 #include "signature.h"
13 #include "refdb.h"
14
15 #include <git2/sys/refdb_backend.h>
16
17 git_reflog_entry *git_reflog_entry__alloc(void)
18 {
19 return git__calloc(1, sizeof(git_reflog_entry));
20 }
21
22 void git_reflog_entry__free(git_reflog_entry *entry)
23 {
24 git_signature_free(entry->committer);
25
26 git__free(entry->msg);
27 git__free(entry);
28 }
29
30 void git_reflog_free(git_reflog *reflog)
31 {
32 size_t i;
33 git_reflog_entry *entry;
34
35 if (reflog == NULL)
36 return;
37
38 if (reflog->db)
39 GIT_REFCOUNT_DEC(reflog->db, git_refdb__free);
40
41 for (i=0; i < reflog->entries.length; i++) {
42 entry = git_vector_get(&reflog->entries, i);
43
44 git_reflog_entry__free(entry);
45 }
46
47 git_vector_free(&reflog->entries);
48 git__free(reflog->ref_name);
49 git__free(reflog);
50 }
51
52 int git_reflog_read(git_reflog **reflog, git_repository *repo, const char *name)
53 {
54 git_refdb *refdb;
55 int error;
56
57 assert(reflog && repo && name);
58
59 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
60 return error;
61
62 return git_refdb_reflog_read(reflog, refdb, name);
63 }
64
65 int git_reflog_write(git_reflog *reflog)
66 {
67 git_refdb *db;
68
69 assert(reflog && reflog->db);
70
71 db = reflog->db;
72 return db->backend->reflog_write(db->backend, reflog);
73 }
74
75 int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_signature *committer, const char *msg)
76 {
77 git_reflog_entry *entry;
78 const git_reflog_entry *previous;
79 const char *newline;
80
81 assert(reflog && new_oid && committer);
82
83 entry = git__calloc(1, sizeof(git_reflog_entry));
84 GIT_ERROR_CHECK_ALLOC(entry);
85
86 if ((git_signature_dup(&entry->committer, committer)) < 0)
87 goto cleanup;
88
89 if (msg != NULL) {
90 if ((entry->msg = git__strdup(msg)) == NULL)
91 goto cleanup;
92
93 newline = strchr(msg, '\n');
94
95 if (newline) {
96 if (newline[1] != '\0') {
97 git_error_set(GIT_ERROR_INVALID, "reflog message cannot contain newline");
98 goto cleanup;
99 }
100
101 entry->msg[newline - msg] = '\0';
102 }
103 }
104
105 previous = git_reflog_entry_byindex(reflog, 0);
106
107 if (previous == NULL)
108 git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO);
109 else
110 git_oid_cpy(&entry->oid_old, &previous->oid_cur);
111
112 git_oid_cpy(&entry->oid_cur, new_oid);
113
114 if (git_vector_insert(&reflog->entries, entry) < 0)
115 goto cleanup;
116
117 return 0;
118
119 cleanup:
120 git_reflog_entry__free(entry);
121 return -1;
122 }
123
124 int git_reflog_rename(git_repository *repo, const char *old_name, const char *new_name)
125 {
126 git_refdb *refdb;
127 int error;
128
129 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
130 return -1;
131
132 return refdb->backend->reflog_rename(refdb->backend, old_name, new_name);
133 }
134
135 int git_reflog_delete(git_repository *repo, const char *name)
136 {
137 git_refdb *refdb;
138 int error;
139
140 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
141 return -1;
142
143 return refdb->backend->reflog_delete(refdb->backend, name);
144 }
145
146 size_t git_reflog_entrycount(git_reflog *reflog)
147 {
148 assert(reflog);
149 return reflog->entries.length;
150 }
151
152 const git_reflog_entry * git_reflog_entry_byindex(const git_reflog *reflog, size_t idx)
153 {
154 assert(reflog);
155
156 if (idx >= reflog->entries.length)
157 return NULL;
158
159 return git_vector_get(
160 &reflog->entries, reflog_inverse_index(idx, reflog->entries.length));
161 }
162
163 const git_oid * git_reflog_entry_id_old(const git_reflog_entry *entry)
164 {
165 assert(entry);
166 return &entry->oid_old;
167 }
168
169 const git_oid * git_reflog_entry_id_new(const git_reflog_entry *entry)
170 {
171 assert(entry);
172 return &entry->oid_cur;
173 }
174
175 const git_signature * git_reflog_entry_committer(const git_reflog_entry *entry)
176 {
177 assert(entry);
178 return entry->committer;
179 }
180
181 const char * git_reflog_entry_message(const git_reflog_entry *entry)
182 {
183 assert(entry);
184 return entry->msg;
185 }
186
187 int git_reflog_drop(git_reflog *reflog, size_t idx, int rewrite_previous_entry)
188 {
189 size_t entrycount;
190 git_reflog_entry *entry, *previous;
191
192 entrycount = git_reflog_entrycount(reflog);
193
194 entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx);
195
196 if (entry == NULL) {
197 git_error_set(GIT_ERROR_REFERENCE, "no reflog entry at index %"PRIuZ, idx);
198 return GIT_ENOTFOUND;
199 }
200
201 git_reflog_entry__free(entry);
202
203 if (git_vector_remove(
204 &reflog->entries, reflog_inverse_index(idx, entrycount)) < 0)
205 return -1;
206
207 if (!rewrite_previous_entry)
208 return 0;
209
210 /* No need to rewrite anything when removing the most recent entry */
211 if (idx == 0)
212 return 0;
213
214 /* Have the latest entry just been dropped? */
215 if (entrycount == 1)
216 return 0;
217
218 entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx - 1);
219
220 /* If the oldest entry has just been removed... */
221 if (idx == entrycount - 1) {
222 /* ...clear the oid_old member of the "new" oldest entry */
223 if (git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO) < 0)
224 return -1;
225
226 return 0;
227 }
228
229 previous = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx);
230 git_oid_cpy(&entry->oid_old, &previous->oid_cur);
231
232 return 0;
233 }