struct tree_entry_list {
struct tree_entry_list *next;
- unsigned directory : 1;
- unsigned executable : 1;
- unsigned symlink : 1;
unsigned int mode;
const char *name;
const unsigned char *sha1;
};
-static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
+static struct tree_entry_list *create_tree_entry_list(struct tree_desc *desc)
{
- struct tree_desc desc;
struct name_entry one;
struct tree_entry_list *ret = NULL;
struct tree_entry_list **list_p = &ret;
- if (!tree->object.parsed)
- parse_tree(tree);
-
- init_tree_desc(&desc, tree->buffer, tree->size);
-
- while (tree_entry(&desc, &one)) {
+ while (tree_entry(desc, &one)) {
struct tree_entry_list *entry;
entry = xmalloc(sizeof(struct tree_entry_list));
entry->name = one.path;
entry->sha1 = one.sha1;
entry->mode = one.mode;
- entry->directory = S_ISDIR(one.mode) != 0;
- entry->executable = (one.mode & S_IXUSR) != 0;
- entry->symlink = S_ISLNK(one.mode) != 0;
entry->next = NULL;
*list_p = entry;
return ret;
}
+static inline void remove_entry(int remove)
+{
+ if (remove >= 0)
+ remove_cache_entry_at(remove);
+}
+
static int unpack_trees_rec(struct tree_entry_list **posns, int len,
const char *base, struct unpack_trees_options *o,
struct tree_entry_list *df_conflict_list)
{
+ int remove;
int baselen = strlen(base);
int src_size = len + 1;
- int i_stk = i_stk;
int retval = 0;
- if (o->dir)
- i_stk = push_exclude_per_directory(o->dir, base, strlen(base));
-
do {
int i;
const char *first;
#endif
if (!first || entcmp(first, firstdir,
posns[i]->name,
- posns[i]->directory) > 0) {
+ S_ISDIR(posns[i]->mode)) > 0) {
first = posns[i]->name;
- firstdir = posns[i]->directory;
+ firstdir = S_ISDIR(posns[i]->mode);
}
}
/* No name means we're done */
subposns = xcalloc(len, sizeof(struct tree_list_entry *));
+ remove = -1;
if (cache_name && !strcmp(cache_name, first)) {
any_files = 1;
src[0] = active_cache[o->pos];
- remove_cache_entry_at(o->pos);
+ remove = o->pos;
}
for (i = 0; i < len; i++) {
continue;
}
- if (posns[i]->directory) {
+ if (S_ISDIR(posns[i]->mode)) {
struct tree *tree = lookup_tree(posns[i]->sha1);
+ struct tree_desc t;
any_dirs = 1;
parse_tree(tree);
- subposns[i] = create_tree_entry_list(tree);
+ init_tree_desc(&t, tree->buffer, tree->size);
+ subposns[i] = create_tree_entry_list(&t);
posns[i] = posns[i]->next;
src[i + o->merge] = o->df_conflict_entry;
continue;
printf("\n");
}
#endif
- ret = o->fn(src, o);
+ ret = o->fn(src, o, remove);
#if DBRT_DEBUG > 1
printf("Added %d entries\n", ret);
#endif
o->pos += ret;
} else {
+ remove_entry(remove);
for (i = 0; i < src_size; i++) {
if (src[i]) {
add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
} while (1);
leave_directory:
- if (o->dir)
- pop_exclude_per_directory(o->dir, i_stk);
return retval;
}
static void check_updates(struct cache_entry **src, int nr,
struct unpack_trees_options *o)
{
- unsigned short mask = htons(CE_UPDATE);
unsigned cnt = 0, total = 0;
- struct progress progress;
+ struct progress *progress = NULL;
char last_symlink[PATH_MAX];
if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < nr; cnt++) {
struct cache_entry *ce = src[cnt];
- if (!ce->ce_mode || ce->ce_flags & mask)
+ if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
total++;
}
- start_progress_delay(&progress, "Checking %u files out...",
- "", total, 50, 2);
+ progress = start_progress_delay("Checking out files",
+ total, 50, 2);
cnt = 0;
}
while (nr--) {
struct cache_entry *ce = *src++;
- if (total)
- if (!ce->ce_mode || ce->ce_flags & mask)
- display_progress(&progress, ++cnt);
- if (!ce->ce_mode) {
+ 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);
continue;
}
- if (ce->ce_flags & mask) {
- ce->ce_flags &= ~mask;
+ if (ce->ce_flags & CE_UPDATE) {
+ ce->ce_flags &= ~CE_UPDATE;
if (o->update) {
checkout_entry(ce, &state, NULL);
*last_symlink = '\0';
}
}
}
- if (total)
- stop_progress(&progress);;
+ stop_progress(&progress);
}
-int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
+int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
{
- unsigned len = object_list_length(trees);
struct tree_entry_list **posns;
int i;
- struct object_list *posn = trees;
struct tree_entry_list df_conflict_list;
static struct cache_entry *dfc;
if (len) {
posns = xmalloc(len * sizeof(struct tree_entry_list *));
- for (i = 0; i < len; i++) {
- posns[i] = create_tree_entry_list((struct tree *) posn->item);
- posn = posn->next;
- }
+ for (i = 0; i < len; i++)
+ posns[i] = create_tree_entry_list(t+i);
+
if (unpack_trees_rec(posns, len, o->prefix ? o->prefix : "",
o, &df_conflict_list))
return -1;
return;
if (!lstat(ce->name, &st)) {
- unsigned changed = ce_match_stat(ce, &st, 1);
+ unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
if (!changed)
return;
+ /*
+ * NEEDSWORK: the current default policy is to allow
+ * submodule to be out of sync wrt the supermodule
+ * index. This needs to be tightened later for
+ * submodules that are marked to be automatically
+ * checked out.
+ */
+ if (S_ISGITLINK(ce->ce_mode))
+ return;
errno = 0;
}
if (errno == ENOENT)
int cnt = 0;
unsigned char sha1[20];
- if (S_ISGITLINK(ntohl(ce->ce_mode)) &&
+ if (S_ISGITLINK(ce->ce_mode) &&
resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) {
/* If we are not going to update the submodule, then
* we don't care.
*/
if (!ce_stage(ce)) {
verify_uptodate(ce, o);
- ce->ce_mode = 0;
+ ce->ce_flags |= CE_REMOVE;
}
cnt++;
}
if (!lstat(ce->name, &st)) {
int cnt;
+ int dtype = ce_to_dtype(ce);
- if (o->dir && excluded(o->dir, ce->name))
+ if (o->dir && excluded(o->dir, ce->name, &dtype))
/*
* ce->name is explicitly excluded, so it is Ok to
* overwrite it.
cnt = cache_name_pos(ce->name, strlen(ce->name));
if (0 <= cnt) {
struct cache_entry *ce = active_cache[cnt];
- if (!ce_stage(ce) && !ce->ce_mode)
+ if (ce->ce_flags & CE_REMOVE)
return;
}
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
struct unpack_trees_options *o)
{
- merge->ce_flags |= htons(CE_UPDATE);
+ merge->ce_flags |= CE_UPDATE;
if (old) {
/*
* See if we can re-use the old CE directly?
* a match.
*/
if (same(old, merge)) {
- *merge = *old;
+ memcpy(merge, old, offsetof(struct cache_entry, name));
} else {
verify_uptodate(old, o);
invalidate_ce_path(old);
invalidate_ce_path(merge);
}
- merge->ce_flags &= ~htons(CE_STAGEMASK);
+ merge->ce_flags &= ~CE_STAGEMASK;
add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
return 1;
}
verify_uptodate(old, o);
else
verify_absent(ce, "removed", o);
- ce->ce_mode = 0;
+ ce->ce_flags |= CE_REMOVE;
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
invalidate_ce_path(ce);
return 1;
else
fprintf(o, "%s%06o %s %d\t%s\n",
label,
- ntohl(ce->ce_mode),
+ ce->ce_mode,
sha1_to_hex(ce->sha1),
ce_stage(ce),
ce->name);
#endif
int threeway_merge(struct cache_entry **stages,
- struct unpack_trees_options *o)
+ struct unpack_trees_options *o,
+ int remove)
{
struct cache_entry *index;
struct cache_entry *head;
}
/* #1 */
- if (!head && !remote && any_anc_missing)
+ if (!head && !remote && any_anc_missing) {
+ remove_entry(remove);
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);
if (index)
return deleted_entry(index, index, o);
else if (ce && !head_deleted)
verify_uptodate(index, o);
}
+ remove_entry(remove);
o->nontrivial_merge = 1;
/* #2, #3, #4, #6, #7, #9, #10, #11. */
*
*/
int twoway_merge(struct cache_entry **src,
- struct unpack_trees_options *o)
+ struct unpack_trees_options *o,
+ int remove)
{
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);
return deleted_entry(oldtree, current, o);
}
else if (oldtree && newtree &&
}
else {
/* all other failures */
+ remove_entry(remove);
if (oldtree)
reject_merge(oldtree);
if (current)
}
else if (newtree)
return merged_entry(newtree, current, o);
- else
- return deleted_entry(oldtree, current, o);
+ remove_entry(remove);
+ return deleted_entry(oldtree, current, o);
}
/*
* stage0 does not have anything there.
*/
int bind_merge(struct cache_entry **src,
- struct unpack_trees_options *o)
+ struct unpack_trees_options *o,
+ int remove)
{
struct cache_entry *old = src[0];
struct cache_entry *a = src[1];
* - take the stat information from stage0, take the data from stage1
*/
int oneway_merge(struct cache_entry **src,
- struct unpack_trees_options *o)
+ struct unpack_trees_options *o,
+ int remove)
{
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)
+ if (!a) {
+ remove_entry(remove);
return deleted_entry(old, old, o);
+ }
if (old && same(old, a)) {
if (o->reset) {
struct stat st;
if (lstat(old->name, &st) ||
- ce_match_stat(old, &st, 1))
- old->ce_flags |= htons(CE_UPDATE);
+ ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID))
+ old->ce_flags |= CE_UPDATE;
}
return keep_entry(old, o);
}