git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 07/24] apply: support backup log with --keep-backup

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Dec 9, 2018, 10:44 UTC
Message-ID
<20181209104419.12639-8-pclouds@gmail.com>
In-Reply-To
<20181209104419.12639-1-pclouds@gmail.com>

Normally changes from git-apply are not worth logging because they come from a file and can be recovered from there. This option will mostly be used by add--interactive.pl where patches are generated during an interactive add session and are very much worth logging.

The logging is a bit more complicated because an update is done in two phases. The old version of all patches is removed first then the new one added. We need to keep track of the old version in order to make a backup.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-apply.txt |  3 +++
 apply.c                     | 38 +++++++++++++++++++++++++++++++++++--
 apply.h                     |  1 +
 t/t2080-backup-log.sh       | 25 ++++++++++++++++++++++++
 4 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index b9aa39000f..7b0ae790db 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -250,6 +250,9 @@ When `git apply` is used as a "better GNU patch", the user can pass
 the `--unsafe-paths` option to override this safety check.  This option
 has no effect when `--index` or `--cached` is in use.
 
+--keep-backup::
+	Enable index backup log when `--cached` or `--index` is used.
+
 CONFIGURATION
 -------------
 
diff --git a/apply.c b/apply.c
index 01793d6126..716c9a658f 100644
--- a/apply.c
+++ b/apply.c
@@ -21,6 +21,7 @@
 #include "quote.h"
 #include "rerere.h"
 #include "apply.h"
+#include "backup-log.h"
 
 static void git_apply_config(void)
 {
@@ -226,6 +227,7 @@ struct patch {
 	char old_oid_prefix[GIT_MAX_HEXSZ + 1];
 	char new_oid_prefix[GIT_MAX_HEXSZ + 1];
 	struct patch *next;
+	struct object_id old_oid;
 
 	/* three-way fallback result */
 	struct object_id threeway_stage[3];
@@ -4261,6 +4263,16 @@ static void patch_stats(struct apply_state *state, struct patch *patch)
 static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
 {
 	if (state->update_index && !state->ita_only) {
+		if (state->backup_log) {
+			int pos = index_name_pos(state->repo->index,
+						 patch->old_name,
+						 strlen(patch->old_name));
+			if (pos >= 0)
+				oidcpy(&patch->old_oid,
+				       &state->repo->index->cache[pos]->oid);
+			else
+				oidclr(&patch->old_oid);
+		}
 		if (remove_file_from_index(state->repo->index, patch->old_name) < 0)
 			return error(_("unable to remove %s from index"), patch->old_name);
 	}
@@ -4276,7 +4288,8 @@ static int add_index_file(struct apply_state *state,
 			  const char *path,
 			  unsigned mode,
 			  void *buf,
-			  unsigned long size)
+			  unsigned long size,
+			  const struct object_id *old_oid)
 {
 	struct stat st;
 	struct cache_entry *ce;
@@ -4314,6 +4327,16 @@ static int add_index_file(struct apply_state *state,
 				       "for newly created file %s"), path);
 		}
 	}
+	if (state->backup_log) {
+		struct strbuf *sb = state->repo->index->backup_log;
+
+		if (!sb) {
+			sb = xmalloc(sizeof(*sb));
+			strbuf_init(sb, 0);
+			state->repo->index->backup_log = sb;
+		}
+		bkl_append(sb, ce->name, old_oid, &ce->oid);
+	}
 	if (add_index_entry(state->repo->index, ce, ADD_CACHE_OK_TO_ADD) < 0) {
 		discard_cache_entry(ce);
 		return error(_("unable to add cache entry for %s"), path);
@@ -4484,7 +4507,8 @@ static int create_file(struct apply_state *state, struct patch *patch)
 	if (patch->conflicted_threeway)
 		return add_conflicted_stages_file(state, patch);
 	else if (state->update_index)
-		return add_index_file(state, path, mode, buf, size);
+		return add_index_file(state, path, mode, buf, size,
+				      &patch->old_oid);
 	return 0;
 }
 
