# texdiff for multi-file documents in subversion

I've been looking for a convenient way to highlight changes between subversion revisions of my Latex document in the generated PDF. I am working on a reasonably complex document that pulls together various .tex files. By virtue of using multiple \input{}s, latexdiff-svn doesn't seem to offer a solution. texdiff, despite being more amenable to multi-file documents, unfortunately doesn't have the necessary magic in place to handle SVN diffs.

I have hacked together a solution which works for me, but I'm wondering if there's something more coherent that I've missed.

My solution is a fairly short script which does the following:

1. Given a revision number, ask SVN for all the files that have changed between then and HEAD.
2. Export only those files to a temporary location, and run texdiff between the exported copy and the working copy.
3. Build another temporary directory, which stores either the output from texdiff or, if no changes were made, a copy of the working copy. The directory contains all the .tex files I need to build my document. A little sed ensures all \input{} commands point to the correct (i.e., temporary) location.

This does the trick! But, a solution that hooks directly into svn diff would be much neater. I played around earlier with svn wdiff and tried to hook it directly into texdiff, but I gave up on it when I realised I was breaking all the nice bracket matching that texdiff does. My searches have otherwise proved fruitless. Although I'm happy with my solution, does anyone know a neater way to achieve what I want?

• I don't really know a better way, but thanks for sharing your way. Maybe you could somewhere publish your script? – Paŭlo Ebermann Feb 7 '11 at 0:47
• I very interested in this too. I'm using SVN also with multi-file documents. However, I think the only way to do this is to write a script which calls svn diff by yourself, or wait until someone else does it. – Martin Scharrer Feb 10 '11 at 9:39
• Sure. It's fairly rudimentary, but I've put it here for public consumption: svn.sdstrowes.co.uk/pub/latex – Stephen Feb 14 '11 at 10:55
• Feel free to feedback on this! This script works for me, but expects my dissertation files to be present. Please offer suggestions or (preferably!) diffs, and I'll update this! – Stephen Feb 14 '11 at 10:57
• @Martin well you have seven days. Get working. :) – Seamus Feb 21 '11 at 14:32

I know coded the following Perl script which calls svn diff in summary mode to get the changed files. It extracts these using svn cat into two different directories and calls latexdiff on each modified file. It modifies the TEXINPUTS variable to load files first from the diff directory instead of the current one. This avoids the copying of all unchanged files. Finally the main file is compile using latexmk.

The usage is perl <scriptfile> <mainfile> <rev a> <rev b>.

It is absolutely not fool-proof so far, but is more general as the shell script linked to in the comments. Please test it and provide some feedback.

#!/usr/bin/env perl
use strict;
use warnings;

my @FILES;

my $rpath = '.r'; my ($mainfile,$REVA,$REVB) = @ARGV;
my $dpath = ".diff-${REVA}-${REVB}"; open(my$pipe, '-|', "svn diff --summarize -r${REVA}:${REVB}") or die;
while (<$pipe>) { next if not /^M.{7}(.*\.tex)$/;
push @FILES, $1; } close ($pipe);

exit (1) if not @FILES;

mkdir $rpath .$REVA;
mkdir $rpath .$REVB;
mkdir $dpath; foreach my$file (@FILES) {
print $file, "\n";$file =~ /^(.*)\//;
my $dir =$1 || "";
my $dira =$rpath . $REVA . '/' .$dir;
my $dirb =$rpath . $REVB . '/' .$dir;
my $ddir =$dpath         . '/' . $dir; mkdir$dira if not -e $dira; mkdir$dirb if not -e $dirb; mkdir$ddir if not -e $ddir; system("svn cat -r${REVA} '$file' > '${rpath}${REVA}/$file'");
system("svn cat -r${REVB} '$file' > '${rpath}${REVB}/$file'"); system("latexdiff '${rpath}${REVA}/$file' '${rpath}${REVB}/$file' > '${dpath}/$file'"); } if (not exists$ENV{"TEXINPUTS"} || $ENV{"TEXINPUTS"} eq '') {$ENV{"TEXINPUTS"} = "$dpath:.:"; } else {$ENV{"TEXINPUTS"} = "$dpath:" .$ENV{"TEXINPUTS"};
}

