If you write either large programs or long documents, you have probably been caught at least once in a situation where you've made changes that turned out to be a bad thing, only to be confused and stymied because you weren't sure exactly how to reverse them and get back to a known good state. Or, perhaps you've released a program or document to someone else, then gotten a bug fix or a comment that you couldn't integrate properly because you couldn't recover the old version that person was working with. Perhaps you're a member of a development or documentation team and have felt the need for some way to keep change histories, indicating who was responsible for each change.
These common kinds of problems can be addressed with a version control system. A version control system gives you automated help at keeping a change history for a file or group of files. It allows you to recover any stage in that history, and it makes getting reports on the differences between versions easy.
Today a variety of version control systems are widely available on machines that run Emacs. Some are commercial, but there are a wealth of free, open, and powerful choices, and it seems appropriate for our discussion to focus on these. Historically, Emacs evolved largely in a Unix environment alongside the SCCS and RCS systems, and its built-in support for version control reflects their approach and terminology. Today the most popular by far is CVS (which builds on RCS, giving it more flexibility and power), and there is a new system called Subversion that is starting to catch on. Preliminary support for working with Subversion shipped with Emacs 21.3.5; its documentation suggests you check the Subversion site, http://subversion.tigris.org/, for updates.
Given that when you need version control, you generally need it very badly (and you have enough other challenges to occupy your mind), it's not surprising that most integrated development environments today offer automated support for these tools. And if any other IDE does it, by now you can certainly predict that Emacs does too!
In this chapter, we'll introduce you to the Emacs facility called VC, an Emacs Lisp minor mode that makes using version control systems very easy. VC runs all version control commands for you (using Emacs' subprocess facilities in the same way that compiler modes do). VC hides almost all the details of their interfaces from you; instead, you can trigger most basic version control operations with a single command, with Emacs correctly deducing what needs to be done next.
As noted above, the VC architecture was designed with the behavior of RCS in mind. So as we explain VC, we'll explain the RCS terminology and behavior as Emacs presents it. Where needed, we'll point out key differences in the way CVS behaves. Subversion, in turn, is being designed as a more modern version of CVS, and acts like CVS with respect to its interactions with Emacs.
Each file under version control has a change history that consists of an initial version and a series (or sometimes a branching tree) of subsequent revisions.
To make a file version-controlled, you must register it; that is, you must tell the version control system to treat the file contents you're starting with as an initial version and begin maintaining a change history for it.[85]
To change a registered file, in the old days you'd have to check out the file. Doing so notifies the version control system that you're modifying it. Under SCCS and RCS, this would lock the file so that no one else could check it out until you were done (anyone else could still look at it, though). This limitation was one of the major motivations for the development of CVS, the Concurrent Versions System, which doesn't make locks. Instead, it tries to reconcile any concurrent changes at the time that they are committed, as described below. Even so, some developers prefer to configure CVS to keep files locked at the OS level until they consciously decide they want to make changes to one of them; this largely mimics the RCS experience, albeit on a voluntary basis.
In a system like SCCS or RCS that uses locking, you may sometimes find that you can't check out a file because someone else has it locked already. Perhaps that person checked it out and wandered away, so that the lock is stale. You may want to steal the lock—that is, seize control of the work file with whatever changes the other person has made and take responsibility for checking in a clean set of changes yourself. (It's bad practice to do this casually!) Again, this hasn't generally been an issue since CVS made concurrent edits a practical option—recall that the "C" in CVS stands for "concurrent."
While making changes to your work file (the working copy you've checked out) and experimenting with them, you may decide at any time to revert the work file—that is, to throw away your changes and undo the check-out operation. After you've made changes to your file that you want to keep, you must check in those changes. Doing so adds them permanently to the saved change history as a new revision of the file. Under RCS and SCCS, it also removes the lock on your work file, so that other people can check it out and edit it. Under CVS and Subversion, the file was never locked; instead, the version control system tries to reconcile your changes with any other changes that might have been made since check-out time and yells for help (manual intervention) if it finds conflicts. Because you never really checked the file out in a concurrent system, the standard term for integrating your changes back into such a repository is commit rather than check in. The CVS interface also allows you to call it checking in, to accommodate people who are used to older systems, and that's what Emacs calls it too.
The register, check-out, revert, and check-in operations are the basic ones. But you may want to do other things as well. You can also retrieve any saved revision, get a difference report between any two saved versions or any saved version and your (possibly modified) work file, or even completely remove saved revisions that you want to throw away (though this is rare).
If conflicts are reported during a check-in operation, Emacs offers to help you resolve them by launching an Ediff session (described at the end of this chapter). If you decide against Ediff, you will see the conflicts as represented within the file by the version control system and you can address them manually or use whatever other tools you find convenient. If you later decide you do want help from Ediff after all, you can use M-x vc-resolve-conflicts Enter while you're editing the conflicted file.
Most version control systems (and all the ones we're talking about here) associate change comments with each revision. So each time you check in a registered file, you can add an explanation of the change to the change history, which won't be part of the file itself. Each revision has a revision number, which identifies its place in the history. The base revision in SCCS, RCS, and CVS is 1.1. If the history is a linear sequence of changes (which is typical for small projects), sequence numbers are two numeric fields separated by a dot. Subversion uses a simpler revision numbering scheme with which you're undoubtedly familiar: The first revision is numbered 1, the one that comes after it is 2 . . . subtle, eh?
It is possible to start branches so that variant versions of files can be maintained in parallel. In such cases, the main trunk still has two-field revision numbers, but branches have more fields. The exact naming conventions for branches are arcane and different between SCCS and RCS or CVS; if you need to know about them in detail, consult the documentation for your version control system. Once again, this is a whole lot simpler in Subversion, which versions the entire source tree as a unit and supports efficient copies of parts of the tree. In Subversion, a branch is just another directory. There is a lot more to know about version control systems than we go into here, and two excellent O'Reilly books on the topic are: Essential CVS by Jennifer Vesperman and Version Control with Subversion by Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato.
Historically, you had to know three or four different shell commands to do the basic operations of version control (registration, check in, check out, and revert), and you had to do each one outside your editor (or in an editor subshell). This procedure was complicated and annoying, or at best a distraction from the flow of working on your code and changes.
VC's interface is much simpler. The simplicity comes from noticing that whatever state your version-controlled file is in, there is normally just one logical thing to do next. Here are the rules:
• If your file isn't under version control, the next logical thing to do is register it and (where relevant) check out a modifiable copy for you.
• If it's registered, but not checked out by anyone, the next thing you generally want to do is check it out so you can edit it (again, where relevant, such as if you're using CVS in a "keep files read-only unless I say I want to edit them" mode).
• If you have made changes to the file, the next logical thing is to check it back in, which may involve reconciling your changes with those made by someone else.
• Much more rarely, if you're using one of the pre-CVS systems, if someone else has a file checked out, you may want to steal the lock (notifying the lock owner that you've done so).
Indeed, VC mode has just one basic command: C-x v v (for vc-next-action), which you can think of as "do the next logical thing to this file" or, more precisely: "take the currently visited file to the next normal version control state." It follows the arrows in Figure 12-1, which describes the traditional version control cycle.[86] This command is available in every Emacs since 19; when you invoke it, it automatically fetches the rest of VC and does its job.
Figure 12-1. The traditional version control cycle
There's a little more to it than that, of course. For one thing, when you check in a set of changes to a file, VC pops up a buffer for you to enter a change comment. Similarly, if you're in an older version control environment, when you steal a lock, VC pops up a buffer requesting an explanation. This explanation is mailed to the lock owner.
VC gives you a revert operation as well: C-x v u (for vc-revert-buffer). Actually, the function that implements vc-next-action checks to see if the buffer is unmodified since check-out time; if so, it offers to revert the buffer and unlocks the work file rather than checking in an empty change.
Although it's worth understanding this traditional flow because it's how VC is designed, working with today's concurrent version control systems is slightly different. Luckily, it's even a little simpler. Because there is no need to obtain a lock in order to edit a document, one of the VC steps is missing (or, if you prefer, you can think of it as implicit). This is illustrated in Figure 12-2.
Figure 12-2. The concurrent version control cycle
The transition from the unmodified state to the modified state (with respect to the version in the repository) is shown as a dotted line, because you no longer perform a VC operation here. You just start editing the file you want to work with. Whenever you tell VC you want the "next action" it's able to tell whether the document is modified or not. If it is, the current version is committed ("checked in," if you will) and you're prompted for the change comments. If the file is registered but unmodified, VC simply displays a message in the minibuffer telling you that the buffer is up to date.
If you prefer to configure CVS to give you read-only versions of files until you explicitly choose to edit them, your workflow will remain that of Figure 12-1.
In VC mode, three operations typically pop up a buffer to accept comment or notification text: check in, lock stealing, and (under circumstances to be explained later in the chapter) file registration. In each case, the operation is on hold until you type C-c C-c to commit the comment buffer. You can enter a comment right away and finish the operation, or you can go off and do something else. VC waits patiently to commit until you are ready. If you delete the pop-up buffer, the operation is quietly scrubbed.
The comment buffer is a plain-text buffer. However, each time you commit a comment buffer, the contents are saved to a new slot in a ring of comment buffers. You can cycle backwards in the ring with M-p and forward with M-n, or you can search for text backwards in the ring with M-r and forward with M-s. By design, these are the same keys you can use to navigate an Emacs minibuffer command history. By far the most commonly used of these commands is M-p. Being able to recall and edit the last change comment is often useful since it's common to make a series of related changes.
To give you the flavor of the other things VC can do for you, Table 12-1 provides a summary of VC commands. Each one will be explained in detail, but you can probably guess some of their actions from the command names.
Table 12-1. VC commands
| Keystrokes | Command name | Action |
|---|---|---|
| C-x v v | vc-next-action | Go to the next logical version control state. |
| C-x v d | vc-directory | Show all registered files beneath a directory. |
| C-x v = | vc-diff | Generate a version difference report. |
| C-x v u | vc-revert-buffer | Throw away changes since the last checked-in revision. |
| C-x v ~ | vc-version-other-window | Retrieve a given revision in another window. |
| C-x v l | vc-print-log | Display a file's change comments and history. |
| C-x v i | vc-register | Register a file for version control. |
| C-x v h | vc-insert-headers | Insert version control headers in a file. |
| C-x v r | vc-retrieve-snapshot | Check out a named project snapshot. |
| C-x v s | vc-create-snapshot | Create a named project snapshot. |
| C-x v c | vc-cancel-version | Throw away a saved revision. |
| C-x v a | vc-update-change-log | Update a GNU-style ChangeLog file. |
These commands are ordered in the table roughly by decreasing frequency of use. This is also the order in which we'll describe them in the following sections. All VC commands have the common prefix C-x v. Your fingers will learn this prefix quickly, and all you usually have to remember is the single command suffix. Two minor commands, vc-rename-file and vc-clear-context, are not bound to keys. They are explained later on.
VC grabs a bit of the mode line for each buffer visiting a registered file and tries to use it to keep you informed of the version control state of that file. You'll notice that when a buffer is visiting a version-controlled file, the mode tags part of the mode line (shown in parentheses) shows the name of your version control system and a revision number for the file.
When those two parts are separated by a dash, the file is not yet checked out; when they're separated by a colon, the file has been checked out, and the revision number is the one the file had when you checked it out. Note that since most people use concurrent version control systems these days, in which you don't check files out or obtain locks, you can think of the dash as meaning unmodified, while the colon means there have been changes that are not yet committed to the repository.
If you don't see these indicators, the file isn't registered yet. These three states are illustrated in Figure 12-3.
Figure 12-3. Mode lines showing a file that is not under version control, one that is unchanged with respect to the repository, and one that has had changes saved but not yet committed.
We said earlier that VC uses any of a number of version control systems (more may be added in the future). It chooses which to use for any given file by looking for a corresponding master file—that is, a file containing a change history.
If you're using RCS, each of your project directories usually has a subdirectory in which RCS masters live. If you're using SCCS, there are SCCS subdirectories. CVS is a little trickier; your project directory has a CVS subdirectory with control information in it, but CVS masters are typically kept in one central repository directory, the location of which is typically given by the CVSROOT environment variable, and will likely be on another machine completely, using the pserver network protocol. Subversion, too, uses a separate server machine to store the revision repository; it generally uses WebDAV over HTTP for its transactions. Your local Subversion master files are kept in a subdirectory named .svn.
If VC can't find a master in any of these special directories, it looks for a master in the same directory as your work file (so you don't have to create SCCS or RCS directories if you don't mind your work directories being cluttered with masters). VC checks each of these possibilities (so you can actually use more than one system in the same directory, although we don't recommend it).
If VC can't find a master anywhere, it looks for an RCS, SCCS, CVS, or .svn directory. The order in which these are attempted is controlled by the variable vc-handled-backends, described in "Customizing VC" later in this chapter. The first one it finds tells it which version control system to register new files with. If it can't find any of these directories, and you tell it to register a file, it assumes you want to use RCS and creates the master right alongside your work file.
To find out which of SCCS, RCS, CVS, or Subversion is available on your system, simply execute the commands comb, rcs, cvs, and svn respectively, with no arguments. If you see an error or usage message, the corresponding system is ready to use; if you see
command not found, it's not.
We've already explained what the main command, vc-next-action, does. Now we'll describe each of VC's other commands in detail. We have chosen the order of these descriptions to take you from frequently used and simpler commands to rarer and more complex ones.
You can, accordingly, read to the end of chapter or bail out at any point if you think you've learned all you need to. But try to persevere because you may find that the descriptions of the less common commands give you some new ideas about how to track and organize your project files.
Usually, the projects you want to put under version control have more than one file; it's normal for them to contain all the files under a specific directory and subdirectory. Therefore, seeing a list of all version-controlled files beneath the current working directory is often useful. Being able to perform an operation on all of them en masse is even more useful.
VC mode supports this directly. The command C-x v d (for vc-directory) puts you in a buffer running a customized Dired (directory editing) mode, which lists all registered files under the current directory, indicating which, if any, are checked out and who has locked them. The status field in this listing is automatically kept up to date by check-in and check-out operations.
If you mark several files in this Dired buffer (with the ordinary Dired mark command described in Chapter 5) and then perform either a vc-next-action or vc-revert-buffer, VC performs that operation on all the marked files. The most common case in which you'll perform this procedure is when you want to check in changes to several files simultaneously. VC helps you out: it pops up a buffer for only one change comment, which it then applies to every revision the check-in creates.
The vc-revert-buffer design is a bit more conservative; normally, it prompts you once for each file to make sure you really want to discard its changes.
Some Dired commands are rebound in VC Dired to run version-control commands. The = keystroke, for example, runs vc-diff on the current file rather than a Dired diff. And g refreshes all the VC status fields in the directory.
Earlier, we mentioned that version control systems help you generate difference reports between versions. VC's command for this is C-x v = (for vc-diff). This command normally shows you the difference between your work file and the last revision you checked in so that you can see exactly what changes you'll be committing if you check in again.
If you give this command a prefix argument, C-u C-x v =, it prompts you for a file name and two revision numbers and reports the difference between those revisions of the file. If the older revision number is empty (that is, you simply press Enter at that prompt), it defaults to the last checked-in revision. If the newer revision is empty, it defaults to the work file. So pressing Enter twice compares the work file with what was last checked in to the repository, a very common task.
It's also possible to get a difference report for a whole tree of project files. If the filename you give C-u C-x v = is actually a directory, you'll see the differences between your specified versions for every registered file underneath that directory.
By design, such a difference report can be shipped and mechanically applied as a patch using Larry Wall's patch utility (available on all modern Unixes). This is a tremendous help when you're cooperating on a software project by email; you can download sources, register them, make modifications—and then, with one command, generate a complete patch set of your changes to mail to your collaborators.
The exact format of these reports varies somewhat between version control systems because VC uses each system's native difference reporter.[87] Generally, the output resembles that of the Unix diff command. We'll see how to customize the report later in this chapter. Finally, the last section of the chapter introduces Ediff, an alternate and powerful way to compare and resolve differences between multiple files or versions.
You can use the command C-x v ~ (for vc-version-other-window) to retrieve any saved revision of a file. The revision is retrieved into a work file with the same name as your file, except for a suffix that identifies its revision number (the suffix is actually a dot, followed by a tilde, followed by the revision number, followed by another tilde). So you can retrieve several revisions, and they won't step on each other. This command is useful when you want to eyeball the entire old version of a file, as opposed to just its changes from previous versions or its differences from later ones.
The version suffix format is very close to what Emacs generates for saved versions if you set the global Emacs Lisp variable version-control (which VC has made pretty much obsolete). For example, if you're visiting a file named
and you retrieve version 1.3 by typing C-x v ~ 1 . 3 Enter, you will now be visiting a file named foo.html
(and because it ends with a tilde, Dired's command to flag backup files will mark it, as discussed in Chapter 5).foo.html.~1.3~
If you use C-x v l (for vc-print-log) on a registered file, VC pops up a buffer containing that file's change history. This command is most useful for viewing the change comments associated with each revision.
Normally, registering a file for version control with C-x v v (for vc-next-action) with a nonconcurrent version control system also checks out an editable copy. Occasionally it's useful to be able to just register a file without checking it out. The command C-x v i (for vc-register) does this. With modern concurrent version control systems, this distinction is fading away.
Most version control systems encourage you to embed in your file one or more magic strings that get automatically updated at check-in, check-out, and revert time. The purpose of these strings is to carry automatically inserted information about the current revision number of the file, who last modified it, and when it was last checked in.
These header strings largely duplicate within the file the version information that VC puts on the mode line—and the rest of that information you can get with C-x v l (for vc-print-log). This feature might not seem very useful, but (in particular) embedding a version string can make it possible to mine version-control information out of a compiled binary program.
Further, you may frequently view version-controlled files through something other than Emacs. If so, you won't have an Emacs mode line displaying version control information, and there is some value in having the magic headers visible in the file. Accordingly, VC provides you with a command to insert them. (Note that what VC inserts are correctly formatted placeholders for the headers; the actual values get filled in by the underlying version control system each time you commit the file.)
If you type C-x v h (for vc-insert-headers) while visiting a registered and editable file, VC tries to determine from the syntax of the file how to insert the version control header(s) as a comment and then do so. VC knows about C and Java code, and nroff/troff/groff code especially, and can usually deduce the right thing from Emacs' comment-start and comment-end global variables (set by each major mode) so it can insert HTML comments, for example. It falls back to #-to-\n comments (like those used by shell, awk, Perl, tcl, and many other Unix languages) if it can't figure out anything better to do. This command is also smart enough to notice if you already seem to have version control headers present in the file and will ask you for confirmation before inserting a redundant set.
One special behavior with respect to C code is worth mentioning. C files don't actually get version headers put in comments by default. Instead, Emacs generates a string initialization for a static dummy variable called vcid. This action is taken so the header will actually be generated into the corresponding object file as a string, and you can use the strings command (if you've got a Unix-like environment) to see which versions of its sources a binary was generated from.
A snapshot of a project is a set of revisions of the project files treated as a unit. Typically, releases are associated with points at which the project's product goes to a customer or other outside evaluator.
When you're working with a subtree of project files and want to define a release of a document or program, you may find it tedious to have to do it by remembering or storing long lists of file revision numbers. Accordingly, most version control systems give you the ability to associate a symbolic release name with all the revisions that make up a release, and then to use that symbolic name later on when naming revisions for retrieval or difference reports.
Bare RCS and CVS both provide this capability. Bare SCCS does not, but VC includes code to simulate it under SCCS. In practice, the difference between native symbolic names and VC's is next to invisible. The only drawback of VC's simulation is that the SCCS tools won't know about symbolic names when you call them outside VC. (Note that this concept doesn't really apply to Subversion, because in that environment every revision is a snapshot of the files and directories comprising the entire module.)
The C-x v s (for vc-create-snapshot) prompts you for a symbolic name. VC then associates this name with the current revision level of every registered file under the current directory.
The symbolic names you create with vc-create-snapshot are also valid arguments to any other VC command that wants a revision number. Symbolic names are especially useful with vc-diff; it means you can compare named releases with each other or with your checked-out work files. The C-x v r (for vc-retrieve-snapshot) command takes a symbolic name and checks out every registered file underneath the current working directory at the revision level associated with the name.
Both the snapshot commands will fail, returning an error and not marking or retrieving any files, if any registered file under the current directory is checked out by anyone. The vc-create-snapshot command fails in order to avoid making a snapshot that, when retrieved later, won't restore the current state completely. It also fails in order to avoid stepping on your work file changes before you've had the chance to check them in or revert them out.
The command C-x v a (for vc-update-change-log) helps VC work with some project-management conventions used by the Free Software Foundation. FSF projects generally have in each directory a file called ChangeLog that is supposed to contain timestamped modification comments for every file in that directory. The ChangeLog, historically, provided the change history, or audit trail, for which VC uses change comments.
Rather than make you enter every change comment twice (!), VC provides a hook that copies recent change comments out of masters beneath the current directory and appends them to a ChangeLog in the approved format.
Renaming version-controlled files can be tricky. In RCS or SCCS, you have to rename not just the work file but its associated master. Under CVS, for reasons too arcane to go into here, it's hard to do at all without breaking something.
The vc-rename-file tries to insulate you from the details and to catch and inform you about various error conditions that can arise. It simply prompts for old and new filenames, tries to do the right thing, and tells you if it cannot.
Renaming interacts badly with the simulated symbolic-name feature under SCCS. This is one of the better reasons to use RCS or CVS. And, actually, if you think you might need to rename or move files, you're best off investigating Subversion since one of its major design goals was to be the first version control system in which this task is straightforward.
The filesystem operations required to determine a file's version control state can be expensive and slow, especially in an NFS or other networked environment. VC goes to some pains to compensate (unless, as we'll see later on, you tell it not to).
It has two major methods: (1) caching per-file information (such as the locking user and current revision number) in memory rather than running version control utilities to parse it out of the relevant master every time, and (2) assuming that it can deduce a registered file's version control state from its write permissions. Specifically, VC assumes that a registered file that is writable is in the checked-out-and-locked state and that a registered file that is not writable is not a checked-out version being edited.
Multiuser environments being what they are, VC's cached information and assumptions about permissions occasionally lead it down the wrong path. This situation almost always occurs because someone has manually changed a file's permissions behind VC's back.
If you think that this situation has occurred, call vc-clear-context. This command forces VC to throw away all its cached-in-memory assumptions about the version control state of the files you are working with.
It is also theoretically possible for VC to get confused by a race condition between two or more VCs, or between VC and someone running the bare SCCS, RCS, or CVS utilities. This is not just a VC problem; the same sort of race is possible (though less likely) between two or more people running the bare utilities. However, this kind of race is very rare even in VC; the authors haven't heard of any instance in hundreds of thousands of programmer-hours in which it's known to have happened.
If you're concerned about this issue, the VC source code (vc.el in your Emacs Lisp source directory) includes a comment giving a careful and extensive analysis of potential multiuser conflict and race situations. VC is exactly as safe from them as the underlying utilities can be.
Some of the rules we've described earlier in the chapter for VC's behavior can be changed by setting certain Emacs variables related to VC mode. We'll go over a few of the most important here.
vc-handled-backends
This variable controls the set of version control systems used by VC, and the order in which they are found in the list controls the order in which they are attempted. It defaults to
(RCS CVS SVN MCVS SCCS). If you remove values from the list, they won't be considered valid version control systems to use. If the list is empty, VC is disabled entirely.
vc-display-status
This variable displays a file's revision number and status on the mode line of each buffer visiting it, if this is non-nil. To avoid expensive queries of the master file, you may want to turn this variable off if you are running VC over very slow network links.
vc-backend-header
These variables provides lists of the headers to be inserted by vc-insert-headers when using the specified version control system. For example, the headers for CVS are in the variable vc-cvs-header. You can customize these lists if you like a different format for your version number headers.
vc-keep-workfiles
Normally, VC leaves a read-only copy of the work file in place whenever it performs a check-in. This feature is convenient because it means make and other tools always find work files where they expect to. If you're very tight on disk space, you can turn it off, but then you have to execute an explicit check-out every time a tool other than VC needs the work file. (Emacs itself knows about version control through a piece of VC code that's always resident; its visit commands perform a check-out if necessary, without locking the file.)
vc-mistrust-permissions
This variable is normally nil. Make it t to tell VC not to trust a file's permissions or ownership as indicators of its version control state. This change slows VC down a lot, but it may be necessary if (for example) your development group is working in several different directories and accessing work files via symbolic links. In such a case, the permissions and ownership of the link convey nothing about the state of the work file.
vc-suppress-confirm
This variable defaults to nil. If it is non-nil, it suppresses the confirmation prompt vc-revert-buffer normally gives you before discarding changes.
vc-initial-comment
Most version control systems allow (but do not require) you to enter an initial comment when you register a file—a lead-off for the change history. If this variable is non-nil, VC pops up a buffer for this comment at registration time just as it normally does for change comments at check-in time.
diff-switches
The Emacs diff.el mode takes command-line switches from this global variable to pass to diff when generating a change report. VC uses it the same way. It defaults to the single switch -c to force context-diff format; -u for unified-diff format is also fairly popular.
A number of other, less important global variables are fully documented in the Emacs online help system.
VC was designed from the beginning to be usable as a front-end for multiple version control systems. The code that actually runs the version control tools is carefully isolated from the user-level package logic in such a way that plugging in new systems is not very hard. VC's author originally wrote it to handle SCCS and RCS; CVS support was added later, by a different person, without much difficulty, and Subversion support was an even simpler variant of the CVS code.
There are a couple of extensions to Emacs for users of ClearCase, a popular commercial project-management system. Whether this code is accepted into the GNU Emacs distribution, considering the FSF's hostile attitude towards non-freeware, is another question. So far they have not been, but you can obtain the packages over the internet. At the time of this writing, the best choice appears to be clearcase.el. The author of the first implementation, VC-ClearCase, has even stated that he's switched over to clearcase.el. The current download site is http://members.verizon.net/~vze24fr2/EmacsClearCase/. If it's moved by the time you read this, hopefully a Google search will steer you in the right direction.
By the time you read this book, then, your VC may well handle additional systems besides the ones we have described here (though CVS and Subversion are likely to remain the most popular ones for the foreseeable future). If you are a skilled Emacs Lisp programmer (or would like to become one) and have your own favorite version control system, by all means hack the source code—extend VC to use it, and share your results so that everyone benefits.
VC is not a total solution to the project-management problem. Although it assists single-author programming or document maintenance greatly and can give vital help on small- to medium-scale projects involving several developers, it's not necessarily adequate by itself for large multiple-component, multiple-directory projects. The following are some of its more obvious deficiencies for larger projects:
• It is not integrated with a change request or problem-report system.
• Its only way of grouping project files is by directory subtree. This limitation may create problems for large, multiple-directory projects, especially when two or more need to share a common library or subtree.
You can work around these deficiencies on small projects. Variant versions might be handled with compile-time conditions, like #ifdefs in C code. Change requests can be kept separately in some kind of database (such as the FSF's GNATS system, or Mozilla's Bugzilla). Programmers can carry around in their heads the state needed to do renames without disruption.
As projects scale up in size and intricacy, however, such ad hoc measures increasingly fail to prevent damaging friction and lead to death by accumulated details. Complexity control for very large projects requires a fundamentally stronger (and, unfortunately, more constraining and complex) support environment that goes beyond version control—a full project-management system.
For more on the design issues in project-management systems, see the latter half of the book Applying SCCS and RCS by Don Bolinger and Tan Bronson (O'Reilly).
We urge those of you with prior version control experience to heed the following maxim: to use VC effectively, check in your changes early and often! Of course, when you are working as part of a team of developers, you do need to take care to check in only a consistent and working set of files each time. There's nothing quite equal to the frustration of discovering that you can no longer compile and test your own code because someone else has checked in a fragmentary or broken piece of theirs.
If you're used to version control interfaces that are as clumsy and difficult as bare SCCS, RCS, or—to a lesser extent—CVS, your reflexes may prevent you from getting the most leverage out of VC. You probably won't commit often; you're not used to being able to instantly get status reports on a whole subtree of files.
It's worth a little thought and effort to reeducate yourself. You'll find that, instead of being an irritating minor chore, version control under VC can be tremendously liberating. By checking changes in often, you'll find you can afford to experiment more, because you'll know how to revert to a known good state quickly if need be.
In working with any version control system, you sometimes want to compare different revisions of a file. Often you're interested in what's changed in the current working revision, but sometimes you're after more historical information. The most challenging situation arises when an optimistic strategy like CVS is proved wrong, and you need to merge incompatible changes made by multiple developers to the same section of a file.
We've already described vc-diff, VC's built-in facility for helping with these tasks. We would be remiss, however, if we did not introduce you to Ediff, an even more powerful facility that is available in current releases of GNU Emacs. Ediff is extremely rich; it almost feels like another program that "takes over" your Emacs session for a while. Full coverage would require an entire chapter, or perhaps even its own handbook, but this introduction will get you started and point you at the built-in manual if you want to delve deeper.
For the most part, you launch Ediff as an independent entity rather than having it invoked automatically by the version control interface. The exception (as mentioned above) is if you ask Emacs for help resolving conflicts when they occur during a check-in operation or manually invoke vc-resolve-conflicts while visiting a buffer containing such conflicts.
If you want to use Ediff to compare two nonconflicting revisions of a file, choose Tools → Compare (Ediff) → File with revision, or type M-x ediff-revision Enter. Ediff prompts you for the file you'd like to compare (defaulting to the file associated with the current buffer), and the revision(s) you'd like to compare, defaulting to the version last checked in and the current state of the buffer. (Ediff can also be used for many tasks outside the context of version control systems; you might want to explore the options on the Compare (Ediff) menu on a rainy day.)
The first time you invoke Ediff, you will probably find it disorienting. In addition to the expected pair of buffers showing you the two files or revisions being compared, it pops open a small "control window" (see Figure 12-4) in which you type commands. In its default configuration, this is a separate operating system window (or what Emacs refers to as a "frame"). For Ediff commands to work, this window must have keyboard focus (must show as being the currently active window as far as the operating system is concerned). This is different from almost any other situation in Emacs, in that you're looking at and manipulating content in one frame while a second frame has focus.
Figure 12-4. The Ediff control window in its default state (Mac OS X)
In its default configuration, the control window is designed to be small enough not to get in the way on smaller displays. The problem is that you might not even notice it, let alone realize what it's for! In addition to being the place you type Ediff commands, this small window shows you where you are in the difference list (in this case, before the first of seven differences), and reminds you that you can type ? to get some more help. As a new Ediff user, we strongly recommend that you type ? each time you fire it up to expand the control window into the larger, Quick Help mode, shown in Figure 12-5.
Figure 12-5. The Ediff control window showing Quick Help (Mac OS X)
In addition to the control window, you'll see the differences between the files you're comparing inside the frame you were previously using for editing. If you're looking at a large file, none of the differences might be visible initially. You can jump to the first difference by typing n or pressing the space bar, as suggested by the quick help window. (Remember that for any of the Ediff commands to work, the control/quick help window must have keyboard focus.) The displayed differences will look something like Figure 12-6.
Figure 12-6. Differences displayed by Ediff
Ediff centers the difference regions within each buffer, and marks the changed lines with color, further emphasizing the specific portions of the lines which have changed to help attract visual attention to the differences. This is much more helpful than the traditional diff mode, making it worthwhile learning the strange new interface.
The basic way to use Ediff is to scroll through the buffers, seeing what has changed between them. The normal Emacs "browsing" keys (Space to move forward, Del to move backward) are bound in the control window to take you through the differences one by one. Pressing n (next) and p (previous) has the same effect. If you want to go to a specific difference, you can type a number followed by j (jump) to move immediately to that difference. To scroll up or down by pages rather than by differences you can use v to move forward and V to move backward. If your buffers contain wide lines, you can also type < and > to scroll left and right. If you'd like to view the buffers side by side rather than one above the other, type | (vertical bar). Typing this a second time returns to showing the buffers vertically. To reduce the need to scroll horizontally, you can make the comparison window as wide as possible by typing m (this is also a toggle; typing it again returns the window to its previous width). This command might cause the control window to lose focus, forcing you to click back into it before issuing the next Ediff command. (See "Recovering from Confusion" later in this chapter.) Important commands available in Ediff are summarized in Table 12-2.
Table 12-2. Ediff commands
| Keystrokes | Command name | Action |
|---|---|---|
| Space or n | ediff-next-difference | Move to the next difference between the files. |
| Del or p | ediff-previous-difference | Move to the preceding difference between the files. |
| j | ediff-jump-to-difference | Go to the difference specified as a numeric prefix argument. |
| v or C-v | ediff-scroll-vertically | Move forward one page in both buffers. |
| V or M-v | ediff-scroll-vertically | Move backward one page in both buffers. |
| < | ediff-scroll-horizontally | Scroll each buffer to the left. |
| > | ediff-scroll-horizontally | Scroll each buffer to the right. |
| | (vertical bar) | ediff-toggle-split | Switch between viewing the buffers one above the other and side-by-side. |
| m | ediff-toggle-wide-display | Toggle between normal frame size and making it as wide as possible. |
| a | ediff-copy-A-to-B | Copy the version of the current difference found in buffer A to buffer B. |
| b | ediff-copy-B-to-A | Copy the version of the current difference found in buffer B to buffer A. |
| r a or r b | ediff-restore-diff | Restore the current difference in buffer A (or B) to the way it was before copying from the other buffer. |
| A or B | ediff-toggle-read-only | Switch the specified buffer into (or out of) read-only mode. |
| g a or g b | ediff-jump-to-difference-at-point | Recenter the comparison buffers on the difference nearest to your current location (point) in the specified buffer. |
| C-l | ediff-recenter | Restore the comparison display so that the highlighted regions of all buffers being compared are visible; useful if you've been doing something else and want to get back to comparing. |
| ! | ediff-update-diffs | Recalculate and redisplay the highlighted regions; useful if you've manually made extensive changes to a buffer. |
| w a or w b | ediff-save-buffer | Save the specified buffer to disk. |
| E | ediff-documentation | Open the manual for Ediff. |
| z | ediff-suspend | Close the Ediff control window, but leave the session active so you can resume it later. |
| q | ediff-quit | Close the Ediff window and end this comparison session. |
In addition to simply viewing the differences between files, you will sometimes want to resolve or merge them (especially if you've entered Ediff as the result of conflicts that occurred while checking in a file revision). Several commands help with this, and they generally require you to choose which buffer you want to work from. As you might have noticed in Figure 12-5, Ediff assigns each file or revision buffer a letter to identify it:
A, B and sometimes C if you are comparing three things. A number of Ediff commands work with these buffer identifiers—the letter X is used to stand for these labels in the quick help window for most commands that use them.
To copy the version of the current difference found in one buffer to the other buffer, type the letter assigned to the buffer with the "right" version. For example, to copy
A's version to B, type a. Ediff makes this change but keeps track of the old value in the buffer you changed. Following along in our example, if after changing buffer B like this, you change your mind and want to restore its old state, you can type r b (for "restore buffer B"). These changes are kept track of on a difference-by-difference basis, so you don't have to change your mind right away; you can jump back to that difference and restore it at a later time, as long as you're still in the same Ediff session.
Of course, to make changes to a buffer, it cannot be in read-only mode. If you are comparing a current file with a historical revision, the buffer representing the older version is read-only because you can't change the past. If you want to avoid accidentally changing a file while browsing differences, you can cause its buffer to become read-only by typing Shift and the buffer's letter label. (Shift-b to make buffer
B read-only). This is a toggle, so doing it again makes a read-only buffer editable. If you do this to a buffer representing a historical revision, although Emacs will then let you edit the buffer, you're not actually affecting the revision within the version control system. So unless you're trying to confuse yourself, we'd suggest avoiding this practice.
If you're whipping through the buffers, making many changes by selecting appropriate versions to use within the Ediff control window, you may find yourself wanting to save one or the other of your difference buffers. While you can certainly click over to the difference window, move into that buffer, and use the standard C-s command to save, Ediff offers a more convenient alternative. Simply press w (write) followed by the buffer's letter label to save that buffer without leaving the control window.
When you're done comparing the files, the quickest way to close the control window and get back to the "normal" Emacs world is to type q to quit your Ediff session. After confirming that you really want to do this, Ediff closes the control window and cleans up after itself. You can also suspend the session temporarily by typing z for suspend. This closes the Ediff control window, but Ediff remembers that you were in the middle of a session, to which you can return later whenever you'd like. The easiest way to do this is to view the list of active Ediff sessions by choosing Tools → Ediff Miscellanea → List Ediff Sessions. When you actually quit an Ediff session, it no longer appears in this list.
If you've been cruising along in Ediff and suddenly find your commands aren't working, you've probably accidentally clicked on the differences window and are typing in one of the buffers directly, or perhaps you used an Ediff command that switched the window focus on you unexpectedly. Make sure to undo the stray characters you've typed into the comparison buffer, then click on the control window and start issuing commands again.
Of course, you may want to intentionally jump over to edit one of the buffers as you notice changes you'd like to make. You can do that at any time; just remember to switch back to the control window when you want move to other differences or use other Ediff commands. If, after editing one of the comparison buffers for a while, you'd like to return to viewing differences, starting with the difference nearest to your edit location, click in the control window and type g followed by the letter assigned to the buffer in which you're interested (as discussed earlier in "Making Changes").
If you've made substantial changes by editing the buffer directly, you may find that the difference region highlights have drifted out of synch with the actual location of differences. To fix this, once the control window has focus, type ! to cause Ediff to recalculate and redisplay the differences.
If you've reconfigured the buffers you're looking at (perhaps you wanted to look up some help text, or engage in a side task, which Emacs certainly encourages) you can restore the window configuration for Ediff by clicking on the control window and typing C-l (recenter). This sets up the comparison window to display the files you're comparing and centers the current difference in each buffer. You may find that it also causes the comparison window to get keyboard focus, so be sure to click on the control window if necessary before you try to issue any Ediff commands.
As noted, there is a whole lot more to Ediff than we can discuss here. When you want to explore it, a good starting place is the built-in Ediff manual. You can get to this by typing E (Shift-e, the capitalization matters) in the Ediff control window. If you're not already inside Ediff, you can choose Tools → Ediff Miscellanea → Ediff Manual, or you can invoke Info, the Emacs documentation browser, by typing C-h i, and choose Ediff from the main menu of topics. (Typing m for menu, followed by e d Enter is enough to complete "Ediff" and jump to its manual.)
For more task-specific help, you can click on any of the commands in the quick help window using your middle mouse button to get help describing what it does. (If you lack a three button mouse, you can click on the command with your regular mouse button and then press Enter.)
By now it should come as no surprise that you can change many details about the way that Ediff works so it better fits your way of thinking and working. After you've got a good grasp of the basics, you can use the Custom facility described in Chapter 10 to tweak the way Ediff works by choosing Tools → Ediff Miscellanea → Customize Ediff. If the use of a separate operating system window (frame) for the control window is driving you batty, you can toggle that behavior right away by choosing Tools → Ediff Miscellanea → Toggle use of separate control buffer frame.
If Ediff is so powerful, why isn't it the default mode used by the vc-diff command? The most likely explanation is historical; vc-diff has been around longer than Ediff, and it would have been disruptive to long-standing users of Emacs if a strange new interface was unexpectedly foisted on them. It seems people are writing patches to integrate Ediff more tightly with VC, but they are not (yet?) part of the Emacs distribution. If you're interested in the current state of any of these efforts, try a Google search for "vc ediff."