A repository is a working directory and its store (a copy of the complete history of the project). A working directory contains all the files that can be read and modified.
A changeset is an atomic collection of changes to files in a repository. It contains all recorded local modifications that lead to a new revision of the repository. A changeset is identified by a revision number and a changesetID (rev:changesetId). A changeset occurs when you modify tracked files in the working directory from their parent state.
A commit is needed to create a changeset.
A head is a changeset with no child changesets. Multiple heads in a single repository is supported in Mercurial. This occurs when two different changesets share the same parent. It usually ends in a merge, unless one wants to abandon a certain line of development. Committing to a changeset that is not a tip results in a new head.
The tip is the most recently changed head - this can be the most recent changeset, or, if you pull changes from other repositories, the tip will be the most recently changed head.
Branches occur when lines of development diverge. The term branch can be thought of as a "diverged line of development". For Mercurial, a "line of development" is a linear sequence of consecutive changesets.
A branch is automatically created when you commit a changeset to a repository. If a branch is unnamed, it belongs to the default branch.
Branches can be created in a single repository, as well as seperate repositories that were once cloned from the same parent state (i.e., different users in a project). Different users will have seperate repositories and branches.
To name a branch in Mercurial, you set the branch name of the working directory:
hg branch branch-1
To actually create the branch, you must commit a changeset to it. You do not have to modify any files.
hg commit -m"First branch commit"
To ensure this process worked, you can check all branches in the project by:
hg branches
Which will show all the branches in the project from the time you cloned it. The newly committed branch should be your active branch, which is indicated by a green highlight.
You can check the tip of your repository by:
hg tip
Which should point to your most recent changeset.
changeset: 11:076de5e6ce59
branch: branch-1
tag: tip
parent: 9:76fe2f54ab41
user: Sajeda <smokbel@uwaterloo.ca>
date: Mon Jun 13 04:46:00 2022 -0400
summary: First branch commit
You do not have to name a branch from the start. Branch naming can happen any time in your development phase. You also do not have to branch from the tip changeset. To branch from an older changeset, you run the following command, where is the revision number of the changeset you want to use as your parent for your new branch:
hg update -r <rev>
To move to another branch, you run the command:
hg update <branch_name>
To get changes from another branch into your own branch, you must merge the desired branch with your own. This is done with the following command:
hg merge <branch_name>
Bookmarks are references to changesets that can be automatically changed when new commits occur. Unlike branches, they do not need a changeset to be created, they instead point to a specified changeset, and update with every new commit. The active bookmark will always move forward and point to your newest revision.
You can have multiple bookmarks, but only the active bookmark gets tracked and updated.
Bookmarks are useful for short-lived branches, for instance, testing out a new feature locally. They are also useful if you do not want a full copy of the history of a branch, and just want to try quick experiments.
Let's say the current state of my repository is defined by the following branches:
default 7:8cbe7b17b0b7
user2 4:2bbd76a92990
user1 5:470f1e921494 (inactive)
The tip of my repository is revision 7. I can create a bookmark that references the tip by the following command:
hg bookmark feature1
I can also create another bookmark referencing an older revision by:
hg bookmark -r 4 old-rev-4
When I run hg bookmarks, I get the following output. * denotes the active bookmark.
* feature1 7:8cbe7b17b0b7
old-rev-4 4:2bbd76a92990
If I want to test a feature from the old revision, while keeping the tip bookmark untouched, I can switch to the bookmark I want to work on and start development from there. Moving bookmarks in mercurial is done the same way as moving branches: hg update <bookmark_name>. After completing some experimentation on bookmark old-rev-4, I can commit my changes and my bookmarks will look like this:
feature1 7:8cbe7b17b0b7
* old-rev-4 8:128cfa47b2b0
I can update the feature1 bookmark with the new revision by moving to the feature1 bookmark and running hg merge old-rev-4 and committing the merge. The default branch where feature1 pointed to is updated with this new changeset, while old-rev-4 stays in the same state as before.
* feature1 9:eca80a1f5b8a
old-rev-4 8:128cfa47b2b0
Branches now look like:
default 9:eca80a1f5b8a
user2 8:128cfa47b2b0 (inactive)
user1 5:470f1e921494 (inactive)
I can either delete the old-rev-4 bookmark if I've accomplished my task, or I can continue developing on it and committing my changes to the tip when I feel comfortable doing so.