111

I use revision control (Subversion, to be exact) to keep track of the edits to my LaTeX documents. Is there a LaTeX package that interfaces with revision control? Specifically, it would be nice to see the revision number and time and date inside the document. (Obviously, I'd turn this off in the final version.) Also, it might be nice to get a PDF showing what was added and removed in a given revision.

12 Answers 12

45

Yes, there are packages called svn and svninfo, as well as a few for other version-control systems. See the TeX FAQ: you can have something like \SVNdate $Date$ which will use the value of the Date SVN variable in your document, or have footers containing the date and version number in the document. I don't think either of them shows diffs, though.

2
  • 1 vote up. Yes these are very useful and I have been using them for a long time now. You can have these "tracking" information for each of your main tex document and for any subsidiary tex documents. This way you can keep control when you have made changes in one specific file. Unfortunately, there's no way to have these tracking information for your pictures in case you update them. Sep 19, 2010 at 19:49
  • 1
    @yCalleecharan: that depends very much on what format your pictures are in
    – SamB
    Dec 2, 2010 at 20:53
39

For systems like CVS or Subversion, which modify source files, the TeX FAQ's bare-bones answer is my favourite:

\def\RCS$#1: #2 ${\expandafter\def\csname RCS#1\endcsname{#2}}
\RCS$Revision: 1.13 $ % or any RCS keyword
\RCS$Date: 2010/04/02 18:20:00 $
...
\date{Revision \RCSRevision, \RCSDate}

It's not very sophisticated, but you're only going to use it for draft versions, so this is a case where simple and robust beats pretty.

Systems like Mercurial or Git don't modify source files. In such cases, a good solution is to generate a file which can be \input into a source document. In the case of Mercurial, I use a Makefile rule like:

hg.id: .hg
    hg log -r'p1()' --template '\\def\\HgNode\{{node|short}}\n\\def\\HgDate\{{date|rfc3339date}}\n\\def\\HgAuthor\{{author|person}}\n' >$@

I \input that file into the document, and use \HgDate and \HgNode in \date commands or footnotes.

Update: the OP also mentioned changes between versions. That turns out to be a bit tricky in LaTeX, but the TeX FAQ has a discussion of the various (not completely satisfactory) possibilities.

Edit: More recent versions of Mercurial require the { characters in the template to be escaped. I modified the answer to include that.

Edit: hg parent is better than hg tip, as it gives the correct result if you're formatting an old (tagged?) version of the repository. But (a further edit) hg log -r'p1()' is better than either, since it will produce a single result even in the occasional case when a working directory has two parents, such as when you are mid-merge and resolving merge conflicts.

1
  • Mercurial has keyword extension with functionality similar to rcs keywords.
    – Mekk
    Aug 5, 2010 at 0:51
33

For the last part of your question, I like the Perl script latexdiff. This generates LaTeX documents displaying linebreak-insensitive differences, with changebars and other visual markup. (Alas, the implementation is quite hacky, relying on complex regular expressions for parsing, so it's worth ensuring one has Perl 5.8.10 or later installed for greater regular expression nesting depth.)

5
  • 7
    and the extension latexdiff-vc can handle cvs, rcs, and svn as well
    – Suresh
    Jul 26, 2010 at 23:53
  • 2
    Does latexdiff work if the doc is split into many files and \include'd?
    – Leo Liu
    Aug 15, 2010 at 11:41
  • I have not personally used it for multi-file documents, so can't comment. Sep 7, 2010 at 17:32
  • 1
    @Leo: It's something of a nuisance, but texdiff is intended to handle this case. texdiff happily creates unbound macros, so you need to put some boilerplate in your code to handle them. Oct 4, 2010 at 9:00
  • This post comments on the use of git together with latex diff: tex.stackexchange.com/questions/1325/using-latexdiff-with-git. Feb 9, 2012 at 22:27
29

For Git and Mercurial the only packaged option for writing revision information to the output document is the vc-bundle, which works without keyword substitution by writing to an \input’ed file.

For rendering a diff document a commit hook could be used that calls latexdiff-vc. Just inspecting diffs word-based instead of line based can be done with wdiff, or dwdiff. Git has a helpful diff mode with --color-words

git diff --color-words
2
  • this package work really well for me. I use the \GITHash macro. :D
    – Mica
    Feb 2, 2011 at 22:50
  • 3
    The vc-bundle doesn't seem to provide scripts for Mercurial. (The 3 vc systems supported are Bazaar, git and svn). Does anybody have the scripts adjusted for working with Mercurial? Jun 19, 2012 at 9:41
16

there is a nice package called gitinfo for the use with git. In combination with some easy Makefile gymnastics, this gives pretty nice results, all explained well in the manual of the package.

Edit: As Brent Longborough, the author of gitinfo, pointed out there is now a new version available: gitinfo 2

It simplifies the whole handling in a considerable way. Check it out!

1
  • 3
    As the author, of course I endorse this, by gitinfo has been superseded by gitinfo2. Aug 29, 2014 at 15:06
9

Keyword substitution is frowned on by revision control purists and is not facilitated in some modern systems such as Git and Darcs.

Solution recommended to me is to have a script generate the information and then write it to a file. Then add the information from file using \input.

2
  • 2
    It is not because it is frowned upon. The whole thing just doesn't make sense and git in fact offers a much more powerful way than those offered by svn or rcs. Despite this I still don't use it.
    – Leo Liu
    Aug 15, 2010 at 11:46
  • How about \verbatiminput and not \input, all those special chars tend to break things if you are not careful.
    – Johan
    Aug 16, 2010 at 6:01
8

For better diff-s in git, set .gitattributes to *.tex diff=tex.

Configuration in my repo:

$ cat .gitattributes
*.tex    diff=tex
1
  • Nice, I didn't know there's a default filter for tex in git - of course there's also latexdiff+git Mar 14, 2013 at 10:28
7

If your document uses multiple source files like \include and \input I recommend to use the 'svn-multi' package. For a changelog feature you need to use scripts like mentioned earlier, because a svn client is required to receive the log information from the server.

6

To get the revision id, date and time inside the document you need to use keyword substitution.

Once you've set up your repository to do the substitution you can then insert $Id$, $Revision$, $Date$ or other keywords which will then be replaced when the file is committed.

6

To do this I don't use a LaTeX package, but I play with a Makefile and some simple shell scripts. (But that also mean that this is a Unix/Linux/Cygwin hack).

Add something like this a Makefile

SVN_INFO=svn.info.tex
svninfo: 
    $(shell svn info > $(SVN_INFO) )

Then add something like this in a .tex file

\section{SVN info}
{\scriptsize \verbatiminput{svn.info.tex}}

Maybe with a check so you don't get a error if you don't want to include this svn info.

\IfFileExists{svn.info.tex}
{
    .....
}

This can be changed to include some kind of diff if you rather would like that.

Add something like this in your Makefile to include a diff between the current version and verison 40.

DIFF_INFO=diff.info.tex
DIFF_REV=40
diffinfo:
    $(shell svn diff --revision $(DIFF_REV) $(NAME).tex > $(DIFF_INFO) )

Then add something like this to your .tex.

\IfFileExists{diff.info.tex}
{
    \newpage
    \begin{landscape}
    \section{Diff}
    {\scriptsize \verbatiminput{diff.info.tex}}
    \end{landscape}
}

And this can then be enhanced with whatever shell scripts you feel like, so I don't see any problem doing more or less the same for other systems like git.

/Have fun

5

Mercurial

This is a hack to say the least, but I can just as well show some code.

I write the current revision and information on which files have been modified into drafts in the following way.

I build the documents with Latexmk. In latexmkrc I add:

require('scripts/writeLatexHgInfo.pl');
writeLatexHgInfo('.hginfo');

To make it better integrated with the continuous compilation mode (-pvc), I in practice actually redefine the pdflatex variable as such:

require('scripts/writeLatexHgInfo.pl');

$pdflatex = 'internal hgInfoWrapper xelatex --enable-write18 %O %S';

sub hgInfoWrapper {
    writeLatexHgInfo('.hginfo');
    return system @_;
}

(see man latexmkrc for the internal keyword). This makes the information on changed files update on each compiler invocation instead of once every latexmk run. It is marginally less efficient if one uses the latexmk command directly, but needed if one just lets the latexmk -pvc run in the background.

writeLatexHgInfo.pl contains:

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

my $HG = '/usr/bin/hg';

sub writeLatexHgInfo {
    my $template = '{node|short}|{date|rfc3339date}';
    (my $node, my $date) = split('\|', `$HG parent --template '$template'`);
    my $status = join(' \\\\'."\n", split('\n', `$HG status -mard`));

    open(HGINFO, '>'.$_[0]);
    print HGINFO
        join("\n",
            map {$_->[1] ? '\\def\\'.$_->[0].'{'.$_->[1] =~ s/(_)/\\$1/gr.'}' : ()} (
                ['HgNode', $node],
                ['HgDate', $date],
                ['HgStatus', $status],
            )
        )."\n";
    close(HGINFO);
}

1;

This populates a file named .hginfo with the HG revision, the last commit date and a list of changed files since the last commit. A sample output would be:

\def\HgNode{2f2q4e1000e9}
\def\HgDate{2014-02-26T18:00:43+00:00}
\def\HgStatus{M tex/experiment.tex \\
M tex/introduction.tex}

Note the regular expression that converts all _ to \_ in file names to avoid compilation errors when file names contain underscores. That one caught me by surprise when I had added a new file one day :-) . If one uses exotic file names (containing e.g. \, }, % and other special LaTeX characters) one will need to add more characters to the substitution range for escaping.

Then I have a LaTeX package includes/hginfo.sty with contents:

\newcommand{\hginfo}{%
  \ifoptionfinal{}{%
    \input{.hginfo}
    {%
      \centering % Doesn't center, but skips parindent, for some reason.
      \begin{tikzpicture}[every node/.style={draw, dashed, align=left}]
        \node (draft) [green, label={[gray]below left:\ifdef{\HgStatus}{\HgStatus}{}}] {HG draft revision: \texttt{\HgNode/\HgDate}};
      \end{tikzpicture}
    }
  }
}

Finally, in the document I have

\usepackage{ifdraft}
\usepackage{tikz}
\usepackage{includes/hginfo}

in the preamble, and \hginfo where I want the information to go. The TikZ part is just for colored fancy layout. I use TikZ anyway, so personally it is not an "extra" dependency.

In practice I include the \hginfo output in the page footers, so it is present on every page during the draft phase.


I think this solution will disappear shortly in favor of PythonTeX and Python bindings to Mercurial (EDIT: the CLI is actually the only official API; see below), but that was not available (at least not to my knowledge) when I hacked up the Perl version. I will keep it as long as it continues to work; it is only a few lines of copy+paste now that it is set up.


EDIT: I started looking at a PythonTeX version as well, but I soon realized it will not actually simplify things much; if at all. It adds files to be tracked for Latexmk, requires additional compilation runs, and includes some quirks for getting import paths correct, as it is currently written.

Anyway, this was the initial attempt (note that this is not updated to handle underscores as the Perl version, since I found that bug after I abandoned the Python version):

scripts/hginfo.py

#!/usr/bin/env python
import locale
import subprocess


class HgCLI(dict):
    """Utility function for calling Mercurial CLI and returning output."""
    HG = '/usr/bin/hg'
    CMD_ERR = '--invocation error--'
    encoding = locale.getdefaultlocale()[1]

    @classmethod
    def hg_out(cls, hg_args, function=None):
        """Interpret hg_args as a list of switches for the Mercurial CLI and
        return the result. An optional second parameter defines a function to
        be applied on the result before returning.
        """
        command = [cls.HG] + hg_args
        try:
            hg_out = subprocess.check_output(command).decode(cls.encoding)
        except subprocess.CalledProcessError:
            return cls.CMD_ERR
        return hg_out if function is None else function(hg_out)


def get_hg_info():
    """Return HgDict with project data filled in."""
    return {hg_key: HgCLI.hg_out(*params) for hg_key, params in {
        'node': (['parents', '--template', '{node|short}'],),
        'date': (['parents', '--template', '{date|rfc3339date}'],),
        'status': (['status', '-mard'],
            lambda x: '\\\\'.join(x.strip().split('\n')))
        }.items()}


def main():
    print(get_hg_info())


if __name__ == '__main__':
    main()

The Mercurial CLI is called by design, since it is the official and stable API for Mercurial.

includes/hginfopy.sty

% Print fancy HG repository info in draft mode using TikZ and PythonTeX.
\newcommand{\hginfo}{%
    \ifoptionfinal{}{%
        \pyc[hg]{import sys; sys.path[-1] += '/scripts'; import hginfo; hg = hginfo.get_hg_info()}
        {%
            \centering % Doesn't center, but skips parindent, for some reason.
            \begin{tikzpicture}[every node/.style={draw, dashed, align=left}]
                \node (draft) [green, label={[gray]below left:{\py[hg]{hg['status']}}}] {HG draft revision: \texttt{\py[hg]{hg['node']}/\py[hg]{hg['date']}}};
            \end{tikzpicture}
        }
    }
}

The path kludge is there to be able to collect document related scripts in a certain directory. If hginfo.py is put in e.g. the root of the document folder, it is not needed, but it clutters the file structure. Would have been nice to have an option in PythonTeX to add a script directory to the path. I tried using the \pythontexcustomc macro to add path modifications globally, but they did not seem to propagate to the actual commands. I did not explore it in detail.

sys.path[-1] is the document root in the PythonTeX environment.

In the preamble of the LaTeX document, I add:

\usepackage[runall]{pythontex}
\usepackage{includes/hginfopy}

and where I want to render the info, I run

\hginfo

All in all, the Perl version bypasses several steps since Latexmk is already running in that environment. To get a clearer solution, it would probably be easier to spend time with the Perl function, or alternatively continue with the Python script, but call it from latexmkrc instead of via PythonTeX from within the TeX file.

2
  • 2
    Since this is your first answer: Welcome to TeX.SX!
    – Speravir
    Mar 1, 2014 at 0:45
  • @Speravir: Thanks! "Officially" been a member for four months at TeX.SE, but have been lurking for even longer. This really is a great resource. Mar 1, 2014 at 0:53
1

Regarding highlighting differences between documents under version control, there is also a discussion here: texdiff for multi-file documents in subversion

As I mentioned in that post, if you have multi-file projects in Subversion and want to highlight differences the only reliable solution I found is first to flatten the document and then run latexdiff on that document. I created a batch file that does everything, from flattening to creating a PDF highlighting the differences, automatically with one click. You can find a little tutorial and download the batch on my website http://www.jwe.cc/2012/02/workflow-with-subversion-and-latex/.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .