mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
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.
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user