Creating a version control repository
From Second Life Wiki
This article is intended as a beginner's guide to setting up and using a version control repository.
If you make extensive changes to the source download packages, it is easy to lose track of what files you changed, as well as remembering what you did and when. A version control repository keeps track of these file changes for you automatically, and allows you to track your changes over time and to revert to a previous state if you don't like the way a project is going.
Open source changes submitted to the viewer must be in the form of Mercurial changesets on a publicly accessible repository (we use and recommend BitBucket).
Version control for beginners: Mercurial
Preparing to use Mercurial
Generally all you need to do to get started is to:
- Download and install Mercurial on your system (see the Mercurial wiki for pointers)
- Specify a username and email to use in your branches
- Set up ignore files for items you don't want to track
Identifying yourself to Mercurial
Mercurial is built with the intent that you will share your work with others, and as you create new branches it adds comments and your name and email to each change. If you don't specify this information, it will use the login account name and your computer's DNS name to auto-generate an email address which will likely be wrong.
Make sure that the email address you use is the same one that you configure for your public bitbucket account.
Specifying your name and email is done by adding these lines to the file named ".hgrc" in your home directory:
# This is a Mercurial configuration file. [ui] username = Firstname Lastname <email@example.com>
Windows users can specify these environment variables with these steps:
- Open Control Panels, and select Classic View (if not already set)
- Open System, and click on the Advanced tab
- At the bottom, click the "Environment Variables" button
- At the top of the new window, under "User variables for..", Click "New", and add the variables:
- HGUSER - Your username ("John Smith")
- EMAIL - Your email address ("firstname.lastname@example.org")
Setting up an ignore file
There are many files produced in the process of compiling which are temporary and which you will never directly modify yourself. Hence there is no reason to clutter up the repository with these files, and they will make it seem like more files are changing than you are actually editing. Mercurial can be told to ignore these files and not track their status using an .hgignore file placed in the root of the linden directory you are versioning:
.hgignore file placed in \linden:
# Ignore file constructed using Visual Studio 2003 # and viewer release source 1_20_15. This ignore # file may need additions for other compilers and # future client releases. # use glob syntax. syntax: glob # Ignore this ignore file and hgrc if present # .hgignore .hgrc # Ignore VS2003 compiler project/solution files *.vcproj *.sln # Ignore VS2003 compiler temporary files for 1_20_15 *.ilk *.res *.pyn *.pyc *.ncb *.suo *.pch *.obj *.pdb *.idb *.lib BuildLog.* *.map # Ignore compiled binaries # *.dll *.exe # Ignore everything in linden libraries zipfile # Ignore 3rd party libraries (fmod, quicktime, ..) # LICENSE-libraries-win32.txt libraries\* indra\newview\app_settings\mozilla\* indra\newview\app_settings\mozilla_debug\* indra\newview\fonts\* # Ignore build artifacts produced by compiler. # # * Do not attempt to modify these files, these # are overwritten with every compile. # indra\lscript\lscript_compile\lex_yy.cpp indra\lscript\lscript_compile\ytab.cpp indra\lscript\lscript_compile\ytab.h indra\lscript\lscript_compile\ytab.output # # To edit the default viewer preferences file, # the original is located in: # linden\etc\message.xml # # To edit the viewer protocol definitions file, # the original is located in: # linden\scripts\messages\message_template.msg # indra\newview\app_settings\message.xml indra\newview\app_settings\message_template.msg
Initializing a new repository
The first step to using a repository is to create the initial state of the repository. This takes a snapshot of all source files as they were when you first downloaded and unzipped the packages, and then all changes you make after this point refer back to this state.
- Create a source working directory, without spaces in the name
- From a command line prompt go into this path until you see the \linden\ directory
- Initialize the repository using the entire indra directory tree:
- hg init linden
- cd linden
- hg add
- hg commit
When it commits it opens up a text editor (such as Notepad on Windows) where you type a comment about this commit at the very top. To complete the commit, save the file and exit, whether or not you type a description; if you just close the editor without saving, the repository changes will not commit.
Multiple separate repositories
For each source release, you use Mercurial to create a separate repository for each one, each segregated by directory name.
So rather than having one huge version control library containing every version of the source for all time (as with the Linden SVN) instead each release gets its own Mercurial repository on your local computer.
To work with the example repository created above, you need to be inside the "linden" directory for Mercurial to find the repository associated with this directory:
C:\SL_Viewer_Builds\1_20_15>hg log abort: There is no Mercurial repository here (.hg not found)! C:\SL_Viewer_Builds\1_20_15>cd linden C:\SL_Viewer_Builds\1_20_15\linden>hg log changeset: 0:(hex-ident) tag: tip user: (Your name) date: (Commit date) summary: (Your comment)
Workflow using Bitbucket
- Locate authoritative master on http://hg.secondlife.com
- Fork the master using the bitbucket fork operation
- Clone the fork using the commands shown by bitbucket
- Perform your edits
- Pull to merge changes from other people using your fork, if applicable
- Request a pull from the owner of the authoritative master.
In one big picture
Here, Lefty and Righty are both sharing the same bitbucket repository:
- hg clone, pull and push are essentially database replication operations. They do not actually modify code. They just append to the revision history.
- All repositories have the complete revision graph - which means all the branchy-mergy stuff that happened in the past.
- Multiple heads is the normal state after pulling from an active repository.
- hg merge is the operation that will combine changes.
- hg merge is not symetrical. It will preserve the "branch you are on" and terminate the "branch you are merging from", as illustrated by the colors in the revision graphs below. Keep this in mind when maintaining named branches.
Checking for changes
Mercurial repositories always contain the complete past history, including all the past branching and merging. The revision history is seldom linear:
Considering the complexity of the revision history, it is a good idea to tag important revisions, for example any revision that was used for a release or some well defined milestone.
Examining the revision history needs to take the nature of the history into account. Unfortunately, the default behavior of "hg log" is not very helpful. It essentially reflects the order in which revisions got appended to the change log file. Fortunately, there are some options to "hg log" which will make examining the revision history easier.
For example, if you wanted to see all changes since v1.0, you'd use:
A couple of notes:
- --follow makes it group changes along the branch line, so the changelog output makes more sense. Also, if you have multiple heads, you would only see the ancestors of the specified revision instead of everything except the ancestors of the pruned revision
- --removed is necessary, since for some reason hg thinks that commits that just remove files are not worth listing.
- --prune is the important one, it will remove all revisions that are ancestors of the specified one, thereby leaving only those that contribute to tip since the specified one.
The "Daggy" Fix
The daggy fix is a technique to use for fixing small-ish bugs so that other people can choose to cherrypick them without necessarily having to pull in all your other changes, and without needing complicated diff/patch or transplant extensions.
It also demonstrates a variety of techniques to operate on the revision graph, and how you can pull only specific changes from other people's repositories.
Locate the revision where the bug was introduced
This should be as far back in the past as possible. The farther back, the better - unless of course a lot of reorganization took place. At minimum, it should be the revision where the bug was found.
You can then use the "hg update" command to place your workspace to that revision, v1.0 in the diagram.
The "hg parents" command is helpful for locating yourself in the revision tree. The name is a little misleading, the way to think about it is: "hg parents tells me what the parents of my checkin would be, if I were to check in now".
Create a named branch
This will allow people to identify your fix later on.
Note that the branch doesn't really "exist" yet. The hg branch command just tells hg to mark your next checkin as belonging on that branch.
Edit, Compile, Test, Debug
... and commit. This will create a revision on a little branch, as shown:
Merge fix into your tip
First place yourself on the tip. Merges are directional, and whatever branch your current workspace revision is set to will be the one that survives.
Now run the hg merge command. Note that you can specify a branch name as a --rev parameter. This means all revisions on that branch - which is usually what you want.
How To Pull In a Daggy Fix
Here we demonstrate how you can get someone else's fix into your repository. You cloned your repository right when v1.0 was released, and started some work, as shown:
Pulling in the other repository
Now you could just do an "hg pull" of the other person's repository, and you would get this result:
This may be a little more than you wanted. It is not necessarily bad to do this, but you would have to get comfortable working with multiple heads, and you may end up having to merge unrelated work at an inconvenient time, so this is not really what we want.
If you do this by accident, use "hg rollback" to undo.
Pulling in only part of the other repository
What you should do is specify the branch on the hg pull command, as shown:
This will only pull in that one branch. Note that it doesn't pull in the merge revision, since it no longer is part of that branch.
You then simply merge that branch into your current tip. If you also are using a named branch, be careful to "hg update" yourself to the correct head (i.e. your branch) prior to executing the merge. Remember: the branch you're on survives, the other one dies.
Done! You now have the other person's bug fix, without having to merge all of the other person's work!
(This article is a work in progress by someone without a lot of experience with repositories. More info and notes will be added later.)