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

[PATCH v2 11/11] fast-export: add --always-show-modify-after-rename

From
Elijah Newren <newren@gmail.com>
Date
Nov 14, 2018, 00:26 UTC
Message-ID
<20181114002600.29233-12-newren@gmail.com>
In-Reply-To
<20181114002600.29233-1-newren@gmail.com>
I wanted a way to gather all the following information efficiently
(with as few history traversals as possible):
  * Get all blob sizes
  * Map blob shas to filename(s) they appeared under in the history
  * Find when files and directories were deleted (and whether they
    were later reinstated, since that means they aren't actually gone)
  * Find sets of filenames referring to the same logical 'file'. (e.g.
    foo->bar in commit A and bar->baz in commit B mean that
    {foo,bar,baz} refer to the same 'file', so someone wanting to just
    "keep baz and its history" need all versions of those three
    filenames).  I need to know about things like another foo or bar
    being introduced after the rename though, since that breaks the
    connection between filenames)
and then I would generate various aggregations on the data and display
some type of report for the user.
The only way I know of to get blob sizes is via
  cat-file --batch-all-objects --batch-check

The rest of the data would traditionally be gathered from a log command, e.g.

  git log --format='%H%n%P%n%cd' --date=short --topo-order --reverse \
      -M --diff-filter=RAMD --no-abbrev --raw -c

however, parsing log output seems slightly dangerous given that it is a porcelain command. While we have specified --format and --raw to try to avoid the most obvious problems, I'm still slightly concerned about --date=short, the combinations of --raw and -c, options that might colorize the output, and also the --diff-filter (there is no current option named --no-find-copies or --no-break-rewrites, but what if those turn on by default in the future much as we changed the default with detecting renames?). Each of those is a small worry, but they add up.

A command meant for data serialization, such as fast-export, seems like
a better candidate for this job.  There's just one missing item: in
order to connect blob sizes to filenames, I need fast-export to tell me
the blob sha1sum of any file changes.  It does this for modifies, but
not always for renames.  In particular, if a file is a 100% rename, it
only prints
    R oldname newname
instead of
    R oldname newname
    M 100644 $SHA1 newname
as occurs when there is a rename+modify.  Add an option which allows us
to force the latter output even when commits have exact renames of
files.
Signed-off-by: Elijah Newren <newren@gmail.com>
---
 Documentation/git-fast-export.txt | 11 ++++++++++
 builtin/fast-export.c             |  7 +++++-
 t/t9350-fast-export.sh            | 36 +++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index 64c01ba918..b663b6f8af 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -129,6 +129,17 @@ marks the same across runs.
 	for intermediary filters (e.g. for rewriting commit messages
 	which refer to older commits, or for stripping blobs by id).
 
+--always-show-modify-after-rename::
+	When a rename is detected, fast-export normally issues both a
+	'R' (rename) and a 'M' (modify) directive.  However, if the
+	contents of the old and new filename match exactly, it will
+	only issue the rename directive.  Use this flag to have it
+	always issue the modify directive after the rename, which may
+	be useful for tools which are using the fast-export stream as
+	a mechanism for gathering statistics about a repository.  Note
+	that this option only has effect when rename detection is
+	active (see the -M option).
+
 --refspec::
 	Apply the specified refspec to each ref exported. Multiple of them can
 	be specified.
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index e0f794811e..31ad43077a 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -38,6 +38,7 @@ static int use_done_feature;
 static int no_data;
 static int full_tree;
 static int reference_excluded_commits;
+static int always_show_modify_after_rename;
 static int show_original_ids;
 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
 static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
@@ -407,7 +408,8 @@ static void show_filemodify(struct diff_queue_struct *q,
 				putchar('\n');
 
 				if (oideq(&ospec->oid, &spec->oid) &&
-				    ospec->mode == spec->mode)
+				    ospec->mode == spec->mode &&
+				    !always_show_modify_after_rename)
 					break;
 			}
 			/* fallthrough */
@@ -1105,6 +1107,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 			 &reference_excluded_commits, N_("Reference parents which are not in fast-export stream by sha1sum")),
 		OPT_BOOL(0, "show-original-ids", &show_original_ids,
 			    N_("Show original sha1sums of blobs/commits")),
