Commit bfa1f022 by Edward Thomson

settings: optional unsaved index safety

Add the `GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY` option, which will cause
commands that reload the on-disk index to fail if the current
`git_index` has changed that have not been saved.  This will prevent
users from - for example - adding a file to the index then calling a
function like `git_checkout` and having that file be silently removed
from the index since it was re-read from disk.

Now calls that would re-read the index will fail if the index is
"dirty", meaning changes have been made to it but have not been written.
Users can either `git_index_read` to discard those changes explicitly,
or `git_index_write` to write them.
parent 787768c2
......@@ -194,7 +194,8 @@ typedef enum {
GIT_OPT_GET_WINDOWS_SHAREMODE,
GIT_OPT_SET_WINDOWS_SHAREMODE,
GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION,
GIT_OPT_SET_ALLOCATOR
GIT_OPT_SET_ALLOCATOR,
GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY
} git_libgit2_opt_t;
/**
......@@ -363,6 +364,14 @@ typedef enum {
* > allocator will then be used to make all memory allocations for
* > libgit2 operations.
*
* opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, int enabled)
*
* > Ensure that there are no unsaved changes in the index before
* > beginning any operation that reloads the index from disk (eg,
* > checkout). If there are unsaved changes, the instruction will
* > fail. (Using the FORCE flag to checkout will still overwrite
* > these changes.)
*
* @param option Option key
* @param ... value to set the option
* @return 0 on success, <0 on failure
......
......@@ -135,6 +135,8 @@ struct reuc_entry_internal {
char path[GIT_FLEX_ARRAY];
};
bool git_index__enforce_unsaved_safety = false;
/* local declarations */
static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size);
static int read_header(struct index_header *dest, const void *buffer);
......@@ -682,7 +684,7 @@ int git_index_read(git_index *index, int force)
int git_index_read_safely(git_index *index)
{
if (index->dirty) {
if (git_index__enforce_unsaved_safety && index->dirty) {
giterr_set(GITERR_INDEX,
"the index has unsaved changes that would be overwritten by this operation");
return GIT_EINDEXDIRTY;
......
......@@ -20,6 +20,8 @@
#define GIT_INDEX_FILE "index"
#define GIT_INDEX_FILE_MODE 0666
extern bool git_index__enforce_unsaved_safety;
struct git_index {
git_refcount rc;
......
......@@ -23,6 +23,7 @@
#include "object.h"
#include "odb.h"
#include "refs.h"
#include "index.h"
#include "transports/smart.h"
#include "streams/openssl.h"
#include "streams/mbedtls.h"
......@@ -265,6 +266,10 @@ int git_libgit2_opts(int key, ...)
error = git_allocator_setup(va_arg(ap, git_allocator *));
break;
case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY:
git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
break;
default:
giterr_set(GITERR_INVALID, "invalid option key");
error = -1;
......
......@@ -72,6 +72,11 @@ void test_index_tests__initialize(void)
{
}
void test_index_tests__cleanup(void)
{
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, 0));
}
void test_index_tests__empty_index(void)
{
git_index *index;
......@@ -384,7 +389,7 @@ void test_index_tests__dirty_and_clean(void)
git_repository_free(repo);
}
void test_index_tests__dirty_fails_with_error(void)
void test_index_tests__dirty_fails_optionally(void)
{
git_repository *repo;
git_index *index;
......@@ -400,6 +405,15 @@ void test_index_tests__dirty_fails_with_error(void)
cl_git_pass(git_index_add_frombuffer(index, &entry, "Hi.\n", 4));
cl_assert(git_index_is_dirty(index));
cl_git_pass(git_checkout_head(repo, NULL));
/* Index is dirty (again) after adding an entry */
entry.mode = GIT_FILEMODE_BLOB;
entry.path = "test.txt";
cl_git_pass(git_index_add_frombuffer(index, &entry, "Hi.\n", 4));
cl_assert(git_index_is_dirty(index));
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, 1));
cl_git_fail_with(GIT_EINDEXDIRTY, git_checkout_head(repo, NULL));
git_index_free(index);
......
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