system("latexmk -pdf $mainfile")  • Cool, will have to try this soon. Looks to be basically what I was aiming for; the neat trick here is not having to copy unchanged files. Surely using latexdiff is incorrect -- it will put preamble right into the middle of a multi-part document. This is why I'm using texdiff. – Stephen Feb 28 '11 at 16:24 • I was looking for a way to stop latexdiff from adding the preamble in any other files except the main file. It doesn't have an option for that. But I thought it wont add it if it doesn't find a \begin{document}. Said that, most of the subfiles I tested the script on actually have it(!) because they use standalone. – Martin Scharrer Feb 28 '11 at 16:45 • Oh, regarding behaviour in the absence of \begin{document}, it seems you are correct! I think my document structure confuses things because I keep \begin{document} in a separate file from \end{document}, and so latexdiff refuses to run. Hence my playing around with texdiff instead. One thing my script neglects to do is spit out the appropriate preamble for texdiff, but that could be automated. – Stephen Feb 28 '11 at 17:13 • @MartinScharrer Could you take a look at tex.stackexchange.com/a/73794, which should be a comment on this but is too long? – Joseph Wright Sep 25 '12 at 20:27 I have created a batch file that combines a few scripts to use multi-file LaTeX projects with Subversion. The idea is to: • Flatten the document, i.e. create a single file that contains all elements of the project • Compare this with a previous version in the repository • Generate a PDF highlighting the changes • Create a version of the flattened document where each sentence starts in a new line (useful when comparing the source) • Create a version that removes comments and to-dos that can be send to others. I use three publicly available scripts for that. The batch file, links to the scripts and a description can be found on my website: http://www.jwe.cc/2012/02/workflow-with-subversion-and-latex/ Martin Scharrer's Perl script worked beautifully. Thanks! I had to change a few things to make the script work on my system. (I would add this as a comment to the answer, but I don't have enough 'reputation' yet.) --> diff diff_latex_orig.pl diff_latex.pl 3a4 > use File::Path qw(make_path); 12,13c13,14 < open(my$pipe, '-|', "svn diff --summarize -r${REVA}:${REVB}") or die;
< while () {
---
> open(XX, '-|', "svn diff --summarize -r${REVA}:${REVB}") or die;
> while (<XX>) {
17c18
< close ($pipe); --- > close (XX); 32,34c33,35 < mkdir$dira if not -e $dira; < mkdir$dirb if not -e $dirb; < mkdir$ddir if not -e $ddir; --- > make_path($dira);
>     make_path($dirb); > make_path($ddir);


Also, I had to add the preamble to the top level .tex file manually.

%DIF PREAMBLE EXTENSION ADDED BY LATEXDIFF
%DIF UNDERLINE PREAMBLE
\RequirePackage[normalem]{ulem}
\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1}
\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}}
%DIF SAFE PREAMBLE
\providecommand{\DIFdelbegin}{}
\providecommand{\DIFdelend}{}
%DIF FLOATSAFE PREAMBLE
\providecommand{\DIFdelFL}[1]{\DIFdel{#1}}
\providecommand{\DIFdelbeginFL}{}
\providecommand{\DIFdelendFL}{}
%DIF END PREAMBLE EXTENSION ADDED BY LATEXDIFF

• I guess ideally this would be a comment, but it's too long for me to convert :-) – Joseph Wright Sep 28 '12 at 6:07

rcs-latexdiff tool can do that. It can made a latexdiff of different versions of a same file within a RCS repository. It also manages included files (it looks for included file and get the file thanks to the svn cat command, for each revision).

The basic usage is:

$rcs-latexdiff [OPTIONS] filename old_commit new_commit  So for example, $ rcs-latexdiff paper.tex 19 20
`

create an output file diff.tex that is the latexdiff of the paper.tex file for the two last revisions (if commit 20 is HEAD). You could also use keywords like BASE, COMMITTED, PREV, etc.

Then, it's up to you to compile the output file using your favorite compiler. Notice that sometime the process could be long due to SVN because it's server-based.

The ultimate goal of this tool is to support all RCS softwares. At the moment, it only support SVN and Git. You can find install instructions on Github page. Feel free to use, reports bugs and contribute ;)