@@ -4659,6 +4683,7 @@ static int apply_patch(struct apply_state *state,
 	struct patch *list = NULL, **listp = &list;
 	int skipped_patch = 0;
 	int res = 0;
+	int core_backup_log = 0;
 
 	state->patch_input_file = filename;
 	if (read_patch_file(&buf, fd) < 0)
@@ -4721,6 +4746,13 @@ static int apply_patch(struct apply_state *state,
 		goto end;
 	}
 
+	if (state->backup_log &&
+	    (!state->update_index ||
+	     repo_config_get_bool(state->repo, "core.backupLog",
+				  &core_backup_log) ||
+	     !core_backup_log))
+		state->backup_log = 0;
+
 	if (state->check || state->apply) {
 		int r = check_patch_list(state, list);
 		if (r == -128) {
@@ -4982,6 +5014,8 @@ int apply_parse_options(int argc, const char **argv,
 			N_("mark new files with `git add --intent-to-add`")),
 		OPT_BOOL(0, "cached", &state->cached,
 			N_("apply a patch without touching the working tree")),
+		OPT_BOOL(0, "keep-backup", &state->backup_log,
+			 N_("log index changes if the feature is enabled")),
 		OPT_BOOL_F(0, "unsafe-paths", &state->unsafe_paths,
 			   N_("accept a patch that touches outside the working area"),
 			   PARSE_OPT_NOCOMPLETE),
diff --git a/apply.h b/apply.h
index 5948348133..d4de2ebcb9 100644
--- a/apply.h
+++ b/apply.h
@@ -51,6 +51,7 @@ struct apply_state {
 	int check_index; /* preimage must match the indexed version */
 	int update_index; /* check_index && apply */
 	int ita_only;	  /* add intent-to-add entries to the index */
+	int backup_log;	  /* enable backup log */
 
 	/* These control cosmetic aspect of the output */
 	int diffstat; /* just show a diffstat, and don't actually apply */
diff --git a/t/t2080-backup-log.sh b/t/t2080-backup-log.sh
index b19e26a807..8d1c8c5935 100755
--- a/t/t2080-backup-log.sh
+++ b/t/t2080-backup-log.sh
@@ -63,4 +63,29 @@ test_expect_success 'partial commit writes backup log' '
 	test_cmp expected .git/index.bkl
 '
 
+test_expect_success 'apply --cached writes backup log' '
+	rm -f .git/index.bkl &&
+	git reset --hard &&
+	test_tick &&
+	echo to-be-deleted >to-be-deleted &&
+	echo to-be-modified >to-be-modified &&
+	OLD_M=$(git hash-object to-be-modified) &&
+	git add . &&
+	git commit -m first &&
+	rm to-be-deleted &&
+	echo modified >>to-be-modified &&
+	NEW_M=$(git hash-object to-be-modified) &&
+	OLD_A=$ZERO_OID &&
+	echo to-be-added >to-be-added &&
+	NEW_A=$(git hash-object to-be-added) &&
+	git add . &&
+	git commit -m second &&
+	git diff HEAD^ HEAD >patch &&
+	git reset --hard HEAD^ &&
+	git -c core.backupLog=true apply --cached --keep-backup patch &&
+	echo "$OLD_A $NEW_A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $test_tick -0700	to-be-added" >expected &&
+	echo "$OLD_M $NEW_M $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $test_tick -0700	to-be-modified" >>expected &&
+	test_cmp expected .git/index.bkl
+'
+
 test_done
-- 
2.20.0.rc2.486.g9832c05c3d
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 9 of 25 in “Add backup log”
  1. 00/24 Add backup logNguyễn Thái Ngọc Duy, Dec 9, 2018
  2. 01/24 doc: introduce new "backup log" conceptNguyễn Thái Ngọc Duy, Dec 9, 2018
  3. 02/24 backup-log: add "update" subcommandNguyễn Thái Ngọc Duy, Dec 9, 2018
  4. 03/24 read-cache.c: new flag for add_index_entry() to write to backup logNguyễn Thái Ngọc Duy, Dec 9, 2018
  5. 04/24 add: support backup logNguyễn Thái Ngọc Duy, Dec 9, 2018
  6. 05/24 update-index: support backup log with --keep-backupNguyễn Thái Ngọc Duy, Dec 9, 2018
  7. 08/24 add--interactive: support backup logNguyễn Thái Ngọc Duy, Dec 9, 2018
  8. 06/24 commit: support backup logNguyễn Thái Ngọc Duy, Dec 9, 2018
  9. 07/24 apply: support backup log with --keep-backupNguyễn Thái Ngọc Duy, Dec 9, 2018
  10. 09/24 backup-log.c: add API for walking backup logNguyễn Thái Ngọc Duy, Dec 9, 2018
  11. 11/24 backup-log: add diff commandNguyễn Thái Ngọc Duy, Dec 9, 2018
  12. 10/24 backup-log: add cat commandNguyễn Thái Ngọc Duy, Dec 9, 2018
  13. 12/24 backup-log: add log commandNguyễn Thái Ngọc Duy, Dec 9, 2018
  14. 17/24 config --edit: support backup logNguyễn Thái Ngọc Duy, Dec 9, 2018
  15. 18/24 refs: keep backup of deleted reflogNguyễn Thái Ngọc Duy, Dec 9, 2018
  16. 15/24 backup-log: keep all blob references aroundNguyễn Thái Ngọc Duy, Dec 9, 2018
  17. 19/24 unpack-trees.c: keep backup of ignored files being overwrittenNguyễn Thái Ngọc Duy, Dec 9, 2018
  18. 22/24 am: keep backup of overwritten files on --skip or --abortNguyễn Thái Ngọc Duy, Dec 9, 2018
  19. 21/24 checkout -f: keep backup of overwritten filesNguyễn Thái Ngọc Duy, Dec 9, 2018
  20. 14/24 gc: prune backup logsNguyễn Thái Ngọc Duy, Dec 9, 2018
  21. 23/24 rebase: keep backup of overwritten files on --skip or --abortNguyễn Thái Ngọc Duy, Dec 9, 2018
  22. 24/24 FIXMENguyễn Thái Ngọc Duy, Dec 9, 2018
  23. 20/24 reset --hard: keep backup of overwritten filesNguyễn Thái Ngọc Duy, Dec 9, 2018
  24. 16/24 sha1-file.c: let index_path() accept NULL istateNguyễn Thái Ngọc Duy, Dec 9, 2018
  25. 13/24 backup-log: add prune commandNguyễn Thái Ngọc Duy, Dec 9, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.