From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 20/24] reset --hard: keep backup of overwritten files
Date: Sun, 9 Dec 2018 11:44:15 +0100 [thread overview]
Message-ID: <20181209104419.12639-21-pclouds@gmail.com> (raw)
In-Reply-To: <20181209104419.12639-1-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin/reset.c | 2 ++
merge-recursive.c | 2 +-
t/t2080-backup-log.sh | 14 +++++++++
unpack-trees.c | 70 +++++++++++++++++++++++++++++++++----------
unpack-trees.h | 3 +-
5 files changed, 74 insertions(+), 17 deletions(-)
diff --git a/builtin/reset.c b/builtin/reset.c
index 58166964f8..517a27dce5 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -67,6 +67,8 @@ static int reset_index(const struct object_id *oid, int reset_type, int quiet)
break;
case HARD:
opts.update = 1;
+ repo_config_get_bool(the_repository, "core.backupLog",
+ &opts.keep_backup);
/* fallthrough */
default:
opts.reset = 1;
diff --git a/merge-recursive.c b/merge-recursive.c
index acc2f64a4e..10a9d3180a 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -896,7 +896,7 @@ static int was_dirty(struct merge_options *o, const char *path)
ce = index_file_exists(o->unpack_opts.src_index,
path, strlen(path), ignore_case);
- dirty = verify_uptodate(ce, &o->unpack_opts) != 0;
+ dirty = verify_uptodate(ce, &o->unpack_opts, NULL) != 0;
return dirty;
}
diff --git a/t/t2080-backup-log.sh b/t/t2080-backup-log.sh
index a283528912..901755ce93 100755
--- a/t/t2080-backup-log.sh
+++ b/t/t2080-backup-log.sh
@@ -211,4 +211,18 @@ test_expect_success 'overwritten ignored file is backed up' '
)
'
+test_expect_success 'overwritten out-of-date file is backed up' '
+ git init overwrite-outofdate &&
+ (
+ cd overwrite-outofdate &&
+ test_commit haha &&
+ NEW=$(git hash-object haha.t) &&
+ echo bad >>haha.t &&
+ OLD=$(git hash-object haha.t) &&
+ git -c core.backupLog reset --hard &&
+ echo "$OLD $NEW $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $test_tick -0700 haha.t" >expected &&
+ test_cmp expected .git/worktree.bkl
+ )
+'
+
test_done
diff --git a/unpack-trees.c b/unpack-trees.c
index 8d7273af2b..221869b47c 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1715,7 +1715,8 @@ static int same(const struct cache_entry *a, const struct cache_entry *b)
*/
static int verify_uptodate_1(const struct cache_entry *ce,
struct unpack_trees_options *o,
- enum unpack_trees_error_types error_type)
+ enum unpack_trees_error_types error_type,
+ struct object_id *old_hash)
{
struct stat st;
@@ -1727,10 +1728,16 @@ static int verify_uptodate_1(const struct cache_entry *ce,
* if this entry is truly up-to-date because this file may be
* overwritten.
*/
- if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))
+ if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
; /* keep checking */
- else if (o->reset || ce_uptodate(ce))
+ } else if (o->reset) {
+ if (o->keep_backup && old_hash && !lstat(ce->name, &st))
+ index_path(NULL, old_hash, ce->name, &st,
+ HASH_WRITE_OBJECT);
+ return 0;
+ } else if (ce_uptodate(ce)) {
return 0;
+ }
if (!lstat(ce->name, &st)) {
int flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE;
@@ -1764,17 +1771,20 @@ static int verify_uptodate_1(const struct cache_entry *ce,
}
int verify_uptodate(const struct cache_entry *ce,
- struct unpack_trees_options *o)
+ struct unpack_trees_options *o,
+ struct object_id *old_hash)
{
+ if (o->keep_backup && old_hash)
+ oidclr(old_hash);
if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
return 0;
- return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
+ return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE, old_hash);
}
static int verify_uptodate_sparse(const struct cache_entry *ce,
struct unpack_trees_options *o)
{
- return verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);
+ return verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE, NULL);
}
/*
@@ -1862,8 +1872,11 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
* removed.
*/
if (!ce_stage(ce2)) {
- if (verify_uptodate(ce2, o))
+ struct object_id old_hash;
+
+ if (verify_uptodate(ce2, o, &old_hash))
return -1;
+ make_backup(ce2, &old_hash, NULL, o);
add_entry(o, ce2, CE_REMOVE, 0);
invalidate_ce_path(ce, o);
mark_ce_used(ce2, o);
@@ -1973,8 +1986,13 @@ static int verify_absent_1(const struct cache_entry *ce,
int len;
struct stat st;
- if (o->index_only || o->reset || !o->update)
+ if (o->index_only || o->reset || !o->update) {
+ if (o->reset && o->keep_backup &&
+ old_hash && !lstat(ce->name, &st))
+ index_path(NULL, old_hash, ce->name, &st,
+ HASH_WRITE_OBJECT);
return 0;
+ }
len = check_leading_path(ce->name, ce_namelen(ce));
if (!len)
@@ -2092,10 +2110,12 @@ static int merged_entry(const struct cache_entry *ce,
copy_cache_entry(merge, old);
update = 0;
} else {
- if (verify_uptodate(old, o)) {
+ struct object_id old_hash;
+ if (verify_uptodate(old, o, &old_hash)) {
discard_cache_entry(merge);
return -1;
}
+ make_backup(old, &old_hash, &merge->oid, o);
/* Migrate old flags over */
update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
invalidate_ce_path(old, o);
@@ -2124,18 +2144,20 @@ static int deleted_entry(const struct cache_entry *ce,
const struct cache_entry *old,
struct unpack_trees_options *o)
{
+ struct object_id old_hash;
+
/* Did it exist in the index? */
if (!old) {
- struct object_id old_hash;
-
if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED,
o, &old_hash))
return -1;
make_backup(ce, &old_hash, NULL, o);
return 0;
}
- if (!(old->ce_flags & CE_CONFLICTED) && verify_uptodate(old, o))
+ if (!(old->ce_flags & CE_CONFLICTED) &&
+ verify_uptodate(old, o, &old_hash))
return -1;
+ make_backup(ce, &old_hash, NULL, o);
add_entry(o, ce, CE_REMOVE, 0);
invalidate_ce_path(ce, o);
return 1;
@@ -2305,8 +2327,16 @@ int threeway_merge(const struct cache_entry * const *stages,
* conflict resolution files.
*/
if (index) {
- if (verify_uptodate(index, o))
+ struct object_id old_hash;
+
+ if (verify_uptodate(index, o, &old_hash))
return -1;
+ /*
+ * A new conflict appears. We could make a backup from
+ * worktree version to stage 2 or 3. But neither makes much
+ * sense. Make a deletion backup instead.
+ */
+ make_backup(index, &old_hash, NULL, o);
}
o->nontrivial_merge = 1;
@@ -2447,16 +2477,26 @@ int oneway_merge(const struct cache_entry * const *src,
return deleted_entry(old, old, o);
if (old && same(old, a)) {
+ struct object_id old_hash;
int update = 0;
+
+ oidclr(&old_hash);
if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) {
struct stat st;
+
if (lstat(old->name, &st) ||
- ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
+ ie_match_stat(o->src_index, old, &st,
+ CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
update |= CE_UPDATE;
+
+ if (update & CE_UPDATE && o->keep_backup)
+ index_path(NULL, &old_hash, old->name, &st,
+ HASH_WRITE_OBJECT);
}
if (o->update && S_ISGITLINK(old->ce_mode) &&
- should_update_submodules() && !verify_uptodate(old, o))
+ should_update_submodules() && !verify_uptodate(old, o, NULL))
update |= CE_UPDATE;
+ make_backup(old, &old_hash, &old->oid, o);
add_entry(o, old, update, 0);
return 0;
}
diff --git a/unpack-trees.h b/unpack-trees.h
index e2a64e2401..a453def564 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -93,7 +93,8 @@ int unpack_trees(unsigned n, struct tree_desc *t,
struct unpack_trees_options *options);
int verify_uptodate(const struct cache_entry *ce,
- struct unpack_trees_options *o);
+ struct unpack_trees_options *o,
+ struct object_id *old_hash);
int threeway_merge(const struct cache_entry * const *stages,
struct unpack_trees_options *o);
--
2.20.0.rc2.486.g9832c05c3d
next prev parent reply other threads:[~2018-12-09 10:45 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-09 10:43 [RFC PATCH 00/24] Add backup log Nguyễn Thái Ngọc Duy
2018-12-09 10:43 ` [PATCH 01/24] doc: introduce new "backup log" concept Nguyễn Thái Ngọc Duy
2018-12-09 10:43 ` [PATCH 02/24] backup-log: add "update" subcommand Nguyễn Thái Ngọc Duy
2018-12-09 10:43 ` [PATCH 03/24] read-cache.c: new flag for add_index_entry() to write to backup log Nguyễn Thái Ngọc Duy
2018-12-09 10:43 ` [PATCH 04/24] add: support " Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 05/24] update-index: support backup log with --keep-backup Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 06/24] commit: support backup log Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 07/24] apply: support backup log with --keep-backup Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 08/24] add--interactive: support backup log Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 09/24] backup-log.c: add API for walking " Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 10/24] backup-log: add cat command Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 11/24] backup-log: add diff command Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 12/24] backup-log: add log command Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 13/24] backup-log: add prune command Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 14/24] gc: prune backup logs Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 15/24] backup-log: keep all blob references around Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 16/24] sha1-file.c: let index_path() accept NULL istate Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 17/24] config --edit: support backup log Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 18/24] refs: keep backup of deleted reflog Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 19/24] unpack-trees.c: keep backup of ignored files being overwritten Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` Nguyễn Thái Ngọc Duy [this message]
2018-12-09 10:44 ` [PATCH 21/24] checkout -f: keep backup of overwritten files Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 22/24] am: keep backup of overwritten files on --skip or --abort Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 23/24] rebase: " Nguyễn Thái Ngọc Duy
2018-12-09 10:44 ` [PATCH 24/24] FIXME Nguyễn Thái Ngọc Duy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181209104419.12639-21-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).