Skip to content

Commit 1f39593

Browse files
committed
refdb: extract function to check whether to append HEAD to the reflog
The logic to determine whether a reflog entry should be for the HEAD reference is non-trivial. Currently, the only user of this is the filesystem-based refdb, but with the advent of the reftable refdb we're going to add a second user that's interested in having the same behaviour. Let's pull out a new function that checks whether a given reference should cause a entry to be written to the HEAD reflog as a preparatory step.
1 parent e02478b commit 1f39593

File tree

3 files changed

+78
-39
lines changed

3 files changed

+78
-39
lines changed

src/refdb.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,55 @@ int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference *
268268
return 0;
269269
}
270270

271+
int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_reference *ref)
272+
{
273+
git_reference *head = NULL, *peeled = NULL;
274+
const char *name;
275+
int error;
276+
277+
*out = 0;
278+
279+
if (ref->type == GIT_REFERENCE_SYMBOLIC) {
280+
error = 0;
281+
goto out;
282+
}
283+
284+
if ((error = git_refdb_lookup(&head, db, GIT_HEAD_FILE)) < 0)
285+
goto out;
286+
287+
if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
288+
goto out;
289+
290+
/* Go down the symref chain until we find the branch */
291+
while (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC) {
292+
if ((error = git_refdb_lookup(&peeled, db, git_reference_symbolic_target(head))) < 0)
293+
break;
294+
295+
git_reference_free(head);
296+
head = peeled;
297+
peeled = NULL;
298+
}
299+
300+
if (error < 0) {
301+
if (error != GIT_ENOTFOUND)
302+
goto out;
303+
error = 0;
304+
name = git_reference_symbolic_target(head);
305+
} else {
306+
name = git_reference_name(head);
307+
}
308+
309+
if (strcmp(name, ref->name))
310+
goto out;
311+
312+
*out = 1;
313+
314+
out:
315+
git_reference_free(peeled);
316+
git_reference_free(head);
317+
return error;
318+
}
319+
271320
int git_refdb_has_log(git_refdb *db, const char *refname)
272321
{
273322
assert(db && refname);

src/refdb.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ int git_refdb_reflog_write(git_reflog *reflog);
7878
*/
7979
int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference *ref);
8080

81+
/**
82+
* Determine whether a reflog entry should be created for HEAD if creating one
83+
* for the given reference
84+
*
85+
* In case the given reference is being pointed to by HEAD, then creating a
86+
* reflog entry for this reference also requires us to create a corresponding
87+
* reflog entry for HEAD. This function can be used to determine that scenario.
88+
*
89+
* @param out pointer to which the result will be written, `1` means a reflog
90+
* entry should be written, `0` means none should be written.
91+
* @param db The refdb to decide this for.
92+
* @param ref The reference one wants to check.
93+
* @return `0` on success, a negative error code otherwise.
94+
*/
95+
int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_reference *ref);
96+
8197
int git_refdb_has_log(git_refdb *db, const char *refname);
8298
int git_refdb_ensure_log(git_refdb *refdb, const char *refname);
8399

src/refdb_fs.c

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,54 +1181,28 @@ static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name,
11811181
*/
11821182
static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message)
11831183
{
1184-
int error;
1184+
git_reference *head = NULL;
1185+
git_refdb *refdb = NULL;
1186+
int error, write_reflog;
11851187
git_oid old_id;
1186-
git_reference *tmp = NULL, *head = NULL, *peeled = NULL;
1187-
const char *name;
11881188

1189-
if (ref->type == GIT_REFERENCE_SYMBOLIC)
1190-
return 0;
1189+
if ((error = git_repository_refdb(&refdb, backend->repo)) < 0 ||
1190+
(error = git_refdb_should_write_head_reflog(&write_reflog, refdb, ref)) < 0)
1191+
goto out;
1192+
if (!write_reflog)
1193+
goto out;
11911194

11921195
/* if we can't resolve, we use {0}*40 as old id */
11931196
if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0)
11941197
memset(&old_id, 0, sizeof(old_id));
11951198

1196-
if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0)
1197-
return error;
1198-
1199-
if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
1200-
goto cleanup;
1201-
1202-
if ((error = git_reference_lookup(&tmp, backend->repo, GIT_HEAD_FILE)) < 0)
1203-
goto cleanup;
1204-
1205-
/* Go down the symref chain until we find the branch */
1206-
while (git_reference_type(tmp) == GIT_REFERENCE_SYMBOLIC) {
1207-
error = git_reference_lookup(&peeled, backend->repo, git_reference_symbolic_target(tmp));
1208-
if (error < 0)
1209-
break;
1210-
1211-
git_reference_free(tmp);
1212-
tmp = peeled;
1213-
}
1214-
1215-
if (error == GIT_ENOTFOUND) {
1216-
error = 0;
1217-
name = git_reference_symbolic_target(tmp);
1218-
} else if (error < 0) {
1219-
goto cleanup;
1220-
} else {
1221-
name = git_reference_name(tmp);
1222-
}
1223-
1224-
if (strcmp(name, ref->name))
1225-
goto cleanup;
1226-
1227-
error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message);
1199+
if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0 ||
1200+
(error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message)) < 0)
1201+
goto out;
12281202

1229-
cleanup:
1230-
git_reference_free(tmp);
1203+
out:
12311204
git_reference_free(head);
1205+
git_refdb_free(refdb);
12321206
return error;
12331207
}
12341208

0 commit comments

Comments
 (0)