+		OPT_BOOL(0, "always-show-modify-after-rename",
+			    &always_show_modify_after_rename,
+			 N_("Always provide 'M' directive after 'R'")),
 
 		OPT_END()
 	};
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 5690fe2810..5c20065e39 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -630,4 +630,40 @@ test_expect_success 'merge commit gets exported with --import-marks' '
 	)
 '
 
+test_expect_success 'rename detection and --always-show-modify-after-rename' '
+	test_create_repo renames &&
+	(
+		cd renames &&
+		test_seq 0  9  >single_digit &&
+		test_seq 10 98 >double_digit &&
+		git add . &&
+		git commit -m initial &&
+
+		echo 99 >>double_digit &&
+		git mv single_digit single-digit &&
+		git mv double_digit double-digit &&
+		git add double-digit &&
+		git commit -m renames &&
+
+		# First, check normal fast-export -M output
+		git fast-export -M --no-data master >out &&
+
+		grep double-digit out >out2 &&
+		test_line_count = 2 out2 &&
+
+		grep single-digit out >out2 &&
+		test_line_count = 1 out2 &&
+
+		# Now, test with --always-show-modify-after-rename; should
+		# have an extra "M" directive for "single-digit".
+		git fast-export -M --no-data --always-show-modify-after-rename master >out &&
+
+		grep double-digit out >out2 &&
+		test_line_count = 2 out2 &&
+
+		grep single-digit out >out2 &&
+		test_line_count = 2 out2
+	)
+'
+
 test_done
