diff options
author | Jeff King <peff@peff.net> | 2014-11-13 13:30:34 -0500 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-11-13 14:35:41 -0800 |
commit | c5326bd62b7e168ba1339dacb7ee812d0fe98c7c (patch) | |
tree | c2eff6145f8367208cd648a6b19dcdcaee459e0d /builtin/checkout.c | |
parent | eeff891ac756fd97a05476446f15269b714ce4cc (diff) | |
download | git-c5326bd62b7e168ba1339dacb7ee812d0fe98c7c.tar.gz git-c5326bd62b7e168ba1339dacb7ee812d0fe98c7c.tar.xz |
checkout $tree: do not throw away unchanged index entries
When we "git checkout $tree", we pull paths from $tree into
the index, and then check the resulting entries out to the
worktree. Our method for the first step is rather
heavy-handed, though; it clobbers the entire existing index
entry, even if the content is the same. This means we lose
our stat information, leading checkout_entry to later
rewrite the entire file with identical content.
Instead, let's see if we have the identical entry already in
the index, in which case we leave it in place. That lets
checkout_entry do the right thing. Our tests cover two
interesting cases:
1. We make sure that a file which has no changes is not
rewritten.
2. We make sure that we do update a file that is unchanged
in the index (versus $tree), but has working tree
changes. We keep the old index entry, and
checkout_entry is able to realize that our stat
information is out of date.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/checkout.c')
-rw-r--r-- | builtin/checkout.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/builtin/checkout.c b/builtin/checkout.c index 54f80bd38..8129eee83 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -67,6 +67,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen, { int len; struct cache_entry *ce; + int pos; if (S_ISDIR(mode)) return READ_TREE_RECURSIVE; @@ -79,6 +80,23 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen, ce->ce_flags = create_ce_flags(0) | CE_UPDATE; ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); + + /* + * If the entry is the same as the current index, we can leave the old + * entry in place. Whether it is UPTODATE or not, checkout_entry will + * do the right thing. + */ + pos = cache_name_pos(ce->name, ce->ce_namelen); + if (pos >= 0) { + struct cache_entry *old = active_cache[pos]; + if (ce->ce_mode == old->ce_mode && + !hashcmp(ce->sha1, old->sha1)) { + old->ce_flags |= CE_UPDATE; + free(ce); + return 0; + } + } + add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); return 0; } |