Commit 629b661c by Edward Thomson

checkout (from index) can write conflicts

parent 3acf44d6
...@@ -131,6 +131,13 @@ typedef enum { ...@@ -131,6 +131,13 @@ typedef enum {
/** Don't refresh index/config/etc before doing checkout */ /** Don't refresh index/config/etc before doing checkout */
GIT_CHECKOUT_NO_REFRESH = (1u << 9), GIT_CHECKOUT_NO_REFRESH = (1u << 9),
/** Allow checkout to skip unmerged files */
GIT_CHECKOUT_SKIP_UNMERGED = (1u << 10),
/** For unmerged files, checkout stage 2 from index */
GIT_CHECKOUT_USE_OURS = (1u << 11),
/** For unmerged files, checkout stage 3 from index */
GIT_CHECKOUT_USE_THEIRS = (1u << 12),
/** Treat pathspec as simple list of exact match file paths */ /** Treat pathspec as simple list of exact match file paths */
GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13), GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13),
...@@ -141,13 +148,6 @@ typedef enum { ...@@ -141,13 +148,6 @@ typedef enum {
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
*/ */
/** Allow checkout to skip unmerged files (NOT IMPLEMENTED) */
GIT_CHECKOUT_SKIP_UNMERGED = (1u << 10),
/** For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED) */
GIT_CHECKOUT_USE_OURS = (1u << 11),
/** For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED) */
GIT_CHECKOUT_USE_THEIRS = (1u << 12),
/** Recursively checkout submodules with same options (NOT IMPLEMENTED) */ /** Recursively checkout submodules with same options (NOT IMPLEMENTED) */
GIT_CHECKOUT_UPDATE_SUBMODULES = (1u << 16), GIT_CHECKOUT_UPDATE_SUBMODULES = (1u << 16),
/** Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) */ /** Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) */
...@@ -238,6 +238,9 @@ typedef struct git_checkout_opts { ...@@ -238,6 +238,9 @@ typedef struct git_checkout_opts {
git_tree *baseline; /** expected content of workdir, defaults to HEAD */ git_tree *baseline; /** expected content of workdir, defaults to HEAD */
const char *target_directory; /** alternative checkout path to workdir */ const char *target_directory; /** alternative checkout path to workdir */
const char *our_label; /** the name of the "our" side of conflicts */
const char *their_label; /** the name of the "their" side of conflicts */
} git_checkout_opts; } git_checkout_opts;
#define GIT_CHECKOUT_OPTS_VERSION 1 #define GIT_CHECKOUT_OPTS_VERSION 1
......
...@@ -41,24 +41,6 @@ enum { ...@@ -41,24 +41,6 @@ enum {
(CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE), (CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
}; };
typedef struct {
git_repository *repo;
git_diff_list *diff;
git_checkout_opts opts;
bool opts_free_baseline;
char *pfx;
git_index *index;
git_pool pool;
git_vector removes;
git_buf path;
size_t workdir_len;
unsigned int strategy;
int can_symlink;
bool reload_submodules;
size_t total_steps;
size_t completed_steps;
} checkout_data;
static int checkout_notify( static int checkout_notify(
checkout_data *data, checkout_data *data,
git_checkout_notify_t why, git_checkout_notify_t why,
...@@ -707,6 +689,7 @@ static int blob_content_to_file( ...@@ -707,6 +689,7 @@ static int blob_content_to_file(
struct stat *st, struct stat *st,
git_blob *blob, git_blob *blob,
const char *path, const char *path,
const char * hint_path,
mode_t entry_filemode, mode_t entry_filemode,
git_checkout_opts *opts) git_checkout_opts *opts)
{ {
...@@ -715,9 +698,12 @@ static int blob_content_to_file( ...@@ -715,9 +698,12 @@ static int blob_content_to_file(
git_buf out = GIT_BUF_INIT; git_buf out = GIT_BUF_INIT;
git_filter_list *fl = NULL; git_filter_list *fl = NULL;
if (hint_path == NULL)
hint_path = path;
if (!opts->disable_filters) if (!opts->disable_filters)
error = git_filter_list_load( error = git_filter_list_load(
&fl, git_blob_owner(blob), blob, path, GIT_FILTER_TO_WORKTREE); &fl, git_blob_owner(blob), blob, hint_path, GIT_FILTER_TO_WORKTREE);
if (!error) if (!error)
error = git_filter_list_apply_to_blob(&out, fl, blob); error = git_filter_list_apply_to_blob(&out, fl, blob);
...@@ -886,34 +872,26 @@ static int checkout_safe_for_update_only(const char *path, mode_t expected_mode) ...@@ -886,34 +872,26 @@ static int checkout_safe_for_update_only(const char *path, mode_t expected_mode)
return 0; return 0;
} }
static int checkout_blob( int git_checkout__write_content(
checkout_data *data, checkout_data *data,
const git_diff_file *file) const git_oid *oid,
const char *full_path,
const char *hint_path,
unsigned int mode,
struct stat *st)
{ {
int error = 0; int error = 0;
git_blob *blob; git_blob *blob;
struct stat st;
git_buf_truncate(&data->path, data->workdir_len);
if (git_buf_puts(&data->path, file->path) < 0)
return -1;
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
int rval = checkout_safe_for_update_only(
git_buf_cstr(&data->path), file->mode);
if (rval <= 0)
return rval;
}
if ((error = git_blob_lookup(&blob, data->repo, &file->oid)) < 0) if ((error = git_blob_lookup(&blob, data->repo, oid)) < 0)
return error; return error;
if (S_ISLNK(file->mode)) if (S_ISLNK(mode))
error = blob_content_to_link( error = blob_content_to_link(
&st, blob, git_buf_cstr(&data->path), data->opts.dir_mode, data->can_symlink); st, blob, full_path, data->opts.dir_mode, data->can_symlink);
else else
error = blob_content_to_file( error = blob_content_to_file(
&st, blob, git_buf_cstr(&data->path), file->mode, &data->opts); st, blob, full_path, hint_path, mode, &data->opts);
git_blob_free(blob); git_blob_free(blob);
...@@ -928,6 +906,30 @@ static int checkout_blob( ...@@ -928,6 +906,30 @@ static int checkout_blob(
error = 0; error = 0;
} }
return error;
}
static int checkout_blob(
checkout_data *data,
const git_diff_file *file)
{
int error = 0;
struct stat st;
git_buf_truncate(&data->path, data->workdir_len);
if (git_buf_puts(&data->path, file->path) < 0)
return -1;
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
int rval = checkout_safe_for_update_only(
git_buf_cstr(&data->path), file->mode);
if (rval <= 0)
return rval;
}
error = git_checkout__write_content(
data, &file->oid, git_buf_cstr(&data->path), NULL, file->mode, &st);
/* update the index unless prevented */ /* update the index unless prevented */
if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
error = checkout_update_index(data, file, &st); error = checkout_update_index(data, file, &st);
...@@ -1172,7 +1174,17 @@ static int checkout_data_init( ...@@ -1172,7 +1174,17 @@ static int checkout_data_init(
(error = git_index_read(data->index)) < 0) (error = git_index_read(data->index)) < 0)
goto cleanup; goto cleanup;
/* clear the REUC when doing a tree or commit checkout */ /* cannot checkout if unresolved conflicts exist */
if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) == 0 &&
git_index_has_conflicts(data->index)) {
error = GIT_EMERGECONFLICT;
giterr_set(GITERR_CHECKOUT,
"unresolved conflicts exist in the index");
goto cleanup;
}
/* clean conflict data when doing a tree or commit checkout */
git_index_name_clear(data->index);
git_index_reuc_clear(data->index); git_index_reuc_clear(data->index);
} }
} }
...@@ -1312,6 +1324,9 @@ int git_checkout_iterator( ...@@ -1312,6 +1324,9 @@ int git_checkout_iterator(
assert(data.completed_steps == data.total_steps); assert(data.completed_steps == data.total_steps);
/* Write conflict data to disk */
error = git_checkout__conflicts(&data);
cleanup: cleanup:
if (error == GIT_EUSER) if (error == GIT_EUSER)
giterr_clear(); giterr_clear();
......
...@@ -9,9 +9,28 @@ ...@@ -9,9 +9,28 @@
#include "git2/checkout.h" #include "git2/checkout.h"
#include "iterator.h" #include "iterator.h"
#include "pool.h"
#define GIT_CHECKOUT__NOTIFY_CONFLICT_TREE (1u << 12) #define GIT_CHECKOUT__NOTIFY_CONFLICT_TREE (1u << 12)
typedef struct {
git_repository *repo;
git_diff_list *diff;
git_checkout_opts opts;
bool opts_free_baseline;
char *pfx;
git_index *index;
git_pool pool;
git_vector removes;
git_buf path;
size_t workdir_len;
unsigned int strategy;
int can_symlink;
bool reload_submodules;
size_t total_steps;
size_t completed_steps;
} checkout_data;
/** /**
* Update the working directory to match the target iterator. The * Update the working directory to match the target iterator. The
* expected baseline value can be passed in via the checkout options * expected baseline value can be passed in via the checkout options
...@@ -21,4 +40,14 @@ extern int git_checkout_iterator( ...@@ -21,4 +40,14 @@ extern int git_checkout_iterator(
git_iterator *target, git_iterator *target,
const git_checkout_opts *opts); const git_checkout_opts *opts);
int git_checkout__write_content(
checkout_data *data,
const git_oid *oid,
const char *path,
const char *hint_path,
unsigned int mode,
struct stat *st);
int git_checkout__conflicts(checkout_data *data);
#endif #endif
...@@ -47,7 +47,7 @@ GIT_INLINE(int) merge_file_best_mode( ...@@ -47,7 +47,7 @@ GIT_INLINE(int) merge_file_best_mode(
* assume executable. Otherwise, if any mode changed from the ancestor, * assume executable. Otherwise, if any mode changed from the ancestor,
* use that one. * use that one.
*/ */
if (GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) { if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) {
if (ours->mode == GIT_FILEMODE_BLOB_EXECUTABLE || if (ours->mode == GIT_FILEMODE_BLOB_EXECUTABLE ||
theirs->mode == GIT_FILEMODE_BLOB_EXECUTABLE) theirs->mode == GIT_FILEMODE_BLOB_EXECUTABLE)
return GIT_FILEMODE_BLOB_EXECUTABLE; return GIT_FILEMODE_BLOB_EXECUTABLE;
......
...@@ -135,7 +135,7 @@ int git_reset( ...@@ -135,7 +135,7 @@ int git_reset(
if (reset_type == GIT_RESET_HARD) { if (reset_type == GIT_RESET_HARD) {
/* overwrite working directory with HEAD */ /* overwrite working directory with HEAD */
opts.checkout_strategy = GIT_CHECKOUT_FORCE; opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_SKIP_UNMERGED;
if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0)
goto cleanup; goto cleanup;
......
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