-#include <signal.h>
-#include <sys/time.h>
#include "cache.h"
#include "dir.h"
#include "tree.h"
if (!tree->object.parsed)
parse_tree(tree);
- desc.buf = tree->buffer;
- desc.size = tree->size;
+ init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &one)) {
struct tree_entry_list *entry;
static int unpack_trees_rec(struct tree_entry_list **posns, int len,
const char *base, struct unpack_trees_options *o,
- int *indpos,
struct tree_entry_list *df_conflict_list)
{
int baselen = strlen(base);
cache_name = NULL;
/* Check the cache */
- if (o->merge && *indpos < active_nr) {
+ if (o->merge && o->pos < active_nr) {
/* This is a bit tricky: */
/* If the index has a subdirectory (with
* contents) as the first name, it'll get a
* file case.
*/
- cache_name = active_cache[*indpos]->name;
+ cache_name = active_cache[o->pos]->name;
if (strlen(cache_name) > baselen &&
!memcmp(cache_name, base, baselen)) {
cache_name += baselen;
if (cache_name && !strcmp(cache_name, first)) {
any_files = 1;
- src[0] = active_cache[*indpos];
- remove_cache_entry_at(*indpos);
+ src[0] = active_cache[o->pos];
+ remove_cache_entry_at(o->pos);
}
for (i = 0; i < len; i++) {
#if DBRT_DEBUG > 1
printf("Added %d entries\n", ret);
#endif
- *indpos += ret;
+ o->pos += ret;
} else {
for (i = 0; i < src_size; i++) {
if (src[i]) {
newbase[baselen + pathlen] = '/';
newbase[baselen + pathlen + 1] = '\0';
if (unpack_trees_rec(subposns, len, newbase, o,
- indpos, df_conflict_list)) {
+ df_conflict_list)) {
retval = -1;
goto leave_directory;
}
int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
{
- int indpos = 0;
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;
- struct cache_entry df_conflict_entry;
+ static struct cache_entry *dfc;
memset(&df_conflict_list, 0, sizeof(df_conflict_list));
df_conflict_list.next = &df_conflict_list;
state.refresh_cache = 1;
o->merge_size = len;
- memset(&df_conflict_entry, 0, sizeof(df_conflict_entry));
- o->df_conflict_entry = &df_conflict_entry;
+
+ if (!dfc)
+ dfc = xcalloc(1, sizeof(struct cache_entry) + 1);
+ o->df_conflict_entry = dfc;
if (len) {
posns = xmalloc(len * sizeof(struct tree_entry_list *));
posn = posn->next;
}
if (unpack_trees_rec(posns, len, o->prefix ? o->prefix : "",
- o, &indpos, &df_conflict_list))
+ o, &df_conflict_list))
return -1;
}
cache_tree_invalidate_path(active_cache_tree, ce->name);
}
+static int verify_clean_subdirectory(const char *path, const char *action,
+ struct unpack_trees_options *o)
+{
+ /*
+ * we are about to extract "path"; we would not want to lose
+ * anything in the existing directory there.
+ */
+ int namelen;
+ int pos, i;
+ struct dir_struct d;
+ char *pathbuf;
+ int cnt = 0;
+
+ /*
+ * First let's make sure we do not have a local modification
+ * in that directory.
+ */
+ namelen = strlen(path);
+ pos = cache_name_pos(path, namelen);
+ if (0 <= pos)
+ return cnt; /* we have it as nondirectory */
+ pos = -pos - 1;
+ for (i = pos; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ int len = ce_namelen(ce);
+ if (len < namelen ||
+ strncmp(path, ce->name, namelen) ||
+ ce->name[namelen] != '/')
+ break;
+ /*
+ * ce->name is an entry in the subdirectory.
+ */
+ if (!ce_stage(ce)) {
+ verify_uptodate(ce, o);
+ ce->ce_mode = 0;
+ }
+ cnt++;
+ }
+
+ /*
+ * Then we need to make sure that we do not lose a locally
+ * present file that is not ignored.
+ */
+ pathbuf = xmalloc(namelen + 2);
+ memcpy(pathbuf, path, namelen);
+ strcpy(pathbuf+namelen, "/");
+
+ memset(&d, 0, sizeof(d));
+ if (o->dir)
+ d.exclude_per_dir = o->dir->exclude_per_dir;
+ i = read_directory(&d, path, pathbuf, namelen+1, NULL);
+ if (i)
+ die("Updating '%s' would lose untracked files in it",
+ path);
+ free(pathbuf);
+ return cnt;
+}
+
/*
* We do not want to remove or overwrite a working tree file that
* is not tracked, unless it is ignored.
if (o->index_only || o->reset || !o->update)
return;
- if (!lstat(path, &st) && !(o->dir && excluded(o->dir, path)))
+
+ if (!lstat(path, &st)) {
+ int cnt;
+
+ if (o->dir && excluded(o->dir, path))
+ /*
+ * path is explicitly excluded, so it is Ok to
+ * overwrite it.
+ */
+ return;
+ if (S_ISDIR(st.st_mode)) {
+ /*
+ * We are checking out path "foo" and
+ * found "foo/." in the working tree.
+ * This is tricky -- if we have modified
+ * files that are in "foo/" we would lose
+ * it.
+ */
+ cnt = verify_clean_subdirectory(path, action, o);
+
+ /*
+ * If this removed entries from the index,
+ * what that means is:
+ *
+ * (1) the caller unpack_trees_rec() saw path/foo
+ * in the index, and it has not removed it because
+ * it thinks it is handling 'path' as blob with
+ * D/F conflict;
+ * (2) we will return "ok, we placed a merged entry
+ * in the index" which would cause o->pos to be
+ * incremented by one;
+ * (3) however, original o->pos now has 'path/foo'
+ * marked with "to be removed".
+ *
+ * We need to increment it by the number of
+ * deleted entries here.
+ */
+ o->pos += cnt;
+ return;
+ }
+
+ /*
+ * The previous round may already have decided to
+ * delete this path, which is in a subdirectory that
+ * is being replaced with a blob.
+ */
+ cnt = cache_name_pos(path, strlen(path));
+ if (0 <= cnt) {
+ struct cache_entry *ce = active_cache[cnt];
+ if (!ce_stage(ce) && !ce->ce_mode)
+ return;
+ }
+
die("Untracked working tree file '%s' "
"would be %s by merge.", path, action);
+ }
}
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
return 1;
}
-static int keep_entry(struct cache_entry *ce)
+static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o)
{
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
return 1;
int count;
int head_match = 0;
int remote_match = 0;
- const char *path = NULL;
int df_conflict_head = 0;
int df_conflict_remote = 0;
int i;
for (i = 1; i < o->head_idx; i++) {
- if (!stages[i])
+ if (!stages[i] || stages[i] == o->df_conflict_entry)
any_anc_missing = 1;
- else {
- if (!path)
- path = stages[i]->name;
+ else
no_anc_exists = 0;
- }
}
index = stages[0];
remote = NULL;
}
- if (!path && index)
- path = index->name;
- if (!path && head)
- path = head->name;
- if (!path && remote)
- path = remote->name;
-
/* First, if there's a #16 situation, note that to prevent #13
* and #14.
*/
if (o->aggressive) {
int head_deleted = !head && !df_conflict_head;
int remote_deleted = !remote && !df_conflict_remote;
+ const char *path = NULL;
+
+ if (index)
+ path = index->name;
+ else if (head)
+ path = head->name;
+ else if (remote)
+ path = remote->name;
+ else {
+ for (i = 1; i < o->head_idx; i++) {
+ if (stages[i] && stages[i] != o->df_conflict_entry) {
+ path = stages[i]->name;
+ break;
+ }
+ }
+ }
+
/*
* Deleted in both.
* Deleted in one and unchanged in the other.
o->nontrivial_merge = 1;
- /* #2, #3, #4, #6, #7, #9, #11. */
+ /* #2, #3, #4, #6, #7, #9, #10, #11. */
count = 0;
if (!head_match || !remote_match) {
for (i = 1; i < o->head_idx; i++) {
- if (stages[i]) {
- keep_entry(stages[i]);
+ if (stages[i] && stages[i] != o->df_conflict_entry) {
+ keep_entry(stages[i], o);
count++;
break;
}
show_stage_entry(stderr, "remote ", stages[remote_match]);
}
#endif
- if (head) { count += keep_entry(head); }
- if (remote) { count += keep_entry(remote); }
+ if (head) { count += keep_entry(head, o); }
+ if (remote) { count += keep_entry(remote, o); }
return count;
}
struct unpack_trees_options *o)
{
struct cache_entry *current = src[0];
- struct cache_entry *oldtree = src[1], *newtree = src[2];
+ struct cache_entry *oldtree = src[1];
+ struct cache_entry *newtree = src[2];
if (o->merge_size != 2)
return error("Cannot do a twoway merge of %d trees",
o->merge_size);
+ if (oldtree == o->df_conflict_entry)
+ oldtree = NULL;
+ if (newtree == o->df_conflict_entry)
+ newtree = NULL;
+
if (current) {
if ((!oldtree && !newtree) || /* 4 and 5 */
(!oldtree && newtree &&
(oldtree && newtree &&
same(oldtree, newtree)) || /* 14 and 15 */
(oldtree && newtree &&
- !same(oldtree, newtree) && /* 18 and 19*/
+ !same(oldtree, newtree) && /* 18 and 19 */
same(current, newtree))) {
- return keep_entry(current);
+ return keep_entry(current, o);
}
else if (oldtree && !newtree && same(current, oldtree)) {
/* 10 or 11 */
if (a && old)
die("Entry '%s' overlaps. Cannot bind.", a->name);
if (!a)
- return keep_entry(old);
+ return keep_entry(old, o);
else
return merged_entry(a, NULL, o);
}
ce_match_stat(old, &st, 1))
old->ce_flags |= htons(CE_UPDATE);
}
- return keep_entry(old);
+ return keep_entry(old, o);
}
return merged_entry(a, old, o);
}