Working with Git

Getting Git

If your machine doesn't already have git installed, get a copy of the 'git' version control system. This is available for many platforms from their upstream package repositories or, failing that, can be downloaded in both source and binary form from http://git-scm.com/download

If you look for a GUI tool to use with git, you can use the built-in GUI by starting "gitk" from the command line. For Windows there is TortoiseGit, on the Mac you can use gitx or
Tower and for all platforms (Mac, Linux, Windows) there is SmartGit - more tools exist (PhpStorm als has Git support), if those don't fit your needs.

Installing git through MacPorts? Make sure to install the bash_completion variant as well to get autocompletion for commands, branch names, remotes, tags, ...

port install git-core +bash_completion

First-time Git setup

Git has to be set up initially, meaning you should tell it a little about yourself, like your email address and full name, as you are registered on TYPO3.org. So it knows who you are when doing commits:

$ git config --global user.name "John Doe" 
$ git config --global user.email johndoe@example.com

More details and helpful configuration options are explained in the Pro Git book, chapter 1.5 http://progit.org/book/ch1-5.html

If you intend to push changed code back for review, please read the article about Working_with_Git_and_Gerrit

Getting the codebase

Note: To clone what we call "distribution" or "application" a single clone command does not suffice! We used svn:externals, and a replacement for this in git are "submodules". See below for a recipe to clone those types of project.

You can download the repository for a project by running one of

git clone git://git.typo3.org/<projectname>.git
git clone git://git.typo3.org/<projectname>.git <name-of-directory>

to place the clone in a directory called like the project or to place your clone in a specific directory.

This will give you a complete copy of the repository and, unless you are exceptionally short of either disk space or time, this is the approach we recommend. Unlike with Subversion, you are not just checking out a particular branch, but making a local copy of the project's whole revision history, across all of it's branches. This does make the download pretty large - but makes daily work with Git blazingly fast and allows for all the goodies of a distributed SCM.

Updating the local copy

Note: To update what we call "distribution" or "application" a single pull command does not suffice! We used svn:externals, and a replacement for this is in git are "submodules". See below for a recipe to update those types of project.

When you want to update the local repository with the central one, running

git pull

will pull all of the new changes into your local repository, and merge those changes into your correct working tree. Note that whilst this is fine when you are browsing the repository, you may want to exercise more control over how upstream changes are merged into your development code.

Handling "superprojects" bundling multiple packages

We used svn:externals a lot to combine some common configuration and code with assorted packages to form "distributions" (e.g. TYPO3 FLOW and TYPO3 Neos) or "applications" (e.g. the Blog). Git does have a replacement for svn:externals called submodules. It does not allow pointing to trunk instead of a fixed revision, so some care needs to be taken.

Cloning a superproject

As usual you need to clone the distribution or application. Then do the following from the root folder of the new clone:

git submodule init
git submodule update

If you are lazy, the same effect can be achieved cloning like this right from the start:

git clone --recursive git://git.typo3.org/<projectname>.git

Updating a superproject

When you update the superproject using git pull the submodules will not be updated, you need to run an additional git submodule update afterwards.

Note: Make sure you know what you are doing!

If you have pulled changes into a submodule or worked on the code there, submodule update will override the changes and check out the commit recorded in the superproject.

If you worked on a topic branch (very recommended!) you can simply checkout that branch again to get your work back.

If you want to update submodules prior to them being "officially" included in the superproject you can do that by

git checkout master
git pull

in the submodule root folder. So, to simulate what we had earlier with svn:externals pointing to trunk of all packages included with a superproject you can do this:
git submodule foreach 'git checkout master; git pull'

Working on the code

We strongly recommend that you do all of your development upon 'topic branches.' This allows you to isolate multiple unrelated changes, and makes it easier to keep your tree in sync with the upstream one.

Before creating a new topic branch, running

git fetch

will make sure that your repository knows about the latest upstream changes (unlike git pull, this will not update any files that you may have checked out).

To create a new topic branch:

git checkout -b <branch>

For example, to work on a patch to fix ereg warnings, based on the current development code, you would do:
git checkout -b fix-ereg-warnings origin/master

This puts you on a new branch, ready to start writing code. All new development should be based upon the origin/master branch, submissions based upon other branches are unlikely to be accepted, unless they address issues that are solely present in that branch.

To tell git about any new files you create as part of your patch

git add

is used. If your patch results in any new byproducts (cache, metadata files, etc) that git should not be tracking, please make sure that they're caught by the .gitignore mechanism. You can do this by checking that they don't appear in the output from git status

git mv and git rm are used to move and delete files respectively.

git commit -a
is used to commit code to all of the files that git is currently tracking (that is, all of the files that you have checked out from the repository, and all those which you have run git add on)

Be sure to explore the power of staging your changes: unlike with Subversion you can stage some changes to a file for commit while not (yet) stage other changes to the same file. This can come in very handy. To shelve work in progress, have a look at git stash.

When you can't see the wood for the trees

If, in the middle of development, you discover that you've gone down a blind alley, and wish to go back to the state of your last commit

git reset --hard

will discard all of the changes you have made since the last commit, or
git checkout -f <file>

will restore <file> to the state it was in at the last commit.

Keeping up with upstream changes

If you're working on a long running development project, you will find that the point your created your topic branch rapidly recedes into history. At some point (and at least before you share your code with us), you'll probably want to update your tree. There are a number of ways of doing this.

If you haven't shared your tree with anyone else, then you can use

git rebase <branch> <topic>

(Where <branch> is the name of the upstream branch - for example origin/master, and <topic> is the name of the topic branch you are currently working on)

Note that git rebase changes your local history (it moves the branch point of your topic branch to the top of the upstream branch), and is a bad idea if others have cloned your repository. See man git-rebase for more details.

If you can't rebase, then consider either merging the changes onto your local branch, or creating a new topic branch and cherry picking your changes onto it. The man pages for git merge and git cherry-pick provide more detail on these options.