-- 
2.19.1.1063.g2b8e4a4f82.dirty
Previous: Elijah NewrenNext: Elijah Newren
Message 60 of 90 in “Import/Export as a fast way to purge files from Git?”
  1. Lars SchneiderSep 23, 2018
  2. Eric SunshineSep 23, 2018
  3. Lars SchneiderSep 23, 2018
  4. brian m. carlsonSep 23, 2018
  5. Jeff KingSep 23, 2018
  6. Elijah NewrenSep 24, 2018
  7. Lars SchneiderOct 31, 2018
  8. Elijah NewrenNov 1, 2018
  9. 00/10 fast export and import fixes and featuresElijah Newren, Nov 11, 2018
  10. 01/10 git-fast-import.txt: fix documentation for --quiet optionElijah Newren, Nov 11, 2018
  11. Jeff KingNov 11, 2018
  12. 02/10 git-fast-export.txt: clarify misleading documentation about rev-list argsElijah Newren, Nov 11, 2018
  13. Jeff KingNov 11, 2018
  14. Elijah NewrenNov 11, 2018
  15. Elijah NewrenNov 13, 2018
  16. Jonathan NiederNov 13, 2018
  17. Elijah NewrenNov 14, 2018
  18. 03/10 fast-export: use value from correct enumElijah Newren, Nov 11, 2018
  19. Jeff KingNov 11, 2018
  20. Ævar Arnfjörð BjarmasonNov 11, 2018
  21. Ævar Arnfjörð BjarmasonNov 12, 2018
  22. Jeff KingNov 12, 2018
  23. 04/10 fast-export: avoid dying when filtering by paths and old tags existElijah Newren, Nov 11, 2018
  24. Jeff KingNov 11, 2018
  25. Elijah NewrenNov 11, 2018
  26. Jeff KingNov 12, 2018
  27. brian m. carlsonNov 12, 2018
  28. Jeff KingNov 13, 2018
  29. 05/10 fast-export: move commit rewriting logic into a function for reuseElijah Newren, Nov 11, 2018
  30. Jeff KingNov 11, 2018
  31. 06/10 fast-export: when using paths, avoid corrupt stream with non-existent markElijah Newren, Nov 11, 2018
  32. Jeff KingNov 11, 2018
  33. Elijah NewrenNov 11, 2018
  34. Jeff KingNov 12, 2018
  35. Elijah NewrenNov 12, 2018
  36. 07/10 fast-export: ensure we export requested refsElijah Newren, Nov 11, 2018
  37. Jeff KingNov 11, 2018
  38. Elijah NewrenNov 11, 2018
  39. 08/10 fast-export: add --reference-excluded-parents optionElijah Newren, Nov 11, 2018
  40. Jeff KingNov 11, 2018
  41. 09/10 fast-export: add a --show-original-ids option to show original namesElijah Newren, Nov 11, 2018
  42. Jeff KingNov 11, 2018
  43. Elijah NewrenNov 11, 2018
  44. Jeff KingNov 12, 2018
  45. Elijah NewrenNov 12, 2018
  46. Jeff KingNov 12, 2018
  47. 10/10 fast-export: add --always-show-modify-after-renameElijah Newren, Nov 11, 2018
  48. Jeff KingNov 11, 2018
  49. Elijah NewrenNov 11, 2018
  50. Jeff KingNov 12, 2018
  51. Elijah NewrenNov 12, 2018
  52. Jeff KingNov 13, 2018
  53. Elijah NewrenNov 13, 2018
  54. Jeff KingNov 14, 2018
  55. Jeff KingNov 11, 2018
  56. Elijah NewrenNov 11, 2018
  57. Jeff KingNov 12, 2018
  58. 00/11 fast export and import fixes and featuresElijah Newren, Nov 14, 2018
  59. 07/11 fast-export: ensure we export requested refsElijah Newren, Nov 14, 2018
  60. 11/11 fast-export: add --always-show-modify-after-renameElijah Newren, Nov 14, 2018
  61. 01/11 git-fast-import.txt: fix documentation for --quiet optionElijah Newren, Nov 14, 2018
  62. 10/11 fast-export: add a --show-original-ids option to show original namesElijah Newren, Nov 14, 2018
  63. 05/11 fast-export: move commit rewriting logic into a function for reuseElijah Newren, Nov 14, 2018
  64. 09/11 fast-import: remove unmaintained duplicate documentationElijah Newren, Nov 14, 2018
  65. 04/11 fast-export: avoid dying when filtering by paths and old tags existElijah Newren, Nov 14, 2018
  66. SZEDER GáborNov 14, 2018
  67. Elijah NewrenNov 14, 2018
  68. 06/11 fast-export: when using paths, avoid corrupt stream with non-existent markElijah Newren, Nov 14, 2018
  69. 08/11 fast-export: add --reference-excluded-parents optionElijah Newren, Nov 14, 2018
  70. SZEDER GáborNov 14, 2018
  71. Elijah NewrenNov 14, 2018
  72. 03/11 fast-export: use value from correct enumElijah Newren, Nov 14, 2018
  73. 02/11 git-fast-export.txt: clarify misleading documentation about rev-list argsElijah Newren, Nov 14, 2018
  74. Jeff KingNov 14, 2018
  75. 00/11 fast export and import fixes and featuresElijah Newren, Nov 16, 2018
  76. 03/11 git-fast-export.txt: clarify misleading documentation about rev-list argsElijah Newren, Nov 16, 2018
  77. 07/11 fast-export: when using paths, avoid corrupt stream with non-existent markElijah Newren, Nov 16, 2018
  78. 01/11 fast-export: convert sha1 to oidElijah Newren, Nov 16, 2018
  79. 02/11 git-fast-import.txt: fix documentation for --quiet optionElijah Newren, Nov 16, 2018
  80. 08/11 fast-export: ensure we export requested refsElijah Newren, Nov 16, 2018
  81. 09/11 fast-export: add --reference-excluded-parents optionElijah Newren, Nov 16, 2018
  82. 10/11 fast-import: remove unmaintained duplicate documentationElijah Newren, Nov 16, 2018
  83. 06/11 fast-export: move commit rewriting logic into a function for reuseElijah Newren, Nov 16, 2018
  84. 11/11 fast-export: add a --show-original-ids option to show original namesElijah Newren, Nov 16, 2018
  85. SZEDER GáborNov 16, 2018
  86. 05/11 fast-export: avoid dying when filtering by paths and old tags existElijah Newren, Nov 16, 2018
  87. 04/11 fast-export: use value from correct enumElijah Newren, Nov 16, 2018
  88. Jeff KingNov 16, 2018
  89. Ævar Arnfjörð BjarmasonNov 12, 2018
  90. Elijah NewrenNov 12, 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.