BitBucket is a cloud-based repository for project management. It is very convenient for collaborating: it allows several people to work on the same project together. Unlike Dropbox, users choose when to "push" their changes to the server, so code or documents don't get stuck in an intermediate state. Two users can even make changes to the same file at the same time, and the version manager will merge the changes. Finally, users write log messages to go with their changes, which explain to their collaborators what the changes were.
There are many version-control programs (RCS, CVS, Subversion, Bazaar, Git,...). I use Mercurial for my private BitBucket projects. Git with GitHub is by now much more popular, but I find Git's interface overly complicated for simple version control involving a few users. In addition, GitHub charges a high fee for private projects. I do use Git/GitHub for open-source projects such as braidlab.
Sign up for a free account. Use your academic e-mail address to get a better account type. You can add other e-mails afterwards.
sudo apt-get install mercurial
Create a Secure Shell (SSH) key, by typing (in Linux or Mac):
ssh-keygenPress enter to accept the default. (If asked to Overwrite, you already have a key and can answer no.) Then type a passphrase (twice), which is like a password except that spaces are permitted.
Log in to BitBucket, and go to Manage Account (in top right drop-down menu), then SSH keys.
Click Add Key, and paste the output of
cat ~/.ssh/id_rsa.pubThis should be a long string of nonsense, beginning with ssh-rsa.
Repeat steps 2 to 5 for each computer you use. Alternatively, you can copy the files ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub to the other computers. Then you don't have to add other keys to BitBucket.
The SSH key you uploaded will allow a secure connection between your computer and BitBucket. On a typical Linux setup, you will only need to type in your passphrase once per session.
The very first thing to do, unless you don't plan on making changes or sharing them with others, is to set up your local Mercurial username. To do this, edit (or create if it doesn't exist) the file ~/.hgrc (on Windows, the configuration file is %USERPROFILE%\Mercurial.ini) and add the lines
[ui] username = Eddie Shore <email@example.com> editor = gedit # On Mac, use editor = open -t -n -W [extensions] fetch = # enable fetch extension color = # nice color highlighting pager = # automatically invoke pager shelve = # stow away changes temporarily record = # allow commit of separate hunkswhere you substitute your own name and e-mail address, and your preferred editor (set 'editor = open -t -n -W' to use TextEdit on OSX, for instance). Make sure to use an e-mail you registered with BitBucket. (Remember that you can add extra e-mails to BitBucket, so use whichever address you consider most "permanent", not necessarily your .edu one.) The last few lines enable some convenient extensions, such as fetch (see below).
To get a list of basic Mercurial commands type
hgby itself. A more complete list is returned by
hg helpTo get help on a specific command, type
hg help thecommand
To get a local copy (a clone) of a Mercurial project (also called repository) such as flipper, type
hg clone ssh://firstname.lastname@example.org/Mark_Bell/flipperflipper is publicly available, so no password is needed. For private projects, if you have access to the project, you will be prompted for the passphrase associated with the key you created above. You only need to enter this passphrase once per session.
Projects hosted as Git repositories (another version control program like Mercurial) can easily by handled by Mercurial using the hg-git plugin. To enable hg-git, add these lines to the [extensions] section of your .hgrc configuration file (see above):
[extensions] hgext.bookmarks = hggit =You can then clone a project such as braidlab with
hg clone git+ssh://email@example.com/jeanluct/braidlab.git
By default, the clone command creates a subdirectory braidlab in the directory where you ran the command, but you can specify an optional target path.
Now you have the entire history of the project available, but by default you will see the latest version. You can edit the files and make changes as usual. If you want to add a new file or directory, just create it as you normally would, and then explicitly tell Mercurial about it with
hg add new_file_or_dir
Note that new additions don't take effect until you commit them, as described next.
To "commit" local changes once you're satisfied with them, use
hg commitAn editor will pop up for you to enter a log comment (save and exit when done). If the log comment is short, you can specify it directly on the command line:
hg commit -m"Added file new_file_or_dir, which does stuff."Write something descriptive (if you use several lines, the first should be a summary and stand on its own), and a new revision is created (also called a changeset). Revisions can consist of several additions, deletions, and/or modifications of files in the project.
Often you'll notice that you committed a file you didn't mean to, or you made a mistake in the commit message. Issuing
hg rollbackwill undo the previous commit (unless it was pushed to the server already, see next item).
Unlike Subversion and many other version control systems, in Mercurial commits are not uploaded to the server automatically. This encourages 'small commits' with well-defined changes. When you are ready you can upload all your commits by issuing
To make sure you have the latest version when you return to a project that you previously cloned, execute the "fetch" command:
hg fetchfrom within the local project directory. To use it, the fetch extension needs to be enabled in your .hgrc file, as done in item 1 above. See the next item for some details about fetch.
Fetch is a very convenient "extension" that was enabled in item 1 above. It automates the three standard steps for bringing your repository up to date with the BitBucket server. Here is how to do the same thing, but without using fetch.
First we "pull" changes from the BitBucket server, which is equivalent to the command
hg pull --updateThe --update flag (which can be abbreviated to -u) tells Mercurial to also update your working copy to the latest revision.
If someone else pushed changes, you might get a message when you pull that a merge is needed. Most of the time, simply issuing
hg mergewill merge your current state with the changes. Note that you then have to commit again:
hg commit -m"Merged changes."The reason for this extra commit is that the merge might require some tweaking to make sure everything works (code is not broken, etc.), so Mercurial adds this extra step to allow the user to intervene before accepting the merge.
The fetch extension does the 'hg pull -u; hg merge; hg commit' sequence all in one go, but it will not proceed if it finds changes that cannot be merged automatically, such as when two changes occur in the same line of a file. If such conflicts occur, you will need to read up on merging, or call someone to the rescue.
Other useful Mercurial commands include
hg statuswhich gives "status report" of the current state of your local files (M = Modified, A = Added, R = Removed, ? = not under version control), and
hg diff paper.texwhich lists the differences between local file and the original file. It is also useful to view the change history (or log) for a file or directory:
hg log paper.texFinally, to remove a file or directory run
hg rm paper.texwhich deletes the file, but will also delete for you collaborators when they pull changes from the server. Note that removals should be explained in the commit log message (as should everything else!).
Do not be afraid to commit changes! Mercurial remembers everything before your commit, so it is virtually impossible to break anything.
Commit changes often! It is better to have a detailed log of small changes than a huge number of simultaneous changes. In particular, if you don't commit changes often you will forget what you changed (though liberal use of 'hg diff' helps to figure that out). That said, a committed changeset should usually be 'consistent,' in the sense that it doesn't break things for everyone else. But sometimes it is preferable to have smaller changesets that do break things, as long as you don't push your changes to the server until done. Just make sure the log message reflects this.
Write helpful log messages! It takes a few seconds more but it's worth it. Refer to changes in specific individual files. Your collaborators will thank you, and you will thank yourself when you revisit the project two years down the line. For multiline log messages, the first line should be a summary of the changes.
Do not include binaries, executables, logs, etc. or any other files that can be recreated. The idea behind version control is to keep track of meaningful changes to files. Binary files tend to change often, and are designed to be recreated from sources. Log files also change often, since they usually contain dates. Unless the binary or log information is truly essential (i.e, the PDF figures in a paper), these should not be versioned. See below for how to avoid them showing up on 'hg stat'.
.hgignore file: To avoid unversioned files showing up on 'hg stat', which is distracting and might lead to you not noticing changes, add their file names to the special .hgignore file, which lives at the base of the project folder.
For example, when dealing with LaTeX documents, my .hgignore file usually contains
syntax: glob *.aux *.bbl *.blg *.log .DS_StoreThe line 'syntax: glob' allows the wildcard (*) notation. The final line ignores the clutter files generated by OSX.
Note that the file .hgignore should itself be under version control ('hg add .hgignore').
Tags are a good way of marking important versions of a code or paper. For instance, if you are submitting a paper in the repository to a journal, you can tag the current version as the submitted version by issuing
hg tag submitted-to-science -m"Submitted the paper to Science!"Here submitted-to-science is the tag name. You can view all the tags in a project with
hg tagsor check out a tagged version with
hg update tagnamewhich updates the current cloned repository to a specific tag. (In Mercurial update and checkout do the same thing.)
Again, the goal is to organize the structure of the repository to remember exactly where things were. If six months later Referee B says "On page 6 line 8", but we've since added 300 lines to the paper, we can check out the tagged version to see what he or she is talking about.
Branches: There are many reasons to create a branch of a project, which are parallel development versions of the repository. For example, you might have an "experimental" feature you want to toy with, but you're not sure how long it will take, and in the meantime it might break things. Another reason is to make a customized version of a code for a specific paper. This guarantees that we have a record of the code used for the paper.
In any case, simply create a named branch from within your local repository with
hg branch mybranchcalled here mybranch. Subsequent changes and commits occur on this branch, and not on the default branch. You need to explicitly merge your changes with the default branch when you're done, though depending on the purpose of your branch this might never be necessary.
You want to switch your local copy back to the default branch with
hg update defaultand then back to your development branch with
hg update mybranch
If ever you choose to abandon a branch (say after merging with the default branch), you can close it with
hg commit --close-branch -m"Closed branch mybranch, after merging."
For more information see the Mercurial Book.