tag:blogger.com,1999:blog-68072572423631810762014-10-06T20:24:58.677-04:00Flow-GeekZaakhttp://www.blogger.com/profile/06719688291830445259noreply@blogger.comBlogger1125tag:blogger.com,1999:blog-6807257242363181076.post-38328648142978174372011-04-29T14:58:00.009-04:002011-04-29T18:06:50.769-04:00Using Emacs ediff as a graphical merge tool for Subversion<div style="text-align: justify;"><a href="http://www.amazon.com/Version-Control-Subversion-Michael-Pilato/dp/0596510330?ie=UTF8&amp;tag=izabbeeshom-20&amp;link_code=bil&amp;camp=213689&amp;creative=392969" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img alt="Version Control with Subversion" src="http://ws.amazon.com/widgets/q?MarketPlace=US&amp;ServiceVersion=20070822&amp;ID=AsinImage&amp;WS=1&amp;Format=_SL160_&amp;ASIN=0596510330&amp;tag=izabbeeshom-20" /></a>Recently, we upgraded our <a href="http://subversion.apache.org/">Subversion</a> repository from 1.4 to 1.6. Subversion 1.5 and 1.6 introduce a lot of badly needed features for managing branches, better merge support, and conflict resolution. The current version of <a href="http://www.amazon.com/Version-Control-Subversion-Michael-Pilato/dp/0596510330?ie=UTF8&amp;tag=izabbeeshom-20&amp;link_code=btl&amp;camp=213689&amp;creative=392969" target="_blank">Version Control with Subversion</a><img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=izabbeeshom-20&amp;l=btl&amp;camp=213689&amp;creative=392969&amp;o=1&amp;a=0596510330" style="border: medium none ! important; margin: 0px ! important; padding: 0px ! important;" width="1" /> <img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=izabbeeshom-20&amp;l=bil&amp;camp=213689&amp;creative=392969&amp;o=1&amp;a=0596510330" style="border: medium none ! important; margin: 0px ! important; padding: 0px ! important;" width="1" />details many of the improvements that svn 1.5 has introduced, and how to use them.&nbsp;<img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=izabbeeshom-20&amp;l=bil&amp;camp=213689&amp;creative=392969&amp;o=1&amp;a=0596510330" style="border: medium none ! important; margin: 0px ! important; padding: 0px ! important;" width="1" /></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody><tr><td style="text-align: center;"><a href="http://meld.sourceforge.net/meld_preview.png" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="75" src="http://meld.sourceforge.net/meld_preview.png" width="200" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Meld</td></tr></tbody></table><a href="http://meld.sourceforge.net/meld_preview.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a>One feature which caught my attention was the interactive conflict resolution, particularly the ability to open a graphical merge tool and fix the syntactic conflicts in the file. At home, I use Ubuntu and started playing with all manner of <i>shiny</i> GUI tools; both Subversion GUI front ends and graphical merge tools. Of these, I was immediately impressed by <a href="http://www.rabbitvcs.org/">RabbitVCS</a>, <a href="http://rapidsvn.tigris.org/">RappidSVN</a> and <a href="http://meld.sourceforge.net/">Meld</a>, all of which were available through the standard Ubuntu repositories.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Now, I am quite comfortable with Subversion on the command line, so you might be wondering why I decided to start poking my nose around for graphical clients. I was inspired to look at GUI svn clients and merge tools because a new lab mate of mine said she had worked with <a href="http://tortoisesvn.tigris.org/">TortoiseSVN</a> on windoze in the past, and that the command line Subversion client intimidated her. So, having discovered these tools which, I thought seemed common enough and pretty neat for GUI tools, I started looking into installing them on our 64 bit RHEL machines in the lab. I don't have administrative privileges, but via some NFS magic from our sysadmins I can install packages from source to an NFS mounted directory that will be available on all the lab machines.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">After a nontrivial prerequisite rundown, I determined that the above mentioned packages would require me to build an absurd number of prerequisites from source. This, I decided, would be prohibitively painful and a waste of my time.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Just then, 'Aha!' It hit me: <a href="http://www.gnu.org/software/emacs/">Emacs</a> already has a sufficiently advanced interface to most popular version control systems, including Subversion, <b><i>and</i></b> has really powerful diff and merge tools which I could use as my fancy graphical merge client. Now the interface with Subversion works off the shelf and I need only configure subversion to use the powerful Emacs merge tools. This can be done via the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">merge-tool-cmd</span> option in your <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">~/.subversion/config</span> file or via the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">SVN_MERGE</span> environment variable.<br /><br />Now, you'll also need a wrapper script because there is no way to configure subversion to pass command line switches that take arguments to the merge tool. Subversion calls the specified merge tool as: <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">&lt;merge-tool&gt; <i>base theirs mine target</i></span> where <i style="font-family: &quot;Courier New&quot;,Courier,monospace;">base</i> is the base revision, <i style="font-family: &quot;Courier New&quot;,Courier,monospace;">theirs</i> is the new file pulled from the repository, <i style="font-family: &quot;Courier New&quot;,Courier,monospace;">mine</i> is your working copy, and <i style="font-family: &quot;Courier New&quot;,Courier,monospace;">target</i> is the target file on which the svn update or svn merge command was run. Now, as mentioned before, you may need to specify command line options which take arguments, or specify the files in a different order, or specify the files as command line option arguments, as is the case when using Emacs as your merge tool. Following <a href="http://www.amazon.com/Version-Control-Subversion-Michael-Pilato/dp/0596510330?ie=UTF8&amp;tag=izabbeeshom-20&amp;link_code=btl&amp;camp=213689&amp;creative=392969" target="_blank">Version Control with Subversion</a><img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=izabbeeshom-20&amp;l=btl&amp;camp=213689&amp;creative=392969&amp;o=1&amp;a=0596510330" style="border: medium none ! important; margin: 0px ! important; padding: 0px ! important;" width="1" />, I wrote my wrapper script in python. The script is listed below:<br /><br /><script src="https://gist.github.com/948481.js?file=gistfile1.py"></script><br /><br />As you can see, I am calling the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">ediff-merge-files-with-ancestor</span> Emacs lisp function as I fire up Emacs, and to this function I am passing the four file names provided by subversion. There are a few subtleties here.&nbsp; The first is that I am passing the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">-Q</span> flag (often <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">-q</span> in Emacs &lt; 23.x) which disables my startup file from being evaluated. If you want emacs to evaluate your init file on startup remove this flag from the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">cmd </span>list. The next subtlety is that I am executing Emacs through the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">os.execvp</span> function which uses your <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">PATH</span> variable to find the executable. The first argument of this function is the executable I want to run and the second argument is a list of command line options <u><i>where the first item in the list is the executable name</i></u>. An alternative to this would be to use the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">os.shell</span> method, but if you do this you need to be careful because of shell word splitting and special characters. Using&nbsp; <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">os.execvp </span>I can pass the arguments as strings directly to the program I am calling. (Make sure you don't have any errant spaces though, since there is no word splitting to consume them before passing the arguments to the executable file.) As you can see, the key element of the above script is the construction of the argument that follows the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">--eval</span> option. This causes Emacs to fire up it's powerful <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">ediff-merge-files-with-ancestor</span> tool on the offending file(s) in conflict. This function's signature is:<br /><br /><script src="https://gist.github.com/948755.js?file=gistfile1.el"></script><br /><br />It is apparent that the order of the arguments passed to the wrapper script from Subversion need rearranging, and note that since the last two arguments are optional, <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">nil</span> is passed as the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">startup-hooks</span> actual argument so we may specify the <span style="font-family: &quot;Courier New&quot;,Courier,monospace;">merge-buffer-file</span> argument.<br /><br />Below is an action shot of the end result. If you are new to ediff make sure that the ediff Emacs frame has focus and hit '<span style="font-family: &quot;Courier New&quot;,Courier,monospace;">?</span>' for a quick help menu, or '<span style="font-family: &quot;Courier New&quot;,Courier,monospace;">E</span>' to read the ediff manual.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-0PUAqZ3kdhs/TbsJBkm5s2I/AAAAAAAABS8/JfaDbro0BE0/s1600/Emacsmerge.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="272" src="http://4.bp.blogspot.com/-0PUAqZ3kdhs/TbsJBkm5s2I/AAAAAAAABS8/JfaDbro0BE0/s640/Emacsmerge.png" width="640" /></a></div><br /></div>Zaakhttp://www.blogger.com/profile/06719688291830445259noreply@blogger.com5