Merge branch 'jc/read-tree-safety' into next
* jc/read-tree-safety: read-tree -m -u: do not overwrite or remove untracked working tree files.
This commit is contained in:
47
read-tree.c
47
read-tree.c
@ -411,7 +411,7 @@ static void verify_uptodate(struct cache_entry *ce)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (index_only)
|
||||
if (index_only || reset)
|
||||
return;
|
||||
|
||||
if (!lstat(ce->name, &st)) {
|
||||
@ -435,6 +435,21 @@ static void invalidate_ce_path(struct cache_entry *ce)
|
||||
cache_tree_invalidate_path(active_cache_tree, ce->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not want to remove or overwrite a working tree file that
|
||||
* is not tracked.
|
||||
*/
|
||||
static void verify_absent(const char *path, const char *action)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (index_only || reset || !update)
|
||||
return;
|
||||
if (!lstat(path, &st))
|
||||
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)
|
||||
{
|
||||
merge->ce_flags |= htons(CE_UPDATE);
|
||||
@ -453,8 +468,11 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old)
|
||||
invalidate_ce_path(old);
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
verify_absent(merge->name, "overwritten");
|
||||
invalidate_ce_path(merge);
|
||||
}
|
||||
|
||||
merge->ce_flags &= ~htons(CE_STAGEMASK);
|
||||
add_cache_entry(merge, ADD_CACHE_OK_TO_ADD);
|
||||
return 1;
|
||||
@ -464,6 +482,8 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old)
|
||||
{
|
||||
if (old)
|
||||
verify_uptodate(old);
|
||||
else
|
||||
verify_absent(ce->name, "removed");
|
||||
ce->ce_mode = 0;
|
||||
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
|
||||
invalidate_ce_path(ce);
|
||||
@ -500,6 +520,7 @@ static int threeway_merge(struct cache_entry **stages)
|
||||
int count;
|
||||
int head_match = 0;
|
||||
int remote_match = 0;
|
||||
const char *path = NULL;
|
||||
|
||||
int df_conflict_head = 0;
|
||||
int df_conflict_remote = 0;
|
||||
@ -511,8 +532,11 @@ static int threeway_merge(struct cache_entry **stages)
|
||||
for (i = 1; i < head_idx; i++) {
|
||||
if (!stages[i])
|
||||
any_anc_missing = 1;
|
||||
else
|
||||
else {
|
||||
if (!path)
|
||||
path = stages[i]->name;
|
||||
no_anc_exists = 0;
|
||||
}
|
||||
}
|
||||
|
||||
index = stages[0];
|
||||
@ -528,8 +552,15 @@ static int threeway_merge(struct cache_entry **stages)
|
||||
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.
|
||||
* and #14.
|
||||
*/
|
||||
if (!same(remote, head)) {
|
||||
for (i = 1; i < head_idx; i++) {
|
||||
@ -588,6 +619,8 @@ static int threeway_merge(struct cache_entry **stages)
|
||||
(remote_deleted && head && head_match)) {
|
||||
if (index)
|
||||
return deleted_entry(index, index);
|
||||
else if (path)
|
||||
verify_absent(path, "removed");
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
@ -605,6 +638,8 @@ static int threeway_merge(struct cache_entry **stages)
|
||||
if (index) {
|
||||
verify_uptodate(index);
|
||||
}
|
||||
else if (path)
|
||||
verify_absent(path, "overwritten");
|
||||
|
||||
nontrivial_merge = 1;
|
||||
|
||||
@ -725,7 +760,7 @@ static int oneway_merge(struct cache_entry **src)
|
||||
|
||||
if (!a) {
|
||||
invalidate_ce_path(old);
|
||||
return deleted_entry(old, NULL);
|
||||
return deleted_entry(old, old);
|
||||
}
|
||||
if (old && same(old, a)) {
|
||||
if (reset) {
|
||||
@ -736,7 +771,7 @@ static int oneway_merge(struct cache_entry **src)
|
||||
}
|
||||
return keep_entry(old);
|
||||
}
|
||||
return merged_entry(a, NULL);
|
||||
return merged_entry(a, old);
|
||||
}
|
||||
|
||||
static int read_cache_unmerged(void)
|
||||
|
Reference in New Issue
Block a user