06 May 2015

Language Select:

Introduction

You can easily get the difference of two LaTeX sources using LaTeXdiff.

Sometimes we manage LaTeX files with git, when we write articles. This program allows taking the difference of Git-managed LaTeX files and displaying the result.

What does it do?

  • GitのコミットIDを2つ指定するとその2つのコミットの差分をLaTeXdiffで調べて出力
  • 単一のLaTeXソースじゃなくて分割したファイルをincludeする場合にも対応

なお、今回は英語の場合しか試してません。

Overview of the program

Requirements

Naturally, TeX and latexdiff are required. If you installed TeX using MacTeX, you can use it. Python are required, too.

Original TeX source

まず今回使ったメインのTeXファイル。1.tex2.texなどをincludeしています。

\documentclass[a4paper,12pt,fleqn]{jsarticle}

\begin{document}

\include{0}
\include{1}
\include{2}
\include{3}
\include{4}

\end{document}

今回は1.tex2.tex3.tex4.texの4つのファイルについて差分を取ることにします。

Extract files from Git repository

Gitリポジトリから任意のコミット時におけるファイルを開くには

git show a8ebb89:1.tex

のようにします。a8ebb89はコミットIDです。 結果は標準出力に出力されますのでリダイレクトするなりパイプに渡して使うことが出来ます。

Processing Python program

 1 #!/usr/bin/env python
 2 #coding: utf-8
 3 import sys
 4 import shlex
 5 import subprocess
 6 FileList=['1.tex', '2.tex', '3.tex', '4.tex' ]
 7 
 8 def write_source(input_file, output_file, commit_id):
 9    print('{0} -> {1} [{2}]'.format(input_file, output_file, commit_id))
10    # Show source from Git
11    cmd=shlex.split('git show {0}:{1}'.format(commit_id, input_file))
12    with open(output_file, 'w') as f:
13       proc=subprocess.Popen(cmd, stdout=f, stderr=subprocess.PIPE)
14    stdout, stderr=proc.communicate()
15    # errchk
16    if stderr:
17       print("standard error of subprocess:")
18       print(stderr)
19       sys.exit()
20 
21 
22 def generate_diff(input_file, old, new):
23    # define names
24    old_file='{0}_{1}'.format(old, input_file)
25    new_file='{0}_{1}'.format(new, input_file)
26    output_file='diff_{0}'.format(input_file)
27    # latexdiff
28    cmd=shlex.split('latexdiff {0} {1}'.format(old_file, new_file))
29    with open(output_file, 'w') as f:
30       proc=subprocess.Popen(cmd, stdout=f, stderr=subprocess.PIPE)
31    stdout, stderr=proc.communicate()
32    # errchk
33    if stderr:
34       print("standard error of subprocess:")
35       print(stderr)
36 
37 
38 def clean(old, new):
39    import glob
40    import os
41    print('Removing intermediate files...')
42    for commit_id in [old, new]:
43       files=glob.glob('{0}_*'.format(commit_id))
44       for filename in files:
45          os.unlink(filename)
46 
47 
48 def main(old, new):
49    print('commit id(old): {0}'.format(old))
50    print('commit id(new): {0}'.format(new))
51    for input_file in FileList:
52       for commit_id in [old, new]:
53          output_file='{0}_{1}'.format(commit_id, input_file)
54          write_source(input_file, output_file, commit_id)
55       generate_diff(input_file, old, new)
56 
57 
58 if __name__ == '__main__':
59    # reading arguments
60    argvs=sys.argv
61    argc=len(argvs)
62    if argc != 3:
63       print('This program takes 2 arguments.')
64       print('Usage: python {0} commit id(old) commit id(new)'.format(argvs[0]))
65       sys.exit()
66    main(argvs[1], argvs[2])
67    #clean(argvs[1], argvs[2])

上のプログラムを適当な名前をつけて保存してください。以下ではlatexdiff.pyとして保存したとして話を進めます。

How to use

6行目のFileListに差分を取りたいLaTeXのソースファイルを記入します。

あとは

python latexdiff.py CommitID(old) CommitID(new)

を実行してください。

中間ファイルを削除するためにclean関数も定義してありますが、上のプログラムではコメントアウトしてあります。必要であれば使ってください。

結果を表示するためのTeXソース

上のプログラムを実行すると、diff_1.texのようなファイルが出力されます。 あとは、これらをインクルードするTeXファイルを作ってください。先ほどのメインファイルを少し修正すればいいでしょう。

\documentclass[a4paper,12pt,fleqn]{jsarticle}

\begin{document}

\include{0}
\include{diff_1}
\include{diff_2}
\include{diff_3}
\include{diff_4}

\end{document}

あとはこちらをコンパイルすれば、2つのコミット間の差が見やすく表示されるはずです。

最後のコンパイルがうまくいかない場合

うまくコンパイルできない場合は以下をTeXソースのプリアンブルに記述するとうまくいくと思います。

\RequirePackage[normalem]{ulem}
\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1}
\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}}
\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}}\providecommand{\DIFaddbegin}{}
\providecommand{\DIFaddend}{}
\providecommand{\DIFdelbegin}{}
\providecommand{\DIFdelend}{}
\providecommand{\DIFaddFL}[1]{\DIFadd{#1}}
\providecommand{\DIFdelFL}[1]{\DIFdel{#1}}
\providecommand{\DIFaddbeginFL}{}
\providecommand{\DIFaddendFL}{}
\providecommand{\DIFdelbeginFL}{}
\providecommand{\DIFdelendFL}{}

Lastly

以上です。すでに似たようなことをされてる方もおられるますし、やってることは大したことではありませんが、LaTeXソースを分割してGitでバージョン管理してる人にはそこそこ便利だと思います。

References



blog comments powered by Disqus

analytics _by_ google