Emacs has built in version control interface and it works with several version control tools (see Emacs Wiki for more info).
Keybindings
C-x v v vc-next-action -- perform the next logical control operation on file C-x v i vc-register -- add a new file to version control C-x v ~ vc-version-other-window -- look at other revisions C-x v = vc-diff -- diff with other revisions C-x v u vc-revert-buffer -- undo checkout C-x v c vc-cancel-version -- delete the latest revision (often it makes more sense to look at an old revision and check that in again!) C-x v d vc-directory -- show all files which are not up to date C-x v g vc-annotate -- show when each line in a tracked file was added and by whom C-x v s vc-create-snapshot -- tag all the files with a symbolic name C-x v r vc-retrieve-snapshot -- undo checkouts and return to a snapshot with a symbolic name C-x v l vc-print-log -- show log (not in ChangeLog format) C-x v a vc-update-change-log -- update ChangeLog C-x v m vc-merge C-x v h vc-insert-headers M-x vc-resolve-conflicts -- pop up an ediff-merge session on a file with conflict markers
For example, let our project consists of one file: ‘/home/user/projects/foo/foo.c’ and let’s use SVN. (see this for short introduction)
/* File 'hello.c' */ #include <stdio.h> int main (int argc, char **argv) { printf ("Hello World\n"); return 0; }
We first create the repository and import the project:
svnadmin create --fs-type fsfs /home/user/svn_for_foo svn import /home/user/projects/foo file:///home/user/svn_for_foo/foo/trunk -m 'Initial import'
which gives us something like this:
Adding /home/user/projects/foo/foo.c Committed revision 1.
Checkout a project:
cd /home/user/projects mv foo foo.BAK svn checkout file:///home/user/svn_for_foo/foo
which gives us something like this:
A foo/trunk A foo/trunk/foo.c Checked out revision 1.
The letter ‘A’ is short for ‘Add’ and this means folder ‘foo/trunk’ and file ‘foo/trunk/foo.c’ were added.
Edit the file with Emacs, change it and save it. It will now look like this:
/* File 'hello.c' (changed) */ #include <stdio.h> #define CURRENT_YEAR 2010 #define YEAR_OF_THE_APOCALYPSE 2012 int main (int argc, char **argv) { int year_distance = YEAR_OF_THE_APOCALYPSE - CURRENT_YEAR; printf ("Hello World!\n"); if (year_distance > 0) printf ("You have %d years left...\n", year_distance); else { if (year_distance == 0) printf ("The end is now!\n"); else printf ("Anybody here? Hello?\n"); } return 0; }
Now, when we press C-x v v , the ‘*VC-log*’ buffer is opened asking for a description of our change. There we can type ‘Added apocalypse analysis…’.
This key combination performs the next logical operation which is the commit operation for which we must enter the description. (this is equivalent to svn commit -m ‘Added apocalypse analysis…’)
When we type C-c-C-c , we will see message ‘Checking in /home/user/projects/foo/trunk/foo.c…done’ in the minibuffer. This means that the change is recorded. If we look at the status bar, we will see “SVN: 2” which shows us that the latest revision is 2.
Also, you can use M-x ediff-revision if you want to see differences between files in different revisions. If we change file a little more and call this function, we will see something like this:
Useful keys in ediff are:
? – help (on / off)
| – (vertical bar) changes to vertical split instead of horizontal
p n – previous and next diff
q – quit ediff
## – ignore whitespace on / off