summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: bc052d7)
raw | patch | inline | side by side (parent: bc052d7)
author | Linus Torvalds <torvalds@linux-foundation.org> | |
Fri, 7 Mar 2008 02:12:28 +0000 (18:12 -0800) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Sun, 9 Mar 2008 09:03:38 +0000 (01:03 -0800) |
We will always unpack into our own internal index, but we will take the
source from wherever specified, and we will optionally write the result
to a specified index (optionally, because not everybody even _wants_ any
result: the index diffing really wants to just walk the tree and index
in parallel).
This ends up removing a fair number more lines than it adds, for the
simple reason that we can now skip all the crud that tried to be
oh-so-careful about maintaining our position in the index as we were
traversing and modifying it. Since we don't actually modify the source
index any more, we can just update the 'o->pos' pointer without worrying
about whether an index entry got removed or replaced or added to.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
source from wherever specified, and we will optionally write the result
to a specified index (optionally, because not everybody even _wants_ any
result: the index diffing really wants to just walk the tree and index
in parallel).
This ends up removing a fair number more lines than it adds, for the
simple reason that we can now skip all the crud that tried to be
oh-so-careful about maintaining our position in the index as we were
traversing and modifying it. Since we don't actually modify the source
index any more, we can just update the 'o->pos' pointer without worrying
about whether an index entry got removed or replaced or added to.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 9bdb6233f01de5e797a860cf1527749f3262922e..7deb504837d252dd43fa9746c5d12342e93a5923 100644 (file)
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = !quiet;
- opts.index = &the_index;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
if (unpack_trees(1, &tree_desc, &opts))
opts.merge = 1;
opts.fn = oneway_merge;
opts.verbose_update = !quiet;
- opts.index = &the_index;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
if (unpack_trees(1, &tree_desc, &opts))
memset(&topts, 0, sizeof(topts));
topts.head_idx = -1;
- topts.index = &the_index;
+ topts.src_index = &the_index;
+ topts.dst_index = &the_index;
refresh_cache(REFRESH_QUIET);
diff --git a/builtin-commit.c b/builtin-commit.c
index 38a542258ab173c76d5171a35799235bb725e63c..660a3458f7f4ef24dfa4fd5bdf902174da1eefb4 100644 (file)
--- a/builtin-commit.c
+++ b/builtin-commit.c
opts.head_idx = 1;
opts.index_only = 1;
opts.merge = 1;
- opts.index = &the_index;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
opts.fn = oneway_merge;
tree = parse_tree_indirect(head_sha1);
index 50b389623cd8dab9adf6b03e62db1af762fac61c..fa02bb5a804a58ea0831e8476aee9a80914667f4 100644 (file)
opts.merge = 1;
opts.head_idx = 2;
opts.fn = threeway_merge;
- opts.index = &the_index;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
init_tree_desc_from_tree(t+0, common);
init_tree_desc_from_tree(t+1, head);
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index d004e9043100a45ae3ccf1d08f819cfdbc0b099c..160456dad13322e3547d6dc3fc91626bd3ec9c2b 100644 (file)
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
memset(&opts, 0, sizeof(opts));
opts.head_idx = -1;
- opts.index = &the_index;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
git_config(git_default_config);
if ((opts.dir && !opts.update))
die("--exclude-per-directory is meaningless unless -u");
- if (opts.prefix) {
- int pfxlen = strlen(opts.prefix);
- int pos;
- if (opts.prefix[pfxlen-1] != '/')
- die("prefix must end with /");
- if (stage != 2)
- die("binding merge takes only one tree");
- pos = cache_name_pos(opts.prefix, pfxlen);
- if (0 <= pos)
- die("corrupt index file");
- pos = -pos-1;
- if (pos < active_nr &&
- !strncmp(active_cache[pos]->name, opts.prefix, pfxlen))
- die("subdirectory '%s' already exists.", opts.prefix);
- pos = cache_name_pos(opts.prefix, pfxlen-1);
- if (0 <= pos)
- die("file '%.*s' already exists.",
- pfxlen-1, opts.prefix);
- opts.pos = -1 - pos;
- }
-
if (opts.merge) {
if (stage < 2)
die("just how do you expect me to merge %d trees?", stage-1);
diff --git a/diff-lib.c b/diff-lib.c
index e359058d0bb65ba716cec137173cfb3eafdcce56..9520773f3b94a6bc4dadb3e9c92d9add0ada75b3 100644 (file)
--- a/diff-lib.c
+++ b/diff-lib.c
*/
static void do_oneway_diff(struct unpack_trees_options *o,
struct cache_entry *idx,
- struct cache_entry *tree,
- int idx_pos, int idx_nr)
+ struct cache_entry *tree)
{
struct rev_info *revs = o->unpack_data;
int match_missing, cached;
show_modified(revs, tree, idx, 1, cached, match_missing);
}
-/*
- * Count how many index entries go with the first one
- */
-static inline int count_skip(const struct cache_entry *src, int pos)
-{
- int skip = 1;
-
- /* We can only have multiple entries if the first one is not stage-0 */
- if (ce_stage(src)) {
- struct cache_entry **p = active_cache + pos;
- int namelen = ce_namelen(src);
-
- for (;;) {
- const struct cache_entry *ce;
- pos++;
- if (pos >= active_nr)
- break;
- ce = *++p;
- if (ce_namelen(ce) != namelen)
- break;
- if (memcmp(ce->name, src->name, namelen))
- break;
- skip++;
- }
- }
- return skip;
-}
-
/*
* The unpack_trees() interface is designed for merging, so
* the different source entries are designed primarily for
* the fairly complex unpack_trees() semantic requirements, including
* the skipping, the path matching, the type conflict cases etc.
*/
-static int oneway_diff(struct cache_entry **src,
- struct unpack_trees_options *o,
- int index_pos)
+static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
{
- int skip = 0;
struct cache_entry *idx = src[0];
struct cache_entry *tree = src[1];
struct rev_info *revs = o->unpack_data;
- if (index_pos >= 0)
- skip = count_skip(idx, index_pos);
-
/*
* Unpack-trees generates a DF/conflict entry if
* there was a directory in the index and a tree
tree = NULL;
if (ce_path_match(idx ? idx : tree, revs->prune_data))
- do_oneway_diff(o, idx, tree, index_pos, skip);
+ do_oneway_diff(o, idx, tree);
- return skip;
+ return 0;
}
int run_diff_index(struct rev_info *revs, int cached)
opts.merge = 1;
opts.fn = oneway_diff;
opts.unpack_data = revs;
- opts.index = &the_index;
+ opts.src_index = &the_index;
+ opts.dst_index = NULL;
init_tree_desc(&t, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts))
opts.merge = 1;
opts.fn = oneway_diff;
opts.unpack_data = &revs;
- opts.index = &the_index;
+ opts.src_index = &the_index;
+ opts.dst_index = &the_index;
init_tree_desc(&t, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts))
index f1b12167b8b5d03634e6f1803b1388b07884bd13..8c4556408ecc81985acd7b8237921330c326e787 100755 (executable)
git commit -m two
'
-test_expect_failure 'reset should work' '
+test_expect_success 'reset should work' '
git read-tree -u --reset HEAD^ &&
git ls-files >actual &&
diff -u expect actual
diff --git a/unpack-trees.c b/unpack-trees.c
index cb8f84796862ba7f3aee42981585441085e9060a..0cdf19817d65ef8b054b8399981be164c8ee7542 100644 (file)
--- a/unpack-trees.c
+++ b/unpack-trees.c
#include "progress.h"
#include "refs.h"
-static inline void remove_entry(int remove, struct unpack_trees_options *o)
+static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
+ unsigned int set, unsigned int clear)
{
- if (remove >= 0)
- remove_index_entry_at(o->index, remove);
+ unsigned int size = ce_size(ce);
+ struct cache_entry *new = xmalloc(size);
+
+ clear |= CE_HASHED | CE_UNHASHED;
+
+ memcpy(new, ce, size);
+ new->next = NULL;
+ new->ce_flags = (new->ce_flags & ~clear) | set;
+ add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|ADD_CACHE_SKIP_DFCHECK);
}
/* Unlink the last component and attempt to remove leading
unsigned cnt = 0, total = 0;
struct progress *progress = NULL;
char last_symlink[PATH_MAX];
+ struct index_state *index = &o->result;
int i;
if (o->update && o->verbose_update) {
- for (total = cnt = 0; cnt < o->index->cache_nr; cnt++) {
- struct cache_entry *ce = o->index->cache[cnt];
+ for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
+ struct cache_entry *ce = index->cache[cnt];
if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
total++;
}
}
*last_symlink = '\0';
- for (i = 0; i < o->index->cache_nr; i++) {
- struct cache_entry *ce = o->index->cache[i];
+ for (i = 0; i < index->cache_nr; i++) {
+ struct cache_entry *ce = index->cache[i];
if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
display_progress(progress, ++cnt);
if (ce->ce_flags & CE_REMOVE) {
if (o->update)
unlink_entry(ce->name, last_symlink);
- remove_index_entry_at(o->index, i);
+ remove_index_entry_at(&o->result, i);
i--;
continue;
}
stop_progress(&progress);
}
-static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o, int remove)
+static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o)
{
- int ret = o->fn(src, o, remove);
- if (ret > 0) {
- o->pos += ret;
+ int ret = o->fn(src, o);
+ if (ret > 0)
ret = 0;
- }
return ret;
}
static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_options *o)
{
struct cache_entry *src[5] = { ce, };
+
+ o->pos++;
if (ce_stage(ce)) {
if (o->skip_unmerged) {
- o->pos++;
- } else {
- remove_entry(o->pos, o);
+ add_entry(o, ce, 0, 0);
+ return 0;
}
return 0;
}
- return call_unpack_fn(src, o, o->pos);
+ return call_unpack_fn(src, o);
}
int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info)
@@ -200,7 +208,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
}
static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmask, struct cache_entry *src[5],
- const struct name_entry *names, const struct traverse_info *info, int remove)
+ const struct name_entry *names, const struct traverse_info *info)
{
int i;
struct unpack_trees_options *o = info->data;
@@ -240,12 +248,11 @@ static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmas
}
if (o->merge)
- return call_unpack_fn(src, o, remove);
+ return call_unpack_fn(src, o);
n += o->merge;
- remove_entry(remove, o);
for (i = 0; i < n; i++)
- add_index_entry(o->index, src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+ add_entry(o, src[i], 0, 0);
return 0;
}
@@ -253,7 +260,6 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
{
struct cache_entry *src[5] = { NULL, };
struct unpack_trees_options *o = info->data;
- int remove = -1;
const struct name_entry *p = names;
/* Find first entry with a real name (we could use "mask" too) */
@@ -262,8 +268,8 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
/* Are we supposed to look at the index too? */
if (o->merge) {
- while (o->pos < o->index->cache_nr) {
- struct cache_entry *ce = o->index->cache[o->pos];
+ while (o->pos < o->src_index->cache_nr) {
+ struct cache_entry *ce = o->src_index->cache[o->pos];
int cmp = compare_entry(ce, info, p);
if (cmp < 0) {
if (unpack_index_entry(ce, o) < 0)
@@ -271,24 +277,25 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
continue;
}
if (!cmp) {
+ o->pos++;
if (ce_stage(ce)) {
/*
* If we skip unmerged index entries, we'll skip this
* entry *and* the tree entries associated with it!
*/
- if (o->skip_unmerged)
+ if (o->skip_unmerged) {
+ add_entry(o, ce, 0, 0);
return mask;
- remove_entry(o->pos, o);
+ }
continue;
}
src[0] = ce;
- remove = o->pos;
}
break;
}
}
- if (unpack_nondirectories(n, mask, dirmask, src, names, info, remove) < 0)
+ if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0)
return -1;
/* Now handle any directories.. */
return error(message);
return -1;
}
- discard_index(o->index);
- read_index(o->index);
return -1;
}
state.quiet = 1;
state.refresh_cache = 1;
+ memset(&o->result, 0, sizeof(o->result));
o->merge_size = len;
if (!dfc)
/* Any left-over entries in the index? */
if (o->merge) {
- while (o->pos < o->index->cache_nr) {
- struct cache_entry *ce = o->index->cache[o->pos];
+ while (o->pos < o->src_index->cache_nr) {
+ struct cache_entry *ce = o->src_index->cache[o->pos];
if (unpack_index_entry(ce, o) < 0)
return unpack_failed(o, NULL);
}
@@ -360,7 +366,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (o->trivial_merges_only && o->nontrivial_merge)
return unpack_failed(o, "Merge requires file-level merging");
+ o->src_index = NULL;
check_updates(o);
+ if (o->dst_index)
+ *o->dst_index = o->result;
return 0;
}
return 0;
if (!lstat(ce->name, &st)) {
- unsigned changed = ie_match_stat(o->index, ce, &st, CE_MATCH_IGNORE_VALID);
+ unsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID);
if (!changed)
return 0;
/*
static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
{
if (ce)
- cache_tree_invalidate_path(o->index->cache_tree, ce->name);
+ cache_tree_invalidate_path(o->src_index->cache_tree, ce->name);
}
/*
@@ -464,12 +473,12 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
* in that directory.
*/
namelen = strlen(ce->name);
- pos = index_name_pos(o->index, ce->name, namelen);
+ pos = index_name_pos(o->src_index, ce->name, namelen);
if (0 <= pos)
return cnt; /* we have it as nondirectory */
pos = -pos - 1;
- for (i = pos; i < o->index->cache_nr; i++) {
- struct cache_entry *ce = o->index->cache[i];
+ for (i = pos; i < o->src_index->cache_nr; i++) {
+ struct cache_entry *ce = o->src_index->cache[i];
int len = ce_namelen(ce);
if (len < namelen ||
strncmp(ce->name, ce->name, namelen) ||
@@ -481,7 +490,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
if (!ce_stage(ce)) {
if (verify_uptodate(ce, o))
return -1;
- ce->ce_flags |= CE_REMOVE;
+ add_entry(o, ce, CE_REMOVE, 0);
}
cnt++;
}
* delete this path, which is in a subdirectory that
* is being replaced with a blob.
*/
- cnt = index_name_pos(o->index, ce->name, strlen(ce->name));
+ cnt = index_name_pos(&o->result, ce->name, strlen(ce->name));
if (0 <= cnt) {
- struct cache_entry *ce = o->index->cache[cnt];
+ struct cache_entry *ce = o->result.cache[cnt];
if (ce->ce_flags & CE_REMOVE)
return 0;
}
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
struct unpack_trees_options *o)
{
- merge->ce_flags |= CE_UPDATE;
if (old) {
/*
* See if we can re-use the old CE directly?
invalidate_ce_path(merge, o);
}
- merge->ce_flags &= ~CE_STAGEMASK;
- add_index_entry(o->index, merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+ add_entry(o, merge, CE_UPDATE, CE_STAGEMASK);
return 1;
}
static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
struct unpack_trees_options *o)
{
- if (old) {
- if (verify_uptodate(old, o))
- return -1;
- } else
+ /* Did it exist in the index? */
+ if (!old) {
if (verify_absent(ce, "removed", o))
return -1;
- ce->ce_flags |= CE_REMOVE;
- add_index_entry(o->index, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+ return 0;
+ }
+ if (verify_uptodate(old, o))
+ return -1;
+ add_entry(o, ce, CE_REMOVE, 0);
invalidate_ce_path(ce, o);
return 1;
}
static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o)
{
- add_index_entry(o->index, ce, ADD_CACHE_OK_TO_ADD);
+ add_entry(o, ce, 0, 0);
return 1;
}
}
#endif
-int threeway_merge(struct cache_entry **stages,
- struct unpack_trees_options *o,
- int remove)
+int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
{
struct cache_entry *index;
struct cache_entry *head;
}
/* #1 */
- if (!head && !remote && any_anc_missing) {
- remove_entry(remove, o);
+ if (!head && !remote && any_anc_missing)
return 0;
- }
/* Under the new "aggressive" rule, we resolve mostly trivial
* cases that we historically had git-merge-one-file resolve.
if ((head_deleted && remote_deleted) ||
(head_deleted && remote && remote_match) ||
(remote_deleted && head && head_match)) {
- remove_entry(remove, o);
if (index)
return deleted_entry(index, index, o);
- else if (ce && !head_deleted) {
+ if (ce && !head_deleted) {
if (verify_absent(ce, "removed", o))
return -1;
}
return -1;
}
- remove_entry(remove, o);
o->nontrivial_merge = 1;
/* #2, #3, #4, #6, #7, #9, #10, #11. */
* "carry forward" rule, please see <Documentation/git-read-tree.txt>.
*
*/
-int twoway_merge(struct cache_entry **src,
- struct unpack_trees_options *o,
- int remove)
+int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
{
struct cache_entry *current = src[0];
struct cache_entry *oldtree = src[1];
}
else if (oldtree && !newtree && same(current, oldtree)) {
/* 10 or 11 */
- remove_entry(remove, o);
return deleted_entry(oldtree, current, o);
}
else if (oldtree && newtree &&
}
else {
/* all other failures */
- remove_entry(remove, o);
if (oldtree)
return o->gently ? -1 : reject_merge(oldtree);
if (current)
}
else if (newtree)
return merged_entry(newtree, current, o);
- remove_entry(remove, o);
return deleted_entry(oldtree, current, o);
}
* stage0 does not have anything there.
*/
int bind_merge(struct cache_entry **src,
- struct unpack_trees_options *o,
- int remove)
+ struct unpack_trees_options *o)
{
struct cache_entry *old = src[0];
struct cache_entry *a = src[1];
o->merge_size);
if (a && old)
return o->gently ? -1 :
- error("Entry '%s' overlaps. Cannot bind.", a->name);
+ error("Entry '%s' overlaps with '%s'. Cannot bind.", a->name, old->name);
if (!a)
return keep_entry(old, o);
else
* The rule is:
* - take the stat information from stage0, take the data from stage1
*/
-int oneway_merge(struct cache_entry **src,
- struct unpack_trees_options *o,
- int remove)
+int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)
{
struct cache_entry *old = src[0];
struct cache_entry *a = src[1];
return error("Cannot do a oneway merge of %d trees",
o->merge_size);
- if (!a) {
- remove_entry(remove, o);
+ if (!a)
return deleted_entry(old, old, o);
- }
+
if (old && same(old, a)) {
+ int update = 0;
if (o->reset) {
struct stat st;
if (lstat(old->name, &st) ||
- ie_match_stat(o->index, old, &st, CE_MATCH_IGNORE_VALID))
- old->ce_flags |= CE_UPDATE;
+ ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID))
+ update |= CE_UPDATE;
}
- return keep_entry(old, o);
+ add_entry(o, old, update, 0);
+ return 0;
}
return merged_entry(a, old, o);
}
diff --git a/unpack-trees.h b/unpack-trees.h
index 65add1652f77978e0e0aee4924b583aefa9978ce..e8abbcd037167a58c816d94f4f0c617d6572d23d 100644 (file)
--- a/unpack-trees.h
+++ b/unpack-trees.h
struct unpack_trees_options;
typedef int (*merge_fn_t)(struct cache_entry **src,
- struct unpack_trees_options *options,
- int remove);
+ struct unpack_trees_options *options);
struct unpack_trees_options {
int reset;
struct cache_entry *df_conflict_entry;
void *unpack_data;
- struct index_state *index;
+
+ struct index_state *dst_index;
+ const struct index_state *src_index;
+ struct index_state result;
};
extern int unpack_trees(unsigned n, struct tree_desc *t,
struct unpack_trees_options *options);
-int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o, int);
-int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o, int);
-int bind_merge(struct cache_entry **src, struct unpack_trees_options *o, int);
-int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o, int);
+int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o);
+int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o);
+int bind_merge(struct cache_entry **src, struct unpack_trees_options *o);
+int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o);
#endif