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

Re: [PATCH 10/10] fast-export: add --always-show-modify-after-rename

From
Elijah Newren <newren@gmail.com>
Date
Nov 12, 2018, 18:08 UTC
Message-ID
<CABPp-BHjPq-2JoeXur+FMs+T==arqvMaAW1uLKMSHKBKBS60rA@mail.gmail.com>
In-Reply-To
<20181112125847.GI3956@sigill.intra.peff.net>
On Mon, Nov 12, 2018 at 4:58 AM Jeff King <peff@peff.net> wrote:
Show 5 quoted lines
> On Sun, Nov 11, 2018 at 12:42:58AM -0800, Elijah Newren wrote:
>
> Maybe I don't understand what you're trying to accomplish. I was
> thinking specifically of your "cat-file can tell you the large objects,
> but you don't know their names/commits" from above.

Fair enough. And just to be clear, the first 9 patches were fixes and features around trying to rewrite history; patch 10 is orthogonal and was used for a separate run to just gather data. It is entirely possible I could gather that data other ways.

Show 9 quoted lines
> I would do:
>
>    git log --raw $(
>      git cat-file --batch-check='%(objectsize:disk) %(objectname)' --batch-all-objects |
>      sort -rn | head -3 |
>      awk '{print "--find-object=" $2 }'
>    )
>
> I'm not sure how renames enter into it at all.

How did I miss objectsize:disk?? Especially since it is right next to objectsize in the manpage to boot? That's awesome, thanks for that pointer.

I do have a separate cat-file --batch-check --batch-all-objects process already, since I can't get sizes out of either log or fast-export. However, I wouldn't use your 'head -3' since I'm not looking for the N biggest, but reporting on _all_ objects (in reverse size order) and letting the user look over the report and deciding where to stop reading. So, this is a big and expensive log command. Granted, we will need a big and expensive log command, but let's keep in mind that we have this one.

Show 30 quoted lines
> > One of the problems with filter-branch that people often run into is
> > they know what they want at a high-level (e.g. extract the history of
> > this directory for a new repository, or rewrite the history of this
> > repo to appear at a subdirectory so it can be merged into a bigger
> > repo and people passing filenames to log will still get the history of
> > those files, or I want to remove some of the big stuff in my history),
> > but often times that's not quite enough.  They need help finding big
> > objects, or may be unaware that the subset of files they want used to
> > be known by alternative names.
> >
> > I want a simple --analyze mode that can report on all files that have
> > been renamed (so users don't just say "all I care about is these N
> > files, give me a rewritten history just including those" -- we can
> > point out to them whether those N files used to be known by other
> > names), as well as reporting on all big files and if they've been
> > deleted, and aggregations of the "big files" information across
> > directories and file extensions.
>
> So this seems like a separate problem than what the commit message talks
> about.
>
> There I think you'd want to assemble the list with something like "git
> log --follow --name-only paths-of-interest" except that --follow sucks
> too much to handle more than one path at a time.
>
> But if you wanted to do it manually, then:
>
>   git log --diff-filter=R --name-only
>
> would be enough to let you track it down, wouldn't it?

Without a -M you'd only catch 100% renames, right? Those aren't the only ones I'd want to catch, so I'd need to add -M. You are right that we could get basic renames this way, but it doesn't cover everything I need. Let's use this as a starting point, though, and build up to what I need...

I also want to know when files were deleted. I've generally found that people are more okay with purging parts of history [corresponding to large ojbects] that were deleted longer ago than more recent stuff, for a variety of reasons. So we could either run yet another log, or modify the command to:

  git log -M --diff-filter=RD --name-status

However, I don't just want to know when files were deleted, I'd like to know when directories are deleted. I only knew how to derive that from knowing what files existed within those directories, so that would take me to:

  git log -M --diff-filter=RAD --name-status

[Edit: I just saw your other email and for the first time learned about the -t rev-list option which might simplify this a little, although "need to worry about deleted files being reinstated" below might require the 'A' anyway.]

