refs: expose a way to ensure a ref has a log Sometimes (e.g. stash) we want to make sure that a log will be written, even if it's not in one of the standard locations. Let's make that easier.
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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 2dc1376..31bf997 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -556,6 +556,18 @@ GIT_EXTERN(int) git_reference_foreach_glob(
GIT_EXTERN(int) git_reference_has_log(git_reference *ref);
/**
+ * Ensure there is a reflog for a particular reference.
+ *
+ * Make sure that successive updates to the reference will append to
+ * its log.
+ *
+ * @param repo the repository
+ * @param refname the reference's name
+ * @return 0 or an error code.
+ */
+GIT_EXTERN(int) git_reference_ensure_log(git_repository *repo, const char *refname);
+
+/**
* Check if a reference is a local branch.
*
* @param ref A git reference
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h
index 131e1b5..1485ed7 100644
--- a/include/git2/sys/refdb_backend.h
+++ b/include/git2/sys/refdb_backend.h
@@ -117,6 +117,12 @@ struct git_refdb_backend {
int (*compress)(git_refdb_backend *backend);
/**
+ * Make sure a particular reference will have a reflog which
+ * will be appended to on writes.
+ */
+ int (*ensure_log)(git_refdb_backend *backend, const char *refname);
+
+ /**
* Frees any resources held by the refdb. A refdb implementation may
* provide this function; if it is not provided, nothing will be done.
*/
diff --git a/src/refdb.c b/src/refdb.c
index bc8c2b3..4f3169f 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -221,3 +221,10 @@ int git_refdb_reflog_read(git_reflog **out, git_refdb *db, const char *name)
return 0;
}
+
+int git_refdb_ensure_log(git_refdb *db, const char *refname)
+{
+ assert(db && refname);
+
+ return db->backend->ensure_log(db->backend, refname);
+}
diff --git a/src/refdb.h b/src/refdb.h
index 215ae17..12c15cb 100644
--- a/src/refdb.h
+++ b/src/refdb.h
@@ -48,5 +48,8 @@ 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);
+int git_refdb_ensure_log(git_refdb *refdb, const char *refname);
+
+
#endif
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 9f23de2..2cdea82 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -1233,7 +1233,7 @@ static int create_new_reflog_file(const char *filepath)
return error;
if ((fd = p_open(filepath,
- O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT,
GIT_REFLOG_FILE_MODE)) < 0)
return -1;
@@ -1245,6 +1245,24 @@ GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const
return git_buf_join_n(path, '/', 3, repo->path_repository, GIT_REFLOG_DIR, name);
}
+static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
+{
+ refdb_fs_backend *backend;
+ git_repository *repo;
+ git_buf path = GIT_BUF_INIT;
+ int error;
+
+ assert(_backend && name);
+
+ backend = (refdb_fs_backend *) _backend;
+ repo = backend->repo;
+
+ if ((error = retrieve_reflog_path(&path, repo, name)) < 0)
+ return error;
+
+ return create_new_reflog_file(git_buf_cstr(&path));
+}
+
static int has_reflog(git_repository *repo, const char *name)
{
int ret = 0;
@@ -1590,6 +1608,7 @@ int git_refdb_backend_fs(
backend->parent.del = &refdb_fs_backend__delete;
backend->parent.rename = &refdb_fs_backend__rename;
backend->parent.compress = &refdb_fs_backend__compress;
+ backend->parent.ensure_log = &refdb_reflog_fs__ensure_log;
backend->parent.free = &refdb_fs_backend__free;
backend->parent.reflog_read = &refdb_reflog_fs__read;
backend->parent.reflog_write = &refdb_reflog_fs__write;
diff --git a/src/refs.c b/src/refs.c
index 598d687..902a17c 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -1068,6 +1068,19 @@ int git_reference_has_log(
return result;
}
+int git_reference_ensure_log(git_repository *repo, const char *refname)
+{
+ int error;
+ git_refdb *refdb;
+
+ assert(repo && refname);
+
+ if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
+ return error;
+
+ return git_refdb_ensure_log(refdb, refname);
+}
+
int git_reference__is_branch(const char *ref_name)
{
return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0;
diff --git a/src/stash.c b/src/stash.c
index 66b1cd7..7d7bf78 100644
--- a/src/stash.c
+++ b/src/stash.c
@@ -414,6 +414,9 @@ static int update_reflog(
git_reference *stash;
int error;
+ if ((error = git_reference_ensure_log(repo, GIT_REFS_STASH_FILE)) < 0)
+ return error;
+
error = git_reference_create_with_log(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1, stasher, message);
git_reference_free(stash);
diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c
index 6c9375d..9f414f2 100644
--- a/tests/refs/reflog/reflog.c
+++ b/tests/refs/reflog/reflog.c
@@ -212,12 +212,9 @@ void test_refs_reflog_reflog__write_when_explicitly_active(void)
{
git_reference *ref;
git_oid id;
- git_buf path = GIT_BUF_INIT;
git_oid_fromstr(&id, current_master_tip);
- cl_git_pass(git_buf_join(&path, '/', git_repository_path(g_repo), "logs/refs/tags/foo"));
- cl_git_pass(git_futils_mkpath2file(git_buf_cstr(&path), 0777));
- cl_git_mkfile(git_buf_cstr(&path), "");
+ git_reference_ensure_log(g_repo, "refs/tags/foo");
cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1));
git_reference_free(ref);