git-blame shouldn't crash if run in an unmerged tree

If we are in the middle of resolving a merge conflict there may be
one or more files whose entries in the index represent an unmerged
state (index entries in the higher-order stages).

Attempting to run git-blame on any file in such a working directory
resulted in "fatal: internal error: ce_mode is 0" as we use the magic
marker for an unmerged entry is 0 (set up by things like diff-lib.c's
do_diff_cache() and builtin-read-tree.c's read_tree_unmerged())
and the ce_match_stat_basic() function gets upset about this.

I'm not entirely sure that the whole "ce_mode = 0" case is a good
idea to begin with, and maybe the right thing to do is to remove
that horrid freakish special case, but removing the internal error
seems to be the simplest fix for now.

                Linus

[sp: Thanks to Björn Steinbrink for the test case]

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Linus Torvalds 2007-10-18 02:31:30 -04:00 committed by Shawn O. Pearce
parent 93a56c2cf7
commit cd8ae20195
2 changed files with 75 additions and 0 deletions

View file

@ -149,6 +149,8 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
else if (ce_compare_gitlink(ce))
changed |= DATA_CHANGED;
return changed;
case 0: /* Special case: unmerged file in index */
return MODE_CHANGED | DATA_CHANGED | TYPE_CHANGED;
default:
die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
}

73
t/t8004-blame.sh Executable file
View file

@ -0,0 +1,73 @@
#!/bin/sh
# Based on a test case submitted by Björn Steinbrink.
test_description='git blame on conflicted files'
. ./test-lib.sh
test_expect_success 'setup first case' '
# Create the old file
echo "Old line" > file1 &&
git add file1 &&
git commit --author "Old Line <ol@localhost>" -m file1.a &&
# Branch
git checkout -b foo &&
# Do an ugly move and change
git rm file1 &&
echo "New line ..." > file2 &&
echo "... and more" >> file2 &&
git add file2 &&
git commit --author "U Gly <ug@localhost>" -m ugly &&
# Back to master and change something
git checkout master &&
echo "
bla" >> file1 &&
git commit --author "Old Line <ol@localhost>" -a -m file1.b &&
# Back to foo and merge master
git checkout foo &&
if git merge master; then
echo needed conflict here
exit 1
else
echo merge failed - resolving automatically
fi &&
echo "New line ...
... and more
bla
Even more" > file2 &&
git rm file1 &&
git commit --author "M Result <mr@localhost>" -a -m merged &&
# Back to master and change file1 again
git checkout master &&
sed s/bla/foo/ <file1 >X &&
rm file1 &&
mv X file1 &&
git commit --author "No Bla <nb@localhost>" -a -m replace &&
# Try to merge into foo again
git checkout foo &&
if git merge master; then
echo needed conflict here
exit 1
else
echo merge failed - test is setup
fi
'
test_expect_success \
'blame runs on unconflicted file while other file has conflicts' '
git blame file2
'
test_expect_success 'blame runs on conflicted file in stages 1,3' '
git blame file1
'
test_done