CMake/Git
CMake version tracking and development is hosted by Git.
Official Repository
One may browse the repository online using the Gitweb interface at http://cmake.org/gitweb.
At the time of this writing the repository does not have branches and tags older than CMake 2.4. Conversion of older branches and tags from CVS will be completed later and added. The release branches in CVS are represented in git as tags. To see the available tags and branches use git show-ref. The current release being worked on will be the release branch.
Cloning
One may clone the repository using git clone through the native git
protocol:
$ git clone git://cmake.org/cmake.git CMake
or through the (less efficient) http
protocol:
$ git clone http://cmake.org/cmake.git CMake
All further commands work inside the local copy of the repository created by the clone:
$ cd CMake
The repository is also available by anonymous cvs pserver, served by git cvsserver. The server maps git branches to cvs modules, so one must ask cvs to get the module "master":
$ cvs -d :pserver:anonymous@cmake.org:/cmake.git co -d CMake master
Branches
At the time of this writing the repository has the following branches:
- release: Latest 2.8.x release or release candidate
- master: Development (default)
- nightly: Follows master, updated at 01:00 UTC
After cloning, create a local branch to track the upstream branch using git checkout:
$ git checkout -b release origin/release
As a shortcut with Git >= 1.6.5 one may choose a branch during the initial clone:
$ git clone -b release git://cmake.org/cmake.git CMakeRel
Updating
Use git pull to update your repository and work tree with the latest upstream changes:
$ git pull From git://cmake.org/cmake 689aa0e..4803630 master -> origin/master Updating 689aa0e..4803630 Fast forward ...
Alternatively, use git fetch to copy new history from the upstream repository:
$ git fetch From git://cmake.org/cmake 689aa0e..4803630 master -> origin/master
Then use git merge to update your work tree:
$ git merge origin/master Updating 689aa0e..4803630 Fast forward ...
The original git pull
implies both fetch and merge.
Development
We provide here a brief introduction to development with Git. See the Resources below for further information.
First, use git config to introduce yourself to Git:
$ git config --global user.name "Your Name" $ git config --global user.email "you@yourdomain.com"
Optionally enable color output from Git commands:
$ git config --global color.ui auto
The --global
option stores the configuration settings in ~/.gitconfig
in your home directory so that they apply to all repositories.
Committing
After cloning the repository using the above instructions one may commit new changes locally.
Git creates commits based on a stage (also called index or cache) that sits between the work tree and the repository.
After editing a file, say Modules/readme.txt
, use git status to see the state of the stage and work tree:
$ git status # On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: Modules/readme.txt # no changes added to commit (use "git add" and/or "git commit -a")
This tells you that no changes are staged for commit (i.e. the stage and HEAD commit have identical content),
and that the Modules/readme.txt
file in the work tree has been modified from what is in the stage.
We stage the change using git add:
$ git add Modules/readme.txt
and check the status again:
$ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: Modules/readme.txt #
This tells you that changes have been staged for commit, and that the work tree is identical to the stage. Now use git commit to create a commit:
$ git commit
Git will bring up an editor interactively to ask for the commit message.
The editor will already have the output of git status
in it as a reminder, but the comment lines will be removed from the message automatically.
A good convention is to use a short one-line summary (preferably 50 characters or less), then a blank line, then a detailed description:
Clarify documentation of module conventions The previous description of output variable XXX_YYY_ZZZ was not precise. We clarify the wording and give an example. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Your branch is ahead of 'origin/master' by 1 commit. # # Changes to be committed: # (use "git reset HEAD^1 <file>..." to unstage) # # modified: Modules/readme.txt #
Upon exit it will create the commit (unless you leave the message blank to abort the commit). After committing, check the status again:
$ git status # On branch master # Your branch is ahead of 'origin/master' by 1 commit. # nothing to commit (working directory clean)
This tells you that the (new) HEAD commit, stage, and work tree are all identical.
Furthermore it says you have one commit on your local master
branch beyond what was last fetched from the upstream origin/master
branch.
Use git log to see your commit:
$ git log origin/master..master commit 0298957e33baab30cda0da625091260a0267a5a4 Author: Your Name <you@yourdomain.com> Date: Thu Feb 4 14:37:53 2010 -0500 Clarify documentation of module conventions The previous description of output variable XXX_YYY_ZZZ was not precise. We clarify the wording and give an example.
The origin/master..master
option says "show me commits reachable from master
but not from origin/master
".
In this case it is just the one commit.
One may also browse history interactively using gitk.
Publishing
Authorized developers may publish work as follows.
Git automatically configures a new clone to refer to its origin through a remote called origin
.
Initially one may fetch or pull changes from origin
,
but may not push changes to it.
In order to publish new commits in the cmake.org
repository, developers must configure a push URL for the origin
.
Use git config to specify an ssh-protocol URL:
$ git config remote.origin.pushurl git@cmake.org:cmake.git
All publishers share the git@cmake.org
account but each uses a unique ssh key for authentication.
To request access, fill out the Kitware Password form.
Include your ssh public key and a reference to someone our administrators may contact to verify your privileges.
Note that we may not grant all contributors push access to the cmake.org
repository.
The distributed nature of Git allows contributors to retain authorship credit even if they do not publish changes directly.
After the final conversion to Git is finished we will consider pull requests from online Git hosting sites.
Once your push URL is configured and your key is installed for git@cmake.org
then you can try pushing changes.
Continuing from the above commit example, you have one commit on your local master
beyond what was last fetched from origin
.
Use git push to send the changes back to origin
:
$ git push
This shorthand push command works when your current local branch tracks a remote branch.
Git automatically configured the local master
branch to track the remote branch origin/master
upon cloning.
The configuration can be seen in .git/config
:
[branch "master"] remote = origin merge = refs/heads/master
The configuration makes the above push command equivalent to the longhand form:
$ git push origin master:master
The origin
option tells Git where to send history.
The master:master
option tells Git what history to send.
The left part names a local branch to send, and the right part names the remote branch to update.
Integration
When someone else pushes changes to cmake.org/cmake.git
after you last fetched from it then a
"git push" as documented above may fail with an error like
To git@cmake.org:cmake.git ! [rejected] master -> master (non-fast forward) error: failed to push some refs to 'git@cmake.org:cmake.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes before pushing again. See the 'non-fast forward' section of 'git push --help' for details.
Git is telling you that your history does not include the new upstream changes, so you must first fetch them from upstream and integrate your work. This is the Git equivalent to when a commit in CVS or Subversion fails with a message that your checkout is not up to date. Those tools make you update and resolve conflicts before you can even commit, but Git lets you commit first and integrate with other work later.
Git provides a shorthand way to integrate the work with one command, but for instructional purposes we'll take the long way. Use git fetch to get the latest upstream changes, and then check the local status:
$ git fetch From git://cmake.org/cmake 689aa0e..4803630 master -> origin/master $ git status # On branch master # Your branch and 'origin/master' have diverged, # and have 1 and 1 different commit(s) each, respectively. # nothing to commit (working directory clean)
Now that the local repository has a copy of the latest upstream changes it tells you explicitly that development has diverged. The graph of history looks somewhat like this:
... o ---- o ---- A ---- B origin/master (upstream work) \ C master (your work)
You based commit C
on commit A
because that was the latest work you had fetched from upstream at the time.
However, before you tried to push back to origin
someone else pushed commit B
.
Development history has diverged into separate paths.
There are two ways to integrate the two paths of history (your work with new upstream work): Merge or Rebase
Merge
Use the git merge command:
$ git merge origin/master
This tells Git to integrate the changes from origin/master
into your work and create a merge commit.
The graph of history now looks like this:
... o ---- o ---- A ---- B origin/master (upstream work) \ \ C ---- M master (your work)
The new merge commit M
has two parents, each representing one path of development that led to the content stored in the commit.
Note that the history behind M
is now non-linear.
We have chosen (for now) to disallow non-linear history in cmake.org/cmake.git
so an attempt to push M
into our repository will fail.
Until this restriction is lifted, please rebase your work instead.
Rebase
Use the git rebase command:
$ git rebase origin/master
This tells Git to replay commit C
(your work) as if you had based it on commit B
instead of A
.
CVS and Subversion users routinely rebase their local changes on top of upstream work when they update before commit.
Git just adds explicit separation between the commit and rebase steps.
The graph of history now looks like this:
... o ---- o ---- A ---- B origin/master (upstream work) \ C' master (your work)
Commit C'
is a new commit created by the git rebase
command.
It is different from C
in two ways:
- It has a different history:
B
instead ofA
. - It's content accounts for changes in both
B
andC
: it is the same asM
from the merge example.
Note that the history behind C'
is still linear.
We have chosen (for now) to allow only linear history in cmake.org/cmake.git
.
This approach preserves the CVS-based workflow used previously and may ease the transition.
An attempt to push C'
into our repository will work (assuming you have permissions and no one has pushed while you were rebasing).
The git pull command provides a shorthand way to fetch from origin
and rebase local work on it:
$ git pull --rebase
This combines the above fetch and rebase steps into one command.
Workflow
We've chosen to approximate our previous CVS-based development workflow after the initial move to Git, at least while things get settled.
This is possible because the cmake.org/cmake.git
repository does not allow non-linear or re-written history to be pushed.
In this section we briefly document how to perform the basic steps of a CVS-like development workflow using Git.
Initialize
The first step to development is to prepare a local work tree. With CVS the commands were:
$ cvs -d :pserver:me@cmake.org:/cvsroot/CMake login (enter password) $ cvs -d :pserver:me@cmake.org:/cvsroot/CMake checkout CMake $ cd CMake
With Git the commands are:
$ git clone git://cmake.org/cmake.git CMake $ cd CMake $ git config remote.origin.pushurl git@cmake.org:cmake.git
The last command is useful only when you have push access to the cmake.org/cmake.git
repository.
Update
At any time during development, particularly before publishing changes, one may update to get the latest changes. With CVS the command was:
$ cvs update (resolve conflicts with local modifications; hope you don't loose anything)
With Git the command is:
$ git pull --rebase
if you have zero or more local commits but no uncommitted modifications. If you have uncommitted modifications then you may (locally) commit them and then use the above command. If conflicts occur then the rebase may not complete, but fear not as nothing is lost and it is always possible to get back what you had before the command. Resolve the conflicts and use
$ git add -u $ git rebase --continue
to finish the update. If the conflicts are too messy and you want to start over, run
$ git rebase --abort
If you prefer not to commit modifications you may instead use git stash to save and restore them. The commands are:
$ git stash save $ git pull --rebase (possibly resolve conflicts as above) $ git stash pop (possibly resolve conflicts)
Commit
When you're ready to record your changes in the repository it's time to commit. If you created any new files then first tell the repository to start tracking them. With CVS the command was:
$ cvs add mynewfile.txt
With Git the command is
$ git add mynewfile.txt
Next it is time to record a commit. With CVS the command was:
$ cvs commit (edit commit message; hope you don't make a typo or decide to abort the commit)
or
$ cvs commit -m "Inline commit message; hope you don't hit enter too early"
CVS would immediately record the changes in the central repository for all to see. Git commits are always local, a separate publication step is needed (see below) afterwards.
With GIT the commands are:
$ git commit -a (edit commit message; leave it empty to abort commit)
or
$ git commit -a -m "Inline commit message"
The -a
option is shorthand for the longer but more explicit alternative
$ git add -u $ git commit
In either case one may use
$ git commit --amend
to edit the commit message again or add missing files.
Publish
Git requires one extra step beyond the commit to share changes in the upstream repository. The command is
$ git push
See the Publishing section above for more information.
Resources
Additional information about Git may be obtained at these sites: