From aa6dff74b747c009fa970b498a72bc144df66abd Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Mar 2012 14:53:24 -0400 Subject: drop casts from users EMPTY_TREE_SHA1_BIN This macro already evaluates to the correct type, as it casts the string literal to "unsigned char *" itself (and callers who want the literal can use the _LITERAL form). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/diff.c | 2 +- merge-recursive.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/diff.c b/builtin/diff.c index 0fe638fc45..b2a9405a72 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -323,7 +323,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) add_head_to_pending(&rev); if (!rev.pending.nr) { struct tree *tree; - tree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(EMPTY_TREE_SHA1_BIN); add_pending_object(&rev, &tree->object, "HEAD"); } break; diff --git a/merge-recursive.c b/merge-recursive.c index c34a4f148b..5e2bc4fbd2 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1913,7 +1913,7 @@ int merge_recursive(struct merge_options *o, /* if there is no common ancestor, use an empty tree */ struct tree *tree; - tree = lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(EMPTY_TREE_SHA1_BIN); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } -- cgit v1.2.1 From 480dd8b8365406bfa47fed87ed59ca5df672e716 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Mar 2012 14:53:39 -0400 Subject: make is_empty_blob_sha1 available everywhere The read-cache implementation defines this static function, but it is a generally useful concept in git. Let's give the empty blob the same treatment as the empty tree, providing both hex and binary forms of the sha1. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- cache.h | 13 +++++++++++++ read-cache.c | 10 ---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cache.h b/cache.h index 8d95fb25a2..7e1122755a 100644 --- a/cache.h +++ b/cache.h @@ -705,6 +705,19 @@ static inline void hashclr(unsigned char *hash) #define EMPTY_TREE_SHA1_BIN \ ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL) +#define EMPTY_BLOB_SHA1_HEX \ + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" +#define EMPTY_BLOB_SHA1_BIN_LITERAL \ + "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \ + "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91" +#define EMPTY_BLOB_SHA1_BIN \ + ((const unsigned char *) EMPTY_BLOB_SHA1_BIN_LITERAL) + +static inline int is_empty_blob_sha1(const unsigned char *sha1) +{ + return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN); +} + int git_mkstemp(char *path, size_t n, const char *template); int git_mkstemps(char *path, size_t n, const char *template, int suffix_len); diff --git a/read-cache.c b/read-cache.c index 5790a91044..21aab4f9ba 100644 --- a/read-cache.c +++ b/read-cache.c @@ -157,16 +157,6 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) return 0; } -static int is_empty_blob_sha1(const unsigned char *sha1) -{ - static const unsigned char empty_blob_sha1[20] = { - 0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b, - 0x29,0xae,0x77,0x5a,0xd8,0xc2,0xe4,0x8c,0x53,0x91 - }; - - return !hashcmp(sha1, empty_blob_sha1); -} - static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) { unsigned int changed = 0; -- cgit v1.2.1 From 536caca5ce0d88e4c54e9e7376ed182807702c58 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Mar 2012 14:53:49 -0400 Subject: merge-recursive: don't detect renames from empty files Merge-recursive detects renames so that if one side modifies "foo" and the other side moves it to "bar", the modification is applied to "bar". However, our rename detection is based on content analysis, it can be wrong (i.e., two files were not intended as a rename, but just happen to have the same or similar content). This is quite rare if the files actually contain content, since two unrelated files are unlikely to have exactly the same content. However, empty files present a problem, in that there is nothing to analyze. An uninteresting placeholder file with zero bytes may or may not be related to a placeholder file with another name. The result is that adding content to an empty file may cause confusion if the other side of a merge removed it; your content may end up in another random placeholder file that was added. Let's err on the side of caution and not consider empty files as renames. This will cause a modify/delete conflict on the merge, which will let the user sort it out themselves. We could do the same thing for general diff rename detection. However, the stakes are much less high there, as we are explicitly reporting the rename to the user. It's only the automatic nature of merge-recursive that makes the result confusing. So there's not as much need for caution when just showing a diff. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- merge-recursive.c | 2 +- t/t6022-merge-rename.sh | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/merge-recursive.c b/merge-recursive.c index 5e2bc4fbd2..833b65536f 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -503,7 +503,7 @@ static struct string_list *get_renames(struct merge_options *o, struct string_list_item *item; struct rename *re; struct diff_filepair *pair = diff_queued_diff.queue[i]; - if (pair->status != 'R') { + if (pair->status != 'R' || is_empty_blob_sha1(pair->one->sha1)) { diff_free_filepair(pair); continue; } diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index 9d8584e957..1104249182 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -884,4 +884,20 @@ test_expect_success 'no spurious "refusing to lose untracked" message' ' ! grep "refusing to lose untracked file" errors.txt ' +test_expect_success 'do not follow renames for empty files' ' + git checkout -f -b empty-base && + >empty1 && + git add empty1 && + git commit -m base && + echo content >empty1 && + git add empty1 && + git commit -m fill && + git checkout -b empty-topic HEAD^ && + git mv empty1 empty2 && + git commit -m rename && + test_must_fail git merge empty-base && + >expect && + test_cmp expect empty2 +' + test_done -- cgit v1.2.1