Skip to content

Commit

Permalink
read-tree -m -u: do not overwrite or remove untracked working tree fi…
Browse files Browse the repository at this point in the history
…les.

When a merge results in a creation of a path that did not exist
in HEAD, and if you already have that path on the working tree,
because the index has not been told about the working tree file,
read-tree happily removes it.  The issue was brought up by Santi
Béjar on the list.

Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Junio C Hamano committed May 17, 2006
1 parent 63dffdf commit fcc387d
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 31 deletions.
45 changes: 40 additions & 5 deletions read-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,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)) {
Expand All @@ -426,6 +426,21 @@ static void verify_uptodate(struct cache_entry *ce)
die("Entry '%s' not uptodate. Cannot merge.", 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);
Expand All @@ -443,6 +458,9 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old)
verify_uptodate(old);
}
}
else
verify_absent(merge->name, "overwritten");

merge->ce_flags &= ~htons(CE_STAGEMASK);
add_cache_entry(merge, ADD_CACHE_OK_TO_ADD);
return 1;
Expand All @@ -452,6 +470,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);
return 1;
Expand Down Expand Up @@ -487,6 +507,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;
Expand All @@ -498,8 +519,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];
Expand All @@ -515,8 +539,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++) {
Expand Down Expand Up @@ -575,6 +606,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;
}
/*
Expand All @@ -592,6 +625,8 @@ static int threeway_merge(struct cache_entry **stages)
if (index) {
verify_uptodate(index);
}
else if (path)
verify_absent(path, "overwritten");

nontrivial_merge = 1;

Expand Down Expand Up @@ -689,7 +724,7 @@ static int oneway_merge(struct cache_entry **src)
merge_size);

if (!a)
return deleted_entry(old, NULL);
return deleted_entry(old, old);
if (old && same(old, a)) {
if (reset) {
struct stat st;
Expand All @@ -699,7 +734,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)
Expand Down
66 changes: 43 additions & 23 deletions t/t1002-read-tree-m-u-2way.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ test_expect_success \
echo nitfol >nitfol &&
echo bozbar >bozbar &&
echo rezrov >rezrov &&
echo yomin >yomin &&
git-update-index --add nitfol bozbar rezrov &&
treeH=`git-write-tree` &&
echo treeH $treeH &&
Expand All @@ -56,7 +55,8 @@ test_expect_success \

test_expect_success \
'1, 2, 3 - no carry forward' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
git-read-tree -m -u $treeH $treeM &&
git-ls-files --stage >1-3.out &&
cmp M.out 1-3.out &&
Expand All @@ -66,11 +66,12 @@ test_expect_success \
check_cache_at frotz clean &&
check_cache_at nitfol clean'

echo '+100644 X 0 yomin' >expected

test_expect_success \
'4 - carry forward local addition.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo "+100644 X 0 yomin" >expected &&
echo yomin >yomin &&
git-update-index --add yomin &&
git-read-tree -m -u $treeH $treeM &&
git-ls-files --stage >4.out || return 1
Expand All @@ -85,7 +86,9 @@ test_expect_success \

test_expect_success \
'5 - carry forward local addition.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
git-read-tree -m -u $treeH &&
echo yomin >yomin &&
git-update-index --add yomin &&
echo yomin yomin >yomin &&
Expand All @@ -103,7 +106,9 @@ test_expect_success \

test_expect_success \
'6 - local addition already has the same.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo frotz >frotz &&
git-update-index --add frotz &&
git-read-tree -m -u $treeH $treeM &&
git-ls-files --stage >6.out &&
Expand All @@ -117,7 +122,8 @@ test_expect_success \

test_expect_success \
'7 - local addition already has the same.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo frotz >frotz &&
git-update-index --add frotz &&
echo frotz frotz >frotz &&
Expand All @@ -134,22 +140,25 @@ test_expect_success \

test_expect_success \
'8 - conflicting addition.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo frotz frotz >frotz &&
git-update-index --add frotz &&
if git-read-tree -m -u $treeH $treeM; then false; else :; fi'

test_expect_success \
'9 - conflicting addition.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo frotz frotz >frotz &&
git-update-index --add frotz &&
echo frotz >frotz &&
if git-read-tree -m -u $treeH $treeM; then false; else :; fi'

test_expect_success \
'10 - path removed.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo rezrov >rezrov &&
git-update-index --add rezrov &&
git-read-tree -m -u $treeH $treeM &&
Expand All @@ -160,22 +169,25 @@ test_expect_success \

test_expect_success \
'11 - dirty path removed.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo rezrov >rezrov &&
git-update-index --add rezrov &&
echo rezrov rezrov >rezrov &&
if git-read-tree -m -u $treeH $treeM; then false; else :; fi'

test_expect_success \
'12 - unmatching local changes being removed.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo rezrov rezrov >rezrov &&
git-update-index --add rezrov &&
if git-read-tree -m -u $treeH $treeM; then false; else :; fi'

test_expect_success \
'13 - unmatching local changes being removed.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo rezrov rezrov >rezrov &&
git-update-index --add rezrov &&
echo rezrov >rezrov &&
Expand All @@ -188,7 +200,8 @@ EOF

test_expect_success \
'14 - unchanged in two heads.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo nitfol nitfol >nitfol &&
git-update-index --add nitfol &&
git-read-tree -m -u $treeH $treeM &&
Expand All @@ -207,7 +220,8 @@ test_expect_success \

test_expect_success \
'15 - unchanged in two heads.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo nitfol nitfol >nitfol &&
git-update-index --add nitfol &&
echo nitfol nitfol nitfol >nitfol &&
Expand All @@ -227,22 +241,25 @@ test_expect_success \

test_expect_success \
'16 - conflicting local change.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo bozbar bozbar >bozbar &&
git-update-index --add bozbar &&
if git-read-tree -m -u $treeH $treeM; then false; else :; fi'

test_expect_success \
'17 - conflicting local change.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo bozbar bozbar >bozbar &&
git-update-index --add bozbar &&
echo bozbar bozbar bozbar >bozbar &&
if git-read-tree -m -u $treeH $treeM; then false; else :; fi'

test_expect_success \
'18 - local change already having a good result.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo gnusto >bozbar &&
git-update-index --add bozbar &&
git-read-tree -m -u $treeH $treeM &&
Expand All @@ -254,7 +271,8 @@ test_expect_success \

test_expect_success \
'19 - local change already having a good result, further modified.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo gnusto >bozbar &&
git-update-index --add bozbar &&
echo gnusto gnusto >bozbar &&
Expand All @@ -273,7 +291,8 @@ test_expect_success \

test_expect_success \
'20 - no local change, use new tree.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo bozbar >bozbar &&
git-update-index --add bozbar &&
git-read-tree -m -u $treeH $treeM &&
Expand All @@ -285,7 +304,8 @@ test_expect_success \

test_expect_success \
'21 - no local change, dirty cache.' \
'rm -f .git/index &&
'rm -f .git/index nitfol bozbar rezrov frotz &&
git-read-tree --reset -u $treeH &&
echo bozbar >bozbar &&
git-update-index --add bozbar &&
echo gnusto gnusto >bozbar &&
Expand All @@ -294,7 +314,7 @@ test_expect_success \
# Also make sure we did not break DF vs DF/DF case.
test_expect_success \
'DF vs DF/DF case setup.' \
'rm -f .git/index &&
'rm -f .git/index
echo DF >DF &&
git-update-index --add DF &&
treeDF=`git-write-tree` &&
Expand Down
1 change: 1 addition & 0 deletions t/t3500-cherry.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ test_expect_success \
git-commit -m "Add C." &&
git-checkout -f master &&
rm -f B C &&
echo Third >> A &&
git-update-index A &&
Expand Down
6 changes: 3 additions & 3 deletions t/t4002-diff-basic.sh
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ test_expect_success \
'rm -fr Z [A-Z][A-Z] &&
git-read-tree $tree_A &&
git-checkout-index -f -a &&
git-read-tree -m $tree_O || return 1
git-read-tree --reset $tree_O || return 1
git-update-index --refresh >/dev/null ;# this can exit non-zero
git-diff-files >.test-a &&
cmp_diff_files_output .test-a .test-recursive-OA'
Expand All @@ -201,7 +201,7 @@ test_expect_success \
'rm -fr Z [A-Z][A-Z] &&
git-read-tree $tree_B &&
git-checkout-index -f -a &&
git-read-tree -m $tree_O || return 1
git-read-tree --reset $tree_O || return 1
git-update-index --refresh >/dev/null ;# this can exit non-zero
git-diff-files >.test-a &&
cmp_diff_files_output .test-a .test-recursive-OB'
Expand All @@ -211,7 +211,7 @@ test_expect_success \
'rm -fr Z [A-Z][A-Z] &&
git-read-tree $tree_B &&
git-checkout-index -f -a &&
git-read-tree -m $tree_A || return 1
git-read-tree --reset $tree_A || return 1
git-update-index --refresh >/dev/null ;# this can exit non-zero
git-diff-files >.test-a &&
cmp_diff_files_output .test-a .test-recursive-AB'
Expand Down
1 change: 1 addition & 0 deletions t/t6022-merge-rename.sh
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ test_expect_success 'pull renaming branch into unrenaming one' \

test_expect_success 'pull renaming branch into another renaming one' \
'
rm -f B
git reset --hard
git checkout red
git pull . white && {
Expand Down

0 comments on commit fcc387d

Please sign in to comment.