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

Notes on diffcore API

From
Junio C Hamano <junkio@cox.net>
Date
Jun 27, 2006, 07:28 UTC
Message-ID
<7virmn9hx8.fsf_-_@assigned-by-dhcp.cox.net>
In-Reply-To
<7v4py7h2b9.fsf@assigned-by-dhcp.cox.net>

I really should have done this six months ago, but I guess being late is much better than never...

Somebody might want to do proper asciidoc and throw it in Documentation/technical/.

-- >8 -- Notes on diffcore API =====================

The diff generation mechanism in git is designed to be self-contained and you should be able to call it as set of library functions, unlike other parts of the system where "we run once and let exit() to clean up afterwards" mentality is dominant. This is mainly because from early on "diff-tree --stdin" needed to be able to process hundreds of parent-child tree pairs without leaking.

NOTE: this note does not describe how combined diff works.  It
is quite a different animal.
The diffcore machinery works in 4 phases:
 1. setting up the machinery, including command line parsing.
 2. feeding input pairs to the machinery.
 3. letting it munge input pairs.
 4. flushing the output.

The first phase sets up the operational parameters (e.g. use of rename detector, output format). The second phase feeds pairs of 'old' and 'new' files to the machinery as the front-end finds them (e.g. diff-files compares each path found in the index and in the working tree, and feeds the information from the index as 'old' and the information from the working tree as 'new'; diff-tree compares entries in two trees or entries in the tree of the first parent commit and the tree of the commit). In the third phase, the pairs collected in the previous phase are split, matched up, and filtered to form a different set of pairs. The last phase formats the resulting set of pairs for the output.

Setting it up -------------

The diffcore machinery takes one structure, `struct diff_options`, to record the set of options that affects its behaviour. These options affect different parts of its operation, but can roughly be classified into three groups: the ones that affects how the input set of pairs are transformed in phase 3, and the ones that affects how the resulting set of pairs are formatted in phase 4.

First call diff_setup() to initialize the diff_options structure. This gives the minimum default set of options:

 - output format defaults to --raw format;
 - output lines are LF terminated;
 - no diffcore transformation (phase 3) is used;

If you are writing a top-level diff command, you can then call diff_opt_parse() to parse the common diff options and fill the information in diff_options structure, but if your usage does not require end-user customizability, you can set up the fields in diff_options yourself without calling this function.

Then call diff_setup_done() -- this makes sure the set of options are consistent and derives a reasonable default (e.g. --find-copies-harder without -C does not make sense, patch output is always recursive).

Feeding Input -------------

Your main program feeds 'file pairs' to the diffcore machinery by using these three functions: diff_addremove(), diff_change() and diff_unmerge(). The first one records a path appears not in 'old' tree but in 'new' tree (or vice versa), the second one records a path is different between 'old' and 'new', and the third one says the comparison is meaningless for the path because it is unmerged (this is only used by diff-index and diff-files).

When you want to do something diff-tree does, which is quite common, you can give two tree object names to diff_tree_sha1() function and let it walk the trees and call these functions for you.

To signal the end of input, call `diffcore_std()`. This starts the diffcore transformation described next.

Diffcore Transformation -----------------------

The input file pairs recorded in the previous phase are collected in diff_queued_diff (a global variable -- which means that you cannot have two diffs running in parallel with the current setup). This is an expandable array of pointers to `struct diff_filepair` structure.

The `struct diff_filepair` structure has (as the name suggests) two pointers to `struct diff_filespec` to record the 'old' and the 'new' file in this pair (the old one is called 'one', and the new one 'two'), along with some information used by various diffcore transformation. `struct diff_filespec` records the blob object name, pathname, size and mode among other things. Two things to watch out for are:

 - a non-existent path is denoted by mode=0 (e.g. in a filepair
   for a deleted file, one->mode != 0 and two->mode == 0).
 - 0{40} SHA-1 is used when the filespec talks about the file in
   the working tree.

Documentation/diffcore.txt should be consulted for the details of what each transformation does. A short version:

 - diffcore-break breaks a filepair that modifies 'one' to 'two'
   into two filepairs that deletes 'one' and creates 'two' if
   'one' and 'two' are sufficiently dissimilar.
 - diffcore-rename matches up a filepair that deletes 'one' and
   another filepair that creates 'two' and makes them into one
   filepair.
 - diffcore-merge-broken picks up two filepairs that were
   originally one but broken by diffcore-break but did not get
   matched up by diffcore-rename.
 - diffcore-pickaxe filters out filepairs whose 'one' and 'two'
   have the same number of occurrences of the specified string.
 - diffcore-order reorders the resulting filepairs according to
   the given input.
 - after all of the above, --diff-filter is applied to remove
   the uninteresting classes of output (e.g. --diff-filter=A
   shows only additions).

Flushing output ---------------

After diffcore transformation runs, the result is still in the same diff_queued_diff variable. Before calling the standard output routines, you can inspect each file pair in the queue to see its status (e.g. what renames to what).

Especially interesting is the 'status' field of the filepair structure. At this point in the processing chain, each file pair is marked with `M` (modified), `C` (copied), `R` (renamed), etc.

Once you are done, calling diff_flush() to perform the output and free the data structure. If you ran the diff primarily because you wanted to read the diff_queued_diff and you do not want any output from this phase, set the putput_format to DIFF_FORMAT_NO_OUTPUT before calling diff_flush() -- otherwise you would leak memory the big way.

The raw, patch-text, diffstat and summary output all happens in this final phase; recent work to make --patch, --stat, --raw etc. independent flags by Timo are primarily about phase 2 and this phase.

Previous: Alex RiesenNext: Alex Riesen
Message 10 of 27 in “CFT: merge-recursive in C”
  1. Alex RiesenJun 26, 2006
  2. CFT: merge-recursive in C (test updates)Alex Riesen, Jun 26, 2006
  3. Linus TorvaldsJun 26, 2006
  4. Linus TorvaldsJun 27, 2006
  5. Alex RiesenJun 27, 2006
  6. Junio C HamanoJun 27, 2006
  7. Alex RiesenJun 27, 2006
  8. Junio C HamanoJun 27, 2006
  9. Alex RiesenJun 27, 2006
  10. Notes on diffcore APIJunio C Hamano, Jun 27, 2006
  11. Alex RiesenJun 27, 2006
  12. Junio C HamanoJun 27, 2006
  13. Johannes SchindelinJun 28, 2006
  14. Johannes SchindelinJun 27, 2006
  15. Alex RiesenJun 27, 2006
  16. Johannes SchindelinJun 27, 2006
  17. Alex RiesenJun 27, 2006
  18. Junio C HamanoJun 27, 2006
  19. Alex RiesenJun 27, 2006
  20. Johannes SchindelinJun 27, 2006
  21. Alex RiesenJun 27, 2006
  22. Uwe ZeisbergerJun 28, 2006
  23. Alex RiesenJun 28, 2006
  24. Junio C HamanoJun 28, 2006
  25. Christopher FaylorJun 28, 2006
  26. Alex RiesenJun 29, 2006
  27. Christopher FaylorJun 29, 2006

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.