diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 2f7b43401..9f23de248 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 80c7703fc..4d5b6dacb 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 9ac15d556..6c9375dc7 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"); +}