At this point, let's remember that we had another full git-log invocation for mapping object sizes to filenames. We might as well coalesce the two log commands into one, by extending this latest one to:

  git log -M --diff-filter=RAMD --no-abbrev --raw

Also, I wanted commit date rather than author date, so we need to extend the headers a bit. Also, for reasons I won't bother detailing, I think I want to traverse commits in reverse topological order. So our command is:

  git log --pretty=fuller --topo-order --reverse -M --diff-filter=RAMD
--no-abbrev --raw

But that still leaves us with four problems, three of which we can solve with further extensions to this command:

1) There are some weird edge cases with deletions and renames.  Lots
of them in fact.  At a simple level, branching and merging and
multiple refs means that "is-this-deleted" isn't a binary flag for a
given filename (but rather a binary flag per-ref).  Also, it makes
"the set of names associated with a single 'file' as perceived by the
user" possibly rather ill-defined as well.  This can get really hairy,
but I'd at least like to handle the very basic cases of (a) "user
re-instates filename that used to be deleted" (i.e. the file isn't
deleted anymore) and (b) "user re-instates a filename that used to
exist but was renamed to something else" (in such cases, we can't just
treat the two filenames as being different names of the same content).
Handling the (b) usecase sanely requires some topology information, so
we need parents as well.  So our command extends to:
   git log --parents --pretty=fuller --topo-order --reverse -M
--diff-filter=RAMD --no-abbrev --raw
2) log is not plumbing, so parsing the stuff before the file
modifications is not a good idea. This could be fixed by using
--format:
  git log --format='%H%n%P%n%cd' --date=short --topo-order --reverse
-M --diff-filter-RAMD --no-abbrev --raw
3) log won't show changes for merge commits by default; we'd need to add -c:
  git log --format='%H%n%P%n%cd' --date=short --topo-order --reverse
-M --diff-filter-RAMD --no-abbrev --raw -c
4) log is not plumbing, revisited: although at this point I've
specified the log output explicitly enough that it ought to be safe to
parse, there are a few things that make me slightly worried.  I can
depend on fast-export to be stable; it only gives 'M' and 'D' unless
you explicitly ask for more types (e.g. -M to detect renames will add
'R').  With log, I'm no so sure; do I need to worry about new types
appearing in the future?  Also, should I just drop --diff-filter=RAMD
since it covers just about everything anyway?  Also, while --raw is
stable, is the combination of -c and --raw stable?  Is --date=short
stable (most likely, but still seems more likely to change than
fast-export would be)?  Is there something else I need to be worried
about?  Granted, each of those is only a small worry with log, but
they add up and give me pause about whether I should be parsing it
output in another tool.

So we've come up with an alternate way to get the data I need, though with some worries.

I could potentially switch to using this and drop patch 10/10.  Maybe
there's even a good reason to prefer using log.  But at the time I was
thinking in terms of "I already have a tool that parses fast-export
output and I know it's stable...and it has access to all the
information I need so why not just get the information from it?"  So I
did that, and then realized towards the end that although it had all
the needed info, it stripped one piece from me.  Namely, when it had a
100% rename, I'd only get
   R oldname newname
and wouldn't know the sha1sum of newname (for mapping object sizes to
all their names).  If I cached the information about all file shas for
all trees I could pull it from that cache (which could be expensive
memory-wise for large repos), or I could use the original-oid
directive and keep another long running "git cat-file
--batch-check='%(objectname)' process and just pass it
"$ORIGINAL_OID:$NEWNAME" lines as I come across them.  However,
fast-export had the information and did special work to try to avoid
showing it when it thought it woudln't be needed, so why not just add
a flag to tell it to just give me the filemodify?

At this point, if folks don't like this patch, I'm more likely to use the supplementary cat-file process than switching to log, unless someone can ameliorate my concerns with it and suggest a good reason why it's actually better.

Anyway, I hope it makes a little more sense why I created this patch. Does it, or have I just made things even more confusing?

...and if you've read this far, I'm impressed.  Thanks for reading.
Previous: Jeff KingNext: Jeff King
Message 51 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.