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

Re: [PATCH] The diff-raw format updates.

From
Linus Torvalds <torvalds@osdl.org>
Date
May 22, 2005, 18:35 UTC
Message-ID
<Pine.LNX.4.58.0505221108000.2307@ppc970.osdl.org>
In-Reply-To
<7vvf5cc779.fsf_-_@assigned-by-dhcp.cox.net>
On Sat, 21 May 2005, Junio C Hamano wrote:
Show 6 quoted lines
>
> Update the diff-raw format as Linus and I discussed, except that
> it does not use sequence of underscore '_' letters to express
> nonexistence.  All '0' mode is used for that purpose instead.
> 
> The new diff-raw format can express rename/copy
Having looked at this, I have to disagree.

It can _almost_ express rename/copy, but you can't tell the two apart. In both cases you have two different modes, two different SHA1's, and two different filenames.

Also, while you can trivially tell whether a file is deleted or new (look at the 000000... SHA1), it is pretty illogical to give a "filename" for the non-existent side, as in the line

:000000 100644 0000000000000000000000000000000000000000 25ab9eda939ad92bb746c2419d083b1e52117a56	diffcore-pathspec.c	diffcore-pathspec.c

Finally, having now looked at it some more, I've come to realize that it's actually pretty hard to tell the different cases apart visually (is it a rename or just a change), because the full pathnames can be so long that it's not at all immediately obvious.

Anyway, I think we can trivially tweak the filename output to handle all these problems.

I'd suggest:
 - we'd continue to have two "filename" fields, with the existing
   termination, but they aren't pure filenames any more, they are just
   tab-separated (or zero-separated) "source" and "destination" fields.
 - if no filename exists (ie the source side of a new file, or the 
   destination side of a deleted file), output "/dev/null". In other
   words, a nonexistent file is _always_ associated with mode 000000, SHA1
   00000..  and a "name field" of "/dev/null".
 - ONLY IF HUMAN-READABLE: if the destination filename is the same as the
   source, drop it (and the tab) completely. This just makes things so
   much more readable, and it's still parseable, because the 
   line-termination is different from the inter-file termination.
   NOTE! In the zero-terminated format, you can't do this, since you 
   wouldn't know where the line ended. You might drop the name completely, 
   but you'd have to have two NUL bytes. I'd argue that since this format 
   isn't human-readable anyway, you might just want to keep the filename 
   the same.
 - in all other cases: if the file is new, prepend a "+", if the file is 
   old, prepend a "*", and if the file goes away, prepend a "-". In other 
   words, the actual pathname (if it exists) always starts at the second
   character and is always prepended by _something_ (ie there is no 
   ambiguoity with pathnames that start in -/+/*).

The above hass a few nice properties, notably you can parse the first character of the name field, and you always know what's up:

 - '/' is always "/dev/null" aka "no file"
 - '+' is always "added file"
 - '-' is always "removed file"
 - '*' is always "existing file"
 - '\0' (ie empty) is always "same filename as source"
So for the above "create" event, it would look like
	:000000 100644 0000.. 25ab..	/dev/null	+diffcore-pathspec.c

which is visually quite obviously a create. Similarly, deletes are also visually pretty obvious:

	:100644 000000 25ab.. 0000..	-diffcore-pathspec.c	/dev/null
while a "copy" would be (git-pull-script stays around, so it gets a "*"):
	:100755 100755 bd89.. 17f2..	*git-pull-script	+git-fetch-script
and a "rename" would be:
	:100644 100644 51bb.. 51bb..	-diff-tree-helper.c	+diff-helper.c

(ie the difference is in the source file having a "-" in front of it instead of a "*").

A regular modification would be
	:100644 100644 bcd3.. c05b..	*Documentation/git-fsck-cache.txt
which is also very visually distinct from the other cases.
What do you think?
		Linus
Previous: Junio C HamanoNext: Niklas Hoglund
Message 12 of 33 in “updated design for the diff-raw format.”
  1. Junio C HamanoMay 21, 2005
  2. Junio C HamanoMay 21, 2005
  3. Junio C HamanoMay 21, 2005
  4. Junio C HamanoMay 21, 2005
  5. Junio C HamanoMay 21, 2005
  6. Prepare diffcore interface for diff-tree header supression.Junio C Hamano, May 22, 2005
  7. The diff-raw format updates.Junio C Hamano, May 22, 2005
  8. Linus TorvaldsMay 22, 2005
  9. Junio C HamanoMay 22, 2005
  10. Junio C HamanoMay 22, 2005
  11. Fix tweak in similarity estimator.Junio C Hamano, May 22, 2005
  12. Linus TorvaldsMay 22, 2005
  13. Niklas HoglundMay 22, 2005
  14. Junio C HamanoMay 22, 2005
  15. Thomas GlanzmannMay 22, 2005
  16. Linus TorvaldsMay 22, 2005
  17. Thomas GlanzmannMay 22, 2005
  18. Junio C HamanoMay 22, 2005
  19. Junio C HamanoMay 22, 2005
  20. Linus TorvaldsMay 22, 2005
  21. Junio C HamanoMay 22, 2005
  22. Linus TorvaldsMay 22, 2005
  23. Junio C HamanoMay 23, 2005
  24. Linus TorvaldsMay 23, 2005
  25. Junio C HamanoMay 23, 2005
  26. Rename/copy detection fix.Junio C Hamano, May 23, 2005
  27. Comments on "Rename/copy detection fix."Junio C Hamano, May 23, 2005
  28. Junio C HamanoMay 22, 2005
  29. Diffcore updates.Junio C Hamano, May 22, 2005
  30. Linus TorvaldsMay 22, 2005
  31. Junio C HamanoMay 22, 2005
  32. Diffcore updates.Junio C Hamano, May 22, 2005
  33. Be careful with symlinks when detecting renames and copies.Junio C Hamano, May 23, 2005

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.