summaryrefslogtreecommitdiff
path: root/builtin/sparse-checkout.c
diff options
context:
space:
mode:
authorDerrick Stolee <dstolee@microsoft.com>2019-11-21 22:04:46 (GMT)
committerJunio C Hamano <gitster@pobox.com>2019-11-22 07:11:44 (GMT)
commite091228e17e88b1bc16cb50d5c3aff10dc5119d1 (patch)
tree22ed9de6fbd48944e5ffc5547bd01ade3300caca /builtin/sparse-checkout.c
parente9de487aa36aa75b5c9068c6bd07cfb8bf2ee955 (diff)
downloadgit-e091228e17e88b1bc16cb50d5c3aff10dc5119d1.zip
git-e091228e17e88b1bc16cb50d5c3aff10dc5119d1.tar.gz
git-e091228e17e88b1bc16cb50d5c3aff10dc5119d1.tar.bz2
sparse-checkout: update working directory in-process
The sparse-checkout builtin used 'git read-tree -mu HEAD' to update the skip-worktree bits in the index and to update the working directory. This extra process is overly complex, and prone to failure. It also requires that we write our changes to the sparse-checkout file before trying to update the index. Remove this extra process call by creating a direct call to unpack_trees() in the same way 'git read-tree -mu HEAD' does. In addition, provide an in-memory list of patterns so we can avoid reading from the sparse-checkout file. This allows us to test a proposed change to the file before writing to it. An earlier version of this patch included a bug when the 'set' command failed due to the "Sparse checkout leaves no entry on working directory" error. It would not rollback the index.lock file, so the replay of the old sparse-checkout specification would fail. A test in t1091 now covers that scenario. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/sparse-checkout.c')
-rw-r--r--builtin/sparse-checkout.c83
1 files changed, 71 insertions, 12 deletions
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 55b337a..a5d32e4 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -7,6 +7,11 @@
#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
+#include "cache.h"
+#include "cache-tree.h"
+#include "lockfile.h"
+#include "resolve-undo.h"
+#include "unpack-trees.h"
static char const * const builtin_sparse_checkout_usage[] = {
N_("git sparse-checkout (init|list|set|disable) <options>"),
@@ -60,18 +65,54 @@ static int sparse_checkout_list(int argc, const char **argv)
return 0;
}
-static int update_working_directory(void)
+static int update_working_directory(struct pattern_list *pl)
{
- struct argv_array argv = ARGV_ARRAY_INIT;
int result = 0;
- argv_array_pushl(&argv, "read-tree", "-m", "-u", "HEAD", NULL);
+ struct unpack_trees_options o;
+ struct lock_file lock_file = LOCK_INIT;
+ struct object_id oid;
+ struct tree *tree;
+ struct tree_desc t;
+ struct repository *r = the_repository;
- if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
- error(_("failed to update index with new sparse-checkout patterns"));
- result = 1;
- }
+ if (repo_read_index_unmerged(r))
+ die(_("you need to resolve your current index first"));
+
+ if (get_oid("HEAD", &oid))
+ return 0;
+
+ tree = parse_tree_indirect(&oid);
+ parse_tree(tree);
+ init_tree_desc(&t, tree->buffer, tree->size);
+
+ memset(&o, 0, sizeof(o));
+ o.verbose_update = isatty(2);
+ o.merge = 1;
+ o.update = 1;
+ o.fn = oneway_merge;
+ o.head_idx = -1;
+ o.src_index = r->index;
+ o.dst_index = r->index;
+ o.skip_sparse_checkout = 0;
+ o.pl = pl;
+ o.keep_pattern_list = !!pl;
+
+ resolve_undo_clear_index(r->index);
+ setup_work_tree();
+
+ cache_tree_free(&r->index->cache_tree);
+
+ repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
+
+ core_apply_sparse_checkout = 1;
+ result = unpack_trees(1, &t, &o);
+
+ if (!result) {
+ prime_cache_tree(r, r->index, tree);
+ write_locked_index(r->index, &lock_file, COMMIT_LOCK);
+ } else
+ rollback_lock_file(&lock_file);
- argv_array_clear(&argv);
return result;
}
@@ -129,6 +170,15 @@ static int write_patterns_and_update(struct pattern_list *pl)
{
char *sparse_filename;
FILE *fp;
+ int result;
+
+ result = update_working_directory(pl);
+
+ if (result) {
+ clear_pattern_list(pl);
+ update_working_directory(NULL);
+ return result;
+ }
sparse_filename = get_sparse_checkout_filename();
fp = fopen(sparse_filename, "w");
@@ -139,9 +189,11 @@ static int write_patterns_and_update(struct pattern_list *pl)
write_patterns_to_file(fp, pl);
fclose(fp);
+
free(sparse_filename);
+ clear_pattern_list(pl);
- return update_working_directory();
+ return 0;
}
enum sparse_checkout_mode {
@@ -199,7 +251,11 @@ static int sparse_checkout_init(int argc, const char **argv)
builtin_sparse_checkout_init_options,
builtin_sparse_checkout_init_usage, 0);
- mode = init_opts.cone_mode ? MODE_CONE_PATTERNS : MODE_ALL_PATTERNS;
+ if (init_opts.cone_mode) {
+ mode = MODE_CONE_PATTERNS;
+ core_sparse_checkout_cone = 1;
+ } else
+ mode = MODE_ALL_PATTERNS;
if (set_config(mode))
return 1;
@@ -230,7 +286,8 @@ static int sparse_checkout_init(int argc, const char **argv)
}
reset_dir:
- return update_working_directory();
+ core_apply_sparse_checkout = 1;
+ return update_working_directory(NULL);
}
static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
@@ -311,6 +368,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
hashmap_init(&pl.recursive_hashmap, pl_hashmap_cmp, NULL, 0);
hashmap_init(&pl.parent_hashmap, pl_hashmap_cmp, NULL, 0);
+ pl.use_cone_patterns = 1;
if (set_opts.use_stdin) {
while (!strbuf_getline(&line, stdin))
@@ -365,7 +423,8 @@ static int sparse_checkout_disable(int argc, const char **argv)
fprintf(fp, "/*\n");
fclose(fp);
- if (update_working_directory())
+ core_apply_sparse_checkout = 1;
+ if (update_working_directory(NULL))
die(_("error while refreshing working directory"));
unlink(sparse_filename);