Commit b976f3c2 by Carlos Martín Nieto

reflog: move the reflog implementation into refdb_fs

References and their logs are logically coupled, let's make it so in
the code by moving the fs-based reflog implementation to live next to
the fs-based refs one.

As part of the change, make the function take names rather than
references, as only the names are relevant when looking up and
handling reflogs.
parent 71e33d26
...@@ -31,10 +31,11 @@ GIT_BEGIN_DECL ...@@ -31,10 +31,11 @@ GIT_BEGIN_DECL
* git_reflog_free(). * git_reflog_free().
* *
* @param out pointer to reflog * @param out pointer to reflog
* @param ref reference to read the reflog for * @param repo the repostiory
* @param name reference to look up
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_reflog_read(git_reflog **out, const git_reference *ref); GIT_EXTERN(int) git_reflog_read(git_reflog **out, git_repository *repo, const char *name);
/** /**
* Write an existing in-memory reflog object back to disk * Write an existing in-memory reflog object back to disk
...@@ -59,26 +60,28 @@ GIT_EXTERN(int) git_reflog_write(git_reflog *reflog); ...@@ -59,26 +60,28 @@ GIT_EXTERN(int) git_reflog_write(git_reflog *reflog);
GIT_EXTERN(int) git_reflog_append(git_reflog *reflog, const git_oid *id, const git_signature *committer, const char *msg); GIT_EXTERN(int) git_reflog_append(git_reflog *reflog, const git_oid *id, const git_signature *committer, const char *msg);
/** /**
* Rename the reflog for the given reference * Rename a reflog
* *
* The reflog to be renamed is expected to already exist * The reflog to be renamed is expected to already exist
* *
* The new name will be checked for validity. * The new name will be checked for validity.
* See `git_reference_create_symbolic()` for rules about valid names. * See `git_reference_create_symbolic()` for rules about valid names.
* *
* @param ref the reference * @param repo the repository
* @param name the new name of the reference * @param old_name the old name of the reference
* @param new_name the new name of the reference
* @return 0 on success, GIT_EINVALIDSPEC or an error code * @return 0 on success, GIT_EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_reflog_rename(git_reference *ref, const char *name); GIT_EXTERN(int) git_reflog_rename(git_repository *repo, const char *old_name, const char *name);
/** /**
* Delete the reflog for the given reference * Delete the reflog for the given reference
* *
* @param ref the reference * @param repo the repository
* @param name the reflog to delete
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_reflog_delete(git_reference *ref); GIT_EXTERN(int) git_reflog_delete(git_repository *repo, const char *name);
/** /**
* Get the number of log entries in a reflog * Get the number of log entries in a reflog
......
...@@ -119,6 +119,38 @@ struct git_refdb_backend { ...@@ -119,6 +119,38 @@ struct git_refdb_backend {
* provide this function; if it is not provided, nothing will be done. * provide this function; if it is not provided, nothing will be done.
*/ */
void (*free)(git_refdb_backend *backend); void (*free)(git_refdb_backend *backend);
/**
* Read the reflog for the given reference name.
*/
int (*reflog_read)(git_reflog **out, git_refdb_backend *backend, const char *name);
/**
* Write a reflog to disk.
*/
int (*reflog_write)(git_refdb_backend *backend, git_reflog *reflog);
/**
* Append an entry to the given reflog
*/
int (*reflog_append)(git_refdb_backend *backend, git_reflog *reflog,
const git_oid *new_oid, const git_signature *committer,
const char *msg);
/**
* Rename a reflog
*/
int (*reflog_rename)(git_refdb_backend *_backend, const char *old_name, const char *new_name);
/**
* Drop an entry from the reflog
*/
int (*reflog_drop)(git_refdb_backend *_backend, git_reflog *reflog,
size_t idx, int rewrite_previous_entry);
/**
* Remove a reflog.
*/
int (*reflog_delete)(git_refdb_backend *backend, const char *name);
}; };
#define GIT_REFDB_BACKEND_VERSION 1 #define GIT_REFDB_BACKEND_VERSION 1
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_sys_git_reflog_h__
#define INCLUDE_sys_git_reflog_h__
#include "git2/common.h"
#include "git2/types.h"
#include "git2/oid.h"
GIT_BEGIN_DECL
GIT_EXTERN(git_reflog_entry *) git_reflog_entry__alloc(void);
GIT_EXTERN(void) git_reflog_entry__free(git_reflog_entry *entry);
GIT_END_DECL
#endif
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "hash.h" #include "hash.h"
#include "refdb.h" #include "refdb.h"
#include "refs.h" #include "refs.h"
#include "reflog.h"
int git_refdb_new(git_refdb **out, git_repository *repo) int git_refdb_new(git_refdb **out, git_repository *repo)
{ {
...@@ -203,3 +204,18 @@ int git_refdb_delete(struct git_refdb *db, const char *ref_name) ...@@ -203,3 +204,18 @@ int git_refdb_delete(struct git_refdb *db, const char *ref_name)
assert(db && db->backend); assert(db && db->backend);
return db->backend->del(db->backend, ref_name); return db->backend->del(db->backend, ref_name);
} }
int git_refdb_reflog_read(git_reflog **out, git_refdb *db, const char *name)
{
int error;
assert(db && db->backend);
if ((error = db->backend->reflog_read(out, db->backend, name)) < 0)
return error;
GIT_REFCOUNT_INC(db);
(*out)->db = db;
return 0;
}
...@@ -43,4 +43,8 @@ void git_refdb_iterator_free(git_reference_iterator *iter); ...@@ -43,4 +43,8 @@ void git_refdb_iterator_free(git_reference_iterator *iter);
int git_refdb_write(git_refdb *refdb, git_reference *ref, int force); int git_refdb_write(git_refdb *refdb, git_reference *ref, int force);
int git_refdb_delete(git_refdb *refdb, const char *ref_name); int git_refdb_delete(git_refdb *refdb, const char *ref_name);
int git_refdb_reflog_read(git_reflog **out, git_refdb *db, const char *name);
int git_refdb_reflog_write(git_reflog *reflog);
#endif #endif
...@@ -27,9 +27,14 @@ struct git_reflog_entry { ...@@ -27,9 +27,14 @@ struct git_reflog_entry {
}; };
struct git_reflog { struct git_reflog {
git_refdb *db;
char *ref_name; char *ref_name;
git_repository *owner;
git_vector entries; git_vector entries;
}; };
GIT_INLINE(size_t) reflog_inverse_index(size_t idx, size_t total)
{
return (total - 1) - idx;
}
#endif /* INCLUDE_reflog_h__ */ #endif /* INCLUDE_reflog_h__ */
...@@ -467,7 +467,7 @@ int git_reference_rename( ...@@ -467,7 +467,7 @@ int git_reference_rename(
if (reference_has_log < 0) if (reference_has_log < 0)
return reference_has_log; return reference_has_log;
if (reference_has_log && (error = git_reflog_rename(ref, new_name)) < 0) if (reference_has_log && (error = git_reflog_rename(git_reference_owner(ref), git_reference_name(ref), new_name)) < 0)
return error; return error;
return 0; return 0;
......
...@@ -160,7 +160,7 @@ static int retrieve_previously_checked_out_branch_or_revision(git_object **out, ...@@ -160,7 +160,7 @@ static int retrieve_previously_checked_out_branch_or_revision(git_object **out,
if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0)
goto cleanup; goto cleanup;
if (git_reflog_read(&reflog, ref) < 0) if (git_reflog_read(&reflog, repo, GIT_HEAD_FILE) < 0)
goto cleanup; goto cleanup;
numentries = git_reflog_entrycount(reflog); numentries = git_reflog_entrycount(reflog);
...@@ -208,7 +208,7 @@ static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t ide ...@@ -208,7 +208,7 @@ static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t ide
const git_reflog_entry *entry; const git_reflog_entry *entry;
bool search_by_pos = (identifier <= 100000000); bool search_by_pos = (identifier <= 100000000);
if (git_reflog_read(&reflog, ref) < 0) if (git_reflog_read(&reflog, git_reference_owner(ref), git_reference_name(ref)) < 0)
return -1; return -1;
numentries = git_reflog_entrycount(reflog); numentries = git_reflog_entrycount(reflog);
......
...@@ -436,14 +436,16 @@ static int update_reflog( ...@@ -436,14 +436,16 @@ static int update_reflog(
const git_signature *stasher, const git_signature *stasher,
const char *message) const char *message)
{ {
git_reference *stash = NULL; git_reference *stash;
git_reflog *reflog = NULL; git_reflog *reflog = NULL;
int error; int error;
if ((error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1)) < 0) if ((error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1)) < 0)
goto cleanup; goto cleanup;
if ((error = git_reflog_read(&reflog, stash)) < 0) git_reference_free(stash);
if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE) < 0))
goto cleanup; goto cleanup;
if ((error = git_reflog_append(reflog, w_commit_oid, stasher, message)) < 0) if ((error = git_reflog_append(reflog, w_commit_oid, stasher, message)) < 0)
...@@ -453,7 +455,6 @@ static int update_reflog( ...@@ -453,7 +455,6 @@ static int update_reflog(
goto cleanup; goto cleanup;
cleanup: cleanup:
git_reference_free(stash);
git_reflog_free(reflog); git_reflog_free(reflog);
return error; return error;
} }
...@@ -599,7 +600,7 @@ int git_stash_foreach( ...@@ -599,7 +600,7 @@ int git_stash_foreach(
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
if ((error = git_reflog_read(&reflog, stash)) < 0) if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
goto cleanup; goto cleanup;
max = git_reflog_entrycount(reflog); max = git_reflog_entrycount(reflog);
...@@ -633,7 +634,7 @@ int git_stash_drop( ...@@ -633,7 +634,7 @@ int git_stash_drop(
if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0) if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
return error; return error;
if ((error = git_reflog_read(&reflog, stash)) < 0) if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0)
goto cleanup; goto cleanup;
max = git_reflog_entrycount(reflog); max = git_reflog_entrycount(reflog);
......
...@@ -8,15 +8,10 @@ static size_t entrycount; ...@@ -8,15 +8,10 @@ static size_t entrycount;
void test_refs_reflog_drop__initialize(void) void test_refs_reflog_drop__initialize(void)
{ {
git_reference *ref;
g_repo = cl_git_sandbox_init("testrepo.git"); g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
git_reflog_read(&g_reflog, ref); git_reflog_read(&g_reflog, g_repo, "HEAD");
entrycount = git_reflog_entrycount(g_reflog); entrycount = git_reflog_entrycount(g_reflog);
git_reference_free(ref);
} }
void test_refs_reflog_drop__cleanup(void) void test_refs_reflog_drop__cleanup(void)
...@@ -106,19 +101,15 @@ void test_refs_reflog_drop__can_drop_all_the_entries(void) ...@@ -106,19 +101,15 @@ void test_refs_reflog_drop__can_drop_all_the_entries(void)
void test_refs_reflog_drop__can_persist_deletion_on_disk(void) void test_refs_reflog_drop__can_persist_deletion_on_disk(void)
{ {
git_reference *ref;
cl_assert(entrycount > 2); cl_assert(entrycount > 2);
cl_git_pass(git_reference_lookup(&ref, g_repo, g_reflog->ref_name));
cl_git_pass(git_reflog_drop(g_reflog, 0, 1)); cl_git_pass(git_reflog_drop(g_reflog, 0, 1));
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
cl_git_pass(git_reflog_write(g_reflog)); cl_git_pass(git_reflog_write(g_reflog));
git_reflog_free(g_reflog); git_reflog_free(g_reflog);
git_reflog_read(&g_reflog, ref); git_reflog_read(&g_reflog, g_repo, "HEAD");
git_reference_free(ref);
cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog));
} }
...@@ -50,7 +50,7 @@ void test_refs_reflog_reflog__append_then_read(void) ...@@ -50,7 +50,7 @@ void test_refs_reflog_reflog__append_then_read(void)
cl_git_pass(git_signature_now(&committer, "foo", "foo@bar")); cl_git_pass(git_signature_now(&committer, "foo", "foo@bar"));
cl_git_pass(git_reflog_read(&reflog, ref)); cl_git_pass(git_reflog_read(&reflog, g_repo, new_ref));
cl_git_fail(git_reflog_append(reflog, &oid, committer, "no inner\nnewline")); cl_git_fail(git_reflog_append(reflog, &oid, committer, "no inner\nnewline"));
cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL)); cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL));
...@@ -65,7 +65,7 @@ void test_refs_reflog_reflog__append_then_read(void) ...@@ -65,7 +65,7 @@ void test_refs_reflog_reflog__append_then_read(void)
cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref)); cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref));
/* Read and parse the reflog for this branch */ /* Read and parse the reflog for this branch */
cl_git_pass(git_reflog_read(&reflog, lookedup_ref)); cl_git_pass(git_reflog_read(&reflog, repo2, new_ref));
cl_assert_equal_i(2, (int)git_reflog_entrycount(reflog)); cl_assert_equal_i(2, (int)git_reflog_entrycount(reflog));
entry = git_reflog_entry_byindex(reflog, 1); entry = git_reflog_entry_byindex(reflog, 1);
...@@ -133,21 +133,18 @@ void test_refs_reflog_reflog__reference_has_reflog(void) ...@@ -133,21 +133,18 @@ void test_refs_reflog_reflog__reference_has_reflog(void)
void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_returns_an_empty_one(void) void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_returns_an_empty_one(void)
{ {
git_reference *subtrees;
git_reflog *reflog; git_reflog *reflog;
const char *refname = "refs/heads/subtrees";
git_buf subtrees_log_path = GIT_BUF_INIT; git_buf subtrees_log_path = GIT_BUF_INIT;
cl_git_pass(git_reference_lookup(&subtrees, g_repo, "refs/heads/subtrees")); git_buf_join_n(&subtrees_log_path, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname);
git_buf_join_n(&subtrees_log_path, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, git_reference_name(subtrees));
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&subtrees_log_path))); cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&subtrees_log_path)));
cl_git_pass(git_reflog_read(&reflog, subtrees)); cl_git_pass(git_reflog_read(&reflog, g_repo, refname));
cl_assert_equal_i(0, (int)git_reflog_entrycount(reflog)); cl_assert_equal_i(0, (int)git_reflog_entrycount(reflog));
git_reflog_free(reflog); git_reflog_free(reflog);
git_reference_free(subtrees);
git_buf_free(&subtrees_log_path); git_buf_free(&subtrees_log_path);
} }
...@@ -158,7 +155,7 @@ void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void) ...@@ -158,7 +155,7 @@ void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void)
git_reflog *reflog; git_reflog *reflog;
cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master")); cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
cl_git_pass(git_reflog_read(&reflog, master)); cl_git_pass(git_reflog_read(&reflog, g_repo, "refs/heads/master"));
cl_git_pass(git_reflog_write(reflog)); cl_git_pass(git_reflog_write(reflog));
...@@ -175,12 +172,6 @@ void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void) ...@@ -175,12 +172,6 @@ void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void)
void test_refs_reflog_reflog__renaming_with_an_invalid_name_returns_EINVALIDSPEC(void) void test_refs_reflog_reflog__renaming_with_an_invalid_name_returns_EINVALIDSPEC(void)
{ {
git_reference *master;
cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
cl_assert_equal_i(GIT_EINVALIDSPEC, cl_assert_equal_i(GIT_EINVALIDSPEC,
git_reflog_rename(master, "refs/heads/Inv@{id")); git_reflog_rename(g_repo, "refs/heads/master", "refs/heads/Inv@{id"));
git_reference_free(master);
} }
...@@ -102,7 +102,7 @@ void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void) ...@@ -102,7 +102,7 @@ void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void)
cl_git_pass(git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)); cl_git_pass(git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE));
cl_git_pass(git_reflog_read(&reflog, stash)); cl_git_pass(git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE));
entry = git_reflog_entry_byindex(reflog, 1); entry = git_reflog_entry_byindex(reflog, 1);
git_oid_cpy(&oid, git_reflog_entry_id_old(entry)); git_oid_cpy(&oid, git_reflog_entry_id_old(entry));
...@@ -112,7 +112,7 @@ void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void) ...@@ -112,7 +112,7 @@ void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void)
cl_git_pass(git_stash_drop(repo, 1)); cl_git_pass(git_stash_drop(repo, 1));
cl_git_pass(git_reflog_read(&reflog, stash)); cl_git_pass(git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE));
entry = git_reflog_entry_byindex(reflog, 0); entry = git_reflog_entry_byindex(reflog, 0);
cl_assert_equal_i(0, git_oid_cmp(&oid, git_reflog_entry_id_old(entry))); cl_assert_equal_i(0, git_oid_cmp(&oid, git_reflog_entry_id_old(entry)));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment