Commit e226ad8f2fd76211809cf7b381fb55bb600df82f

Etienne Samson 2018-11-17T17:55:10

refs: add support for core.logAllRefUpdates=always Since we were not expecting this config entry to contain a string, we would fail as soon as its (cached) value would be accessed. Hence, provide some constants for the 4 states we use, and account for "always" when we decide to reflog changes.

diff --git a/src/config_cache.c b/src/config_cache.c
index 0efb1a7..2530217 100644
--- a/src/config_cache.c
+++ b/src/config_cache.c
@@ -58,6 +58,12 @@ static git_cvar_map _cvar_map_safecrlf[] = {
 	{GIT_CVAR_STRING, "warn", GIT_SAFE_CRLF_WARN}
 };
 
+static git_cvar_map _cvar_map_logallrefupdates[] = {
+	{GIT_CVAR_FALSE, NULL, GIT_LOGALLREFUPDATES_FALSE},
+	{GIT_CVAR_TRUE, NULL, GIT_LOGALLREFUPDATES_TRUE},
+	{GIT_CVAR_STRING, "always", GIT_LOGALLREFUPDATES_ALWAYS},
+};
+
 /*
  * Generic map for integer values
  */
@@ -76,7 +82,7 @@ static struct map_data _cvar_maps[] = {
 	{"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT },
 	{"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT },
 	{"core.safecrlf", _cvar_map_safecrlf, ARRAY_SIZE(_cvar_map_safecrlf), GIT_SAFE_CRLF_DEFAULT},
-	{"core.logallrefupdates", NULL, 0, GIT_LOGALLREFUPDATES_DEFAULT },
+	{"core.logallrefupdates", _cvar_map_logallrefupdates, ARRAY_SIZE(_cvar_map_logallrefupdates), GIT_LOGALLREFUPDATES_DEFAULT},
 	{"core.protecthfs", NULL, 0, GIT_PROTECTHFS_DEFAULT },
 	{"core.protectntfs", NULL, 0, GIT_PROTECTNTFS_DEFAULT },
 	{"core.fsyncobjectfiles", NULL, 0, GIT_FSYNCOBJECTFILES_DEFAULT },
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 49b567c..49fc292 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -1090,7 +1090,6 @@ fail:
 static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, 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 int should_write_reflog(int *write, git_repository *repo, const char *name)
 {
 	int error, logall;
@@ -1103,17 +1102,26 @@ static int should_write_reflog(int *write, git_repository *repo, const char *nam
 	if (logall == GIT_LOGALLREFUPDATES_UNSET)
 		logall = !git_repository_is_bare(repo);
 
-	if (!logall) {
+	*write = 0;
+	switch (logall) {
+	case GIT_LOGALLREFUPDATES_FALSE:
 		*write = 0;
-	} else if (has_reflog(repo, name)) {
-		*write = 1;
-	} else 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)) {
+		break;
+
+	case GIT_LOGALLREFUPDATES_TRUE:
+		/* Only write if it already has a log,
+		 * or if it's under heads/, remotes/ or notes/
+		 */
+		*write = has_reflog(repo, name) ||
+			!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);
+		break;
+
+	case GIT_LOGALLREFUPDATES_ALWAYS:
 		*write = 1;
-	} else {
-		*write = 0;
+		break;
 	}
 
 	return 0;
@@ -1713,7 +1721,7 @@ static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, 
 	if ((error == GIT_ENOTFOUND) &&
 		((error = create_new_reflog_file(git_buf_cstr(&log_path))) < 0))
 		goto cleanup;
- 
+
 	if ((error = reflog_parse(log,
 		git_buf_cstr(&log_file), git_buf_len(&log_file))) < 0)
 		goto cleanup;
@@ -1973,7 +1981,7 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_
 		goto cleanup;
 	}
 
-	if (git_path_isdir(git_buf_cstr(&new_path)) && 
+	if (git_path_isdir(git_buf_cstr(&new_path)) &&
 		(git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
 		error = -1;
 		goto cleanup;
diff --git a/src/repository.h b/src/repository.h
index fd6400c..1a72717 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -105,7 +105,10 @@ typedef enum {
 	/* core.safecrlf */
 	GIT_SAFE_CRLF_DEFAULT = GIT_CVAR_FALSE,
 	/* core.logallrefupdates */
+	GIT_LOGALLREFUPDATES_FALSE = GIT_CVAR_FALSE,
+	GIT_LOGALLREFUPDATES_TRUE = GIT_CVAR_TRUE,
 	GIT_LOGALLREFUPDATES_UNSET = 2,
+	GIT_LOGALLREFUPDATES_ALWAYS = 3,
 	GIT_LOGALLREFUPDATES_DEFAULT = GIT_LOGALLREFUPDATES_UNSET,
 	/* core.protectHFS */
 	GIT_PROTECTHFS_DEFAULT = GIT_CVAR_FALSE,
diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c
index ec251da..3a6c97c 100644
--- a/tests/refs/reflog/reflog.c
+++ b/tests/refs/reflog/reflog.c
@@ -422,6 +422,28 @@ void test_refs_reflog_reflog__logallrefupdates_bare_set_false(void)
 	assert_no_reflog_update();
 }
 
+void test_refs_reflog_reflog__logallrefupdates_bare_set_always(void)
+{
+	git_config *config;
+	git_reference *ref;
+	git_reflog *log;
+	git_oid id;
+
+	cl_git_pass(git_repository_config(&config, g_repo));
+	cl_git_pass(git_config_set_string(config, "core.logallrefupdates", "always"));
+	git_config_free(config);
+
+	git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
+	cl_git_pass(git_reference_create(&ref, g_repo, "refs/bork", &id, 1, "message"));
+
+	cl_git_pass(git_reflog_read(&log, g_repo, "refs/bork"));
+	cl_assert_equal_i(1, git_reflog_entrycount(log));
+	cl_assert_equal_s("message", git_reflog_entry_byindex(log, 0)->msg);
+
+	git_reflog_free(log);
+	git_reference_free(ref);
+}
+
 void test_refs_reflog_reflog__logallrefupdates_bare_unset(void)
 {
 	git_config *config;