Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Changes: do not lose worktree's executable permission. t/t1011-read-tree-sparse-checkout.sh | 3 ++- t/t2021-checkout-overwrite.sh | 18 ++++++++++++++++++ unpack-trees.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 5c0053a..38f9899 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -238,7 +238,8 @@ test_expect_success 'print errors when failed to update worktree' ' echo sub >.git/info/sparse-checkout && git checkout -f init && mkdir sub && - touch sub/added sub/addedtoo && + echo modified >sub/added && + echo modified >sub/addedtoo && test_must_fail git checkout top 2>actual && cat >expected <<\EOF && error: The following untracked working tree files would be overwritten by checkout: diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh index 5da63e9..bb1696d 100755 --- a/t/t2021-checkout-overwrite.sh +++ b/t/t2021-checkout-overwrite.sh @@ -47,4 +47,22 @@ test_expect_success SYMLINKS 'checkout commit with dir must not remove untracked test -h a/b ' +test_expect_success 'do not abort on overwriting an existing file with the same content' ' + echo abc >bar && + git add bar && + git commit -m "new file" && + git reset HEAD^ && + git checkout HEAD@{1} +' + +test_expect_success POSIXPERM 'do abort on an existing file, same content but different permission' ' + git checkout -f HEAD^ && + echo abc >bar && + git add bar && + git commit -m "new file" && + git reset HEAD^ && + chmod a+x bar && + test_must_fail git checkout HEAD@{1} +' + test_done diff --git a/unpack-trees.c b/unpack-trees.c index 0e1a196..ea204ae 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -9,6 +9,8 @@ #include "refs.h" #include "attr.h" +#define SAME_CONTENT_SIZE_LIMIT (1024 * 1024) + /* * Error messages expected by scripts out of plumbing commands such as * read-tree. Non-scripted Porcelain is not required to use these messages @@ -1363,6 +1365,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype, struct unpack_trees_options *o) { struct cache_entry *result; + unsigned long ce_size; /* * It may be that the 'lstat()' succeeded even though @@ -1405,6 +1408,34 @@ static int check_ok_to_remove(const char *name, int len, int dtype, return 0; } + /* + * If it has the same content that we are going to overwrite, + * there's no point in complaining. We still overwrite it in + * the end though. + */ + if (ce && + S_ISREG(st->st_mode) && S_ISREG(ce->ce_mode) && + (!trust_executable_bit || + (0100 & (ce->ce_mode ^ st->st_mode)) == 0) && + st->st_size < SAME_CONTENT_SIZE_LIMIT && + sha1_object_info(ce->sha1, &ce_size) == OBJ_BLOB && + ce_size == st->st_size) { + void *buffer = NULL; + unsigned long size; + enum object_type type; + struct strbuf sb = STRBUF_INIT; + int matched = + strbuf_read_file(&sb, ce->name, ce_size) == ce_size && + (buffer = read_sha1_file(ce->sha1, &type, &size)) != NULL && + type == OBJ_BLOB && + size == ce_size && + !memcmp(buffer, sb.buf, size); + free(buffer); + strbuf_release(&sb); + if (matched) + return 0; + } + return o->gently ? -1 : add_rejected_path(o, error_type, name); } -- 1.8.0.rc2.23.g1fb49df -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html