reflog: write to the reflog following git's rules git-core only writes to the reflogs of HEAD, refs/heads/ and, refs/notes/ or if there is already a reflog in place. Adjust our code to follow these semantics.
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
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 2f7b434..9f23de2 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -911,6 +911,22 @@ fail:
}
static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_signature *author, const char *message);
+static int has_reflog(git_repository *repo, const char *name);
+
+/* We only write if it's under heads/, remotes/ or notes/ or if it already has a log */
+static bool should_write_reflog(git_repository *repo, const char *name)
+{
+ if (has_reflog(repo, name))
+ return 1;
+
+ if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR) ||
+ !git__strcmp(name, GIT_HEAD_FILE) ||
+ !git__prefixcmp(name, GIT_REFS_REMOTES_DIR) ||
+ !git__prefixcmp(name, GIT_REFS_NOTES_DIR))
+ return 1;
+
+ return 0;
+}
static int refdb_fs_backend__write(
git_refdb_backend *_backend,
@@ -933,7 +949,8 @@ static int refdb_fs_backend__write(
if ((error = loose_lock(&file, backend, ref)) < 0)
return error;
- if ((error = reflog_append(backend, ref, who, message)) < 0) {
+ if (should_write_reflog(backend->repo, ref->name) &&
+ (error = reflog_append(backend, ref, who, message)) < 0) {
git_filebuf_cleanup(&file);
return error;
}
@@ -1228,6 +1245,21 @@ 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 has_reflog(git_repository *repo, const char *name)
+{
+ int ret = 0;
+ git_buf path = GIT_BUF_INIT;
+
+ if (retrieve_reflog_path(&path, repo, name) < 0)
+ goto cleanup;
+
+ ret = git_path_isfile(git_buf_cstr(&path));
+
+cleanup:
+ git_buf_free(&path);
+ return ret;
+}
+
static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, const char *name)
{
int error = -1;
@@ -1338,7 +1370,6 @@ static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflo
int error = -1;
unsigned int i;
git_reflog_entry *entry;
- git_repository *repo;
refdb_fs_backend *backend;
git_buf log = GIT_BUF_INIT;
git_filebuf fbuf = GIT_FILEBUF_INIT;
@@ -1346,7 +1377,6 @@ static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflo
assert(_backend && reflog);
backend = (refdb_fs_backend *) _backend;
- repo = backend->repo;
if ((error = lock_reflog(&fbuf, backend, reflog->ref_name)) < 0)
return -1;
diff --git a/src/refs.h b/src/refs.h
index 80c7703..4d5b6da 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -19,6 +19,7 @@
#define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"
#define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/"
#define GIT_REFS_REMOTES_DIR GIT_REFS_DIR "remotes/"
+#define GIT_REFS_NOTES_DIR GIT_REFS_DIR "notes/"
#define GIT_REFS_DIR_MODE 0777
#define GIT_REFS_FILE_MODE 0666
diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c
index 9ac15d5..6c9375d 100644
--- a/tests/refs/reflog/reflog.c
+++ b/tests/refs/reflog/reflog.c
@@ -187,3 +187,39 @@ void test_refs_reflog_reflog__renaming_with_an_invalid_name_returns_EINVALIDSPEC
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_reflog_rename(g_repo, "refs/heads/master", "refs/heads/Inv@{id"));
}
+
+void test_refs_reflog_reflog__write_only_std_locations(void)
+{
+ git_reference *ref;
+ git_oid id;
+
+ git_oid_fromstr(&id, current_master_tip);
+
+ cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/foo", &id, 1));
+ git_reference_free(ref);
+ cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1));
+ git_reference_free(ref);
+ cl_git_pass(git_reference_create(&ref, g_repo, "refs/notes/foo", &id, 1));
+ git_reference_free(ref);
+
+ assert_has_reflog(true, "refs/heads/foo");
+ assert_has_reflog(false, "refs/tags/foo");
+ assert_has_reflog(true, "refs/notes/foo");
+
+}
+
+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), "");
+
+ cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1));
+ git_reference_free(ref);
+ assert_has_reflog(true, "refs/tags/foo");
+}