1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-06-08 06:36:10 +02:00

git-read-tree: be a lot more careful about merging dirty trees

We don't want to overwrite state that we haven't committed yet
when merging, so it's better to make git-read-tree fail than
end up with a merge tree that ends up not having the dirty changes.

Update git-resolve-script to fail cleanly when git-read-tree fails.
This commit is contained in:
Linus Torvalds 2005-06-05 20:02:31 -07:00
parent 9b63f50148
commit 02ede67ad4
2 changed files with 54 additions and 5 deletions

View File

@ -39,13 +39,14 @@ if [ "$common" == "$head" ]; then
echo "Destroying all noncommitted data!"
echo "Kill me within 3 seconds.."
sleep 3
git-read-tree -m $merge && git-checkout-cache -f -u -a
git-read-tree -m $merge || exit 1
git-checkout-cache -f -u -a
echo $merge > "$GIT_DIR"/HEAD
git-diff-tree -p ORIG_HEAD HEAD | git-apply --stat
exit 0
fi
echo "Trying to merge $merge into $head"
git-read-tree -m $common $head $merge
git-read-tree -m $common $head $merge || exit 1
merge_msg="Merge of $merge_repo"
result_tree=$(git-write-tree 2> /dev/null)
if [ $? -ne 0 ]; then

View File

@ -93,11 +93,46 @@ static struct cache_entry *merge_entries(struct cache_entry *a,
return NULL;
}
/*
* When a CE gets turned into an unmerged entry, we
* want it to be up-to-date
*/
static void verify_uptodate(struct cache_entry *ce)
{
struct stat st;
if (!lstat(ce->name, &st)) {
unsigned changed = ce_match_stat(ce, &st);
if (!changed)
return;
errno = 0;
}
if (errno == ENOENT)
return;
die("Entry '%s' not uptodate. Cannot merge.", ce->name);
}
/*
* If the old tree contained a CE that isn't even in the
* result, that's always a problem, regardless of whether
* it's up-to-date or not (ie it can be a file that we
* have updated but not committed yet).
*/
static void verify_cleared(struct cache_entry *ce)
{
if (ce)
die("Entry '%s' would be overwritten by merge. Cannot merge.", ce->name);
}
static int old_match(struct cache_entry *old, struct cache_entry *a)
{
return old && path_matches(old, a) && same(old, a);
}
static void trivially_merge_cache(struct cache_entry **src, int nr)
{
static struct cache_entry null_entry;
struct cache_entry **dst = src;
struct cache_entry *old = &null_entry;
struct cache_entry *old = NULL;
while (nr) {
struct cache_entry *ce, *result;
@ -106,6 +141,7 @@ static void trivially_merge_cache(struct cache_entry **src, int nr)
/* We throw away original cache entries except for the stat information */
if (!ce_stage(ce)) {
verify_cleared(old);
old = ce;
src++;
nr--;
@ -117,18 +153,30 @@ static void trivially_merge_cache(struct cache_entry **src, int nr)
* See if we can re-use the old CE directly?
* That way we get the uptodate stat info.
*/
if (path_matches(result, old) && same(result, old))
if (old_match(old, result)) {
*result = *old;
old = NULL;
}
ce = result;
ce->ce_flags &= ~htons(CE_STAGEMASK);
src += 2;
nr -= 2;
active_nr -= 2;
}
/*
* If we had an old entry that we now effectively
* overwrite, make sure it wasn't dirty.
*/
if (old_match(old, ce)) {
verify_uptodate(old);
old = NULL;
}
*dst++ = ce;
src++;
nr--;
}
verify_cleared(old);
}
static void merge_stat_info(struct cache_entry **src, int nr)