For Developers‎ > ‎How-Tos‎ > ‎

Get the Code

Post Git Migration Update! Developer workflow and tools documentation has now largely moved to the man pages provided with depot_tools.

Please see the online version of those docs, and especially the new tutorial page for the most up-to-date information about getting and working with Chromium sources.

Not all the information here has been migrated to the depot_tools docs yet, so this page will stay around for a while as a resource, but where there are discrepancies, the depot_tools pages should be considered authoritative.

New to Git?

If you're new to Git but experienced with Subversion, we recommend following the Git-SVN Crash Course. This guide should help you understand how Git differs from Subversion and how to get up to speed the fastest.


  • depot_tools is required on every platform. Install it and make sure it's correctly in your PATH.

Windows (non-Cygwin) Prerequisites

Run gclient TWICE, FROM A CMD WINDOW to download and setup everything else you need.  It's important to run twice, and not to use msysgit bash or other non-cmd shells, because otherwise gclient may fail to properly install all its dependencies. Using the "--version" flags just reduces the amount of output spew; it's not necessary for the operations to succeed. If you run gclient --version a third time it should succeed.

  gclient --version
  gclient --version

After running gclient (twice), depot_tools will now contain a full stand-alone installation of msysgit. If you have a previous installation of msysgit, it is strongly recommended that you use the version installed under depot_tools. This version of msysgit contains custom performance improvements that facilitate working with very large git repositories (like chromium and blink). You can run the shell from the provided version of msysgit using:

  /path/to/depot_tools/git-.../bin/sh.exe --login -i

where git-... will depend on which version of msysgit was fetched (e.g. git-1.9.0.chromium.5_bin). However you will normally just run git.bat, which should now be in your path.

Windows (Cygwin), Mac and Linux Prerequisites

You'll need to manually install:

  • Git 1.9 or above
  • git-svn
    • Required if you want to commit repos other than the chromium/src.git repo. Completely optional if you only want to access the repos in read-only mode.

Initial checkout

First, tell git about yourself.

  git config --global "My Name"
  git config --global ""
  git config --global core.autocrlf false
  git config --global core.filemode false git config --global branch.autosetuprebase always

Git credentials setup for committers (.netrc file)

If you plan to push commits directly to Git (bypassing Commit Queue, e.g. with 'git cl land') you would need to setup netrc file with your git password:

  1. Go to
  2. Login with your account (e.g. your committer account, ones work too).
  3. Follow the instructions in the "Staying Authenticated" section. It would ask you to copy-paste two lines into ~/.netrc file.
In the end, ~/.netrc (or %HOME%/_netrc on Windows) should have two lines that look like:

machine login password <generated pwd>
machine login password <generated pwd>

Make sure that ~/.netrc file's permissions are 0600 as many programs refuse to read .netrc files which are readable by anyone other than you.

On Windows, you must manually create HOME as a per-user environment variable and set it to the same as %USERPROFILE%.

You can check that you have everything set up properly by running tools/ .

SVN setup for committers

If you want to use SVN (optional, only do this if you know you need it), ensure that you have a SVN account and that your login credentials are registered locally via:

  svn ls svn://
  svn ls svn
://  # if checking out ToT Blink

Password is at

When you first run this, you will be prompted for your credentials, which should then be stored locally. On second run these should automatically log you in, without prompting for credentials, otherwise, make sure "store-passwords" is not explicitly set to "no" in ~/.subversion/servers and ~/.subversion/config.

Actual Checkout

We will use the fetch tool included in depot_tools to check out Chromium, including all dependencies. This will create a new folder in your current working directory named src.

fetch --nohooks chromium  # 'chromium' may alternatively be one of blink, android, ios, see below.
# or alternatively
fetch --nohooks --no-history chromium  # get a shallow checkout (saves disk space and fetch time at the cost of no git history)

cd src
git checkout master

# if you are building for Linux only:

# if you are building for Android:

# if you are building for iOS:
echo "{ 'GYP_DEFINES': 'OS=ios', 'GYP_GENERATOR_FLAGS': 'xcode_project_version=3.2', }" > chromium.gyp_env

gclient sync

Alternatives to 'fetch chromium' are:

  fetch chromium # Blink from DEPS (most recent roll) - if you're not working on Blink itself
  fetch blink    
# Blink at Tip of Tree (latest) - if you are working on Blink instead of or in addition to Chromium
  fetch android  
# Blink from DEPS with additional Android tools - if you are building for Android
  fetch ios      
# Using iOS dependencies instead of Mac dependencies - if you are building for iOS

fetch chromium and fetch blink both fetch both Chromium and Blink, but the two commands fetch different versions of Blink: fetching chromium will get a dated Blink (most recent roll to Chromium), and is sufficient and easier if only working on Chromium, while fetching blink will instead get the latest Blink (ToT), and is useful if working on Blink.

In other words, fetch X if you want to work on X.

Note that, by default, fetch creates a local branch called "master".  This can be confusing if you mistake it for the upstream "origin/master".  Unless you know what you're doing, you should simply delete this branch as follows:

  git checkout origin/master
  git branch -D master

Note that if e.g. you're developing Blink, you'll want to do this in you Blink directory (likely third_party/WebKit) as well.

Post initial checkout, you should be able to switch between projects via but better tooling is being worked on. If you wish to later add Android to an existing Chromium tree, will not help. It may be better to make a separate top level directory and have a parallel tree. While the projects can live happily in the same tree, we don't have tools yet to help you configure the tree for both.

Additional environments

If you're building Chrome for:

Using the last known good/compilable revision (LKGR/LKCR)

If you'd like to only sync to the last known good revision (lkgr), you can checkout origin/lkgr instead of origin/master. Similarly, the lkcr is available at origin/lkcr.

Updating the code

Update your current branch with git pull followed by gclient sync, as follows.  Note that if you're not on a branch, git pull won't work, and you'll need to use git fetch instead (but you make all your changes on branches, right?  See "Contributing" below).

  git pull

  gclient sync

If developing Blink, you'll need to pull Blink as well, as follows:

  cd "$CHROMIUM_DIR" && git pull
"$BLINK_DIR" && git pull
  gclient sync

To speed up updating, using more jobs, for example --jobs=16:

  git pull

  gclient sync


With git you should make all your changes in a local branch. Once your change is committed, you can delete this branch.

Create a local branch named "mywork" and make changes to it.

  cd src
  git new-branch mywork


Commit your change locally (this doesn't commit your change to the SVN or Git server)

  git commit -a

If you added new files, you should tell git so by running git add <files> before committing.

Upload your change for review

  git cl upload

Send a try job

  git cl try

See Contributing code for more detailed git instructions, including how to update your CL when you get review comments.

There's a short tutorial that might be helpful to try before your first change: C++ in Chromium 101.

Commit your change manually

The preferred way to commit changes is by using the commit queue. If this is not an option, you can commit directly from your git checkout (dcommit in Chromium, push in ChromeOS). See "Directly committing code" for details; this can easily break things, and is finicky, so please only do this is necessary, and follow the instructions to the letter.


See GitTips for general tips, and GitCookbook for more Chromium-specific tips.


See http://wiki/Main/ChromeBuildInstructions

Multiple Working Directories

If you are a multitasker or want to build chromium for different targets without clobbering each other, then perhaps you'll like the script located in depot_tools. The script works by creating a new working directory with symlinks pointing to the git database(s) found in your original chromium checkout. You can have as many working directories as you want without the overhead and hassle of cloning chromium multiple times. /path/to/original/chromium chromium2

Working with release branches

Syncing and building a release tag

Releases are tagged in git with the release version number.
Note: You cannot commit to a release tag. This is purely for acquiring the sources that went into a release build.

# Make sure you have all the release tag information in your checkout.
git fetch --tags
# Checkout whatever version you need (known versions can be seen with 'git show-ref --tags')
git checkout -b your_release_branch 34.0.1847.9  # or more explicitly, tags/34.0.1847.9
gclient sync --with_branch_heads --jobs 16

Checking out a release branch

Note: it is NOT possible to sync and build full release branch (i.e. with consistent third_party DEPS) refer to the internal documentation for that.
The instructions below show how to check out a release branch only for a specific project  (e.g. src.git)

# Make sure you are in 'src'.
# This part should only need to be done once, but it won't hurt to repeat it.  The first
# time might take a while because it fetches an extra 1/2 GB or so of branch commits.
gclient sync
git fetch

# Checkout the branch 'src' tree.
git checkout
-b branch_$BRANCH branch-heads/$BRANCH
# Checkout all the submodules at their branch DEPS revisions.
gclient sync
--jobs 16

Edit files, 'git commit', and 'git cl upload' as normal. After that, 'git cl land' commits to the right branch magically! (Don't try to use the CQ on a branch.)

To get back to the "trunk":

# Make sure you are in 'src'.
git checkout -f master
gclient sync
--jobs 16

Also, if you need to merge changes to DEPS, see the internal ChromeReleaseBranches?? wiki page for some notes.



Enumerate your local branches:

  cd src
  git branch

Switching from one branch to another: Example: Switching from branch 'branch1' to branch 'branch2'.

  cd src
  git checkout branch2

Note that - can be used to refer to the previous branch, which is useful when switching between two branches.

git checkout some_branch
git checkout - # back to previous branch!

Suggested branching workflow

We normally do our feature work in branches to keep changes isolated from each other. The recommended workflow is to make local branches off the server master, referred to as the origin/master branch.  The git-new-branch command (in depot_tools) will do this:

      git new-branch branch_name
Note that this is equivalent to the following:
      git checkout -b new_branch origin/master

Branch off a branch

If you have dependent changes, a very productive workflow is to have a branch off a branch. Notably, this means that your patch sets (in Rietveld) will show the separate changes, and be easy to review, rather than showing the merged changes (including irrelevant changes), and means you can commit downstream CLs without having to rebase them after the upstream has landed. Do this as follows:
git checkout master
git checkout branch1
# some edits, commit
git checkout -b branch2
git branch --set-upstream-to=branch1
# some edits, commit

Now when you update the first branch, you can simply git pull on the second branch as normal to pull in your changes:
git checkout branch1
# some edits, commit
git checkout branch2
git pull

Note that these incremental patch sets are easy to review, but cannot be applied to HEAD (because they are based off another branch), so you cannot test them on try bots. To test these, upload the diff from HEAD to a different (test-only) issue and test there:
ISSUE=$(git cl issue | sed -r 's/[^0-9]*([0-9]*).*/\1/')  # Save current issue via git cl issue
git cl issue 0  # Clear issue
git cl upload -t "[TEST ONLY] Run tests for $ISSUE" -f origin/master  # Upload to new issue, no prompts
TEST_ISSUE=$(git cl issue | sed -r 's/[^0-9]*([0-9]*).*/\1/')  # Save test issue
git cl try
git cl issue $ISSUE  # Restore original issue

To open the test issue in Rietveld:
git cl issue $TEST_ISSUE
git cl web
git cl issue $ISSUE

To try again:
git cl issue $TEST_ISSUE
git cl upload -t 'Try again' -f origin/master
git cl try
git cl issue $ISSUE

...and then when finished, delete the CL to clean up (via Rietveld):
git cl issue $TEST_ISSUE
# git cl delete  # This command does not exist, go through Rietveld
git cl web
git cl issue $ISSUE

Lastly, when an upstream branch has landed, and you've rebased it so it agrees with master, you can set the downstream branch's upstream branch to be origin/master, which means you can now forget about the earlier branch:
git checkout branch2
git pull  # assuming branch1 is up-to-date with origin/master
git branch --set-upstream-to=origin/master

Splitting up a CL

A common variant of "branch off a branch" is splitting up a large CL into pieces. Given a local branch big, you'd like to split it up into branch1 and branch2.

One way to do this is to split off branch1, have that reviewed and committed, update local repo (gclient sync), and then rebase big to master. This is ok, but adds latency, and you can get the same result locally, so the second part of the CL can be uploaded and reviewed even before the first part is committed.

This can be done manually, particularly if the files don't overlap, by making a new branch branch1, manually copying the changed files in the first part, then branching branch2 off of that, and manually copying the files in the second part.

However, this can be done more cleanly via git. The main points are git-add -i (Interactive Stagingto interactively choose files or hunks of a patch set) and git-rebase (to set the second part to be dependent on the first part, removing the common changes); git-cherry-pick is a technicality:
# first split off branch1
git checkout origin/master
git new-branch branch1
git cherry-pick -n ..big  # apply and stage all ancestors of big that are not ancestors of HEAD, do not commit
git add -i  # interactively choose which files or hunks to stage
git commit  # commit staged changes
git checkout -- . # discard unstaged changes

# next set big to be a branch off of branch1
git checkout big
git branch --set-upstream-to=branch1
git rebase branch1  # may need to resolve conflicts
git branch -m branch2  # done!

Concretely, git-cherry-pick -n applies and stages all changes, but does not commit them. In git-add -i, you can unstage files via 3: revert, and then stage files (or hunks of files, or edit the diff manually) via 5: patch, with manually editing via by the e - manually edit the current hunk option when staging a hunk. While tedious, this is often easier than resolving conflicts during rebasing.

Deleting an obsolete branch

You generally want to delete local branches after the changes have been committed to master. It is safest to check that your work has, in fact, been committed before deleting it.
Remember that you can always apply a CL that has been posted via:
  git checkout -b myworkfrompatch
  git cl patch
12345  # Using CL issue number, not bug number, applies latest patch set
  git cl patch https
://  # Use URL of raw patch for older patch sets as long as your CL has been posted, you can easily recover your work. Otherwise, you'll need to dig through the git repository, so be careful.

Simply, if master (remote or local) is up-to-date and your branch has been rebased, git branch -d will delete the branch. If not, it will refuse; to force deletion, use git branch -D. So make sure master is up-to-date, rebase branch, and then try deleting (optionally check manually before).

Beware that if your local branch has many revisions (instead of always amending a single revision), rebasing to master may fail, since it will try to apply the patches incrementally. You can avoid this by squashing your local revisions into a single revision (see 6.4 Git Tools - Rewriting History, or more simply squashing commits with rebase). This may be more trouble than it's worth, but it's the safest way.

To check that the branch has been committed upstream:

  git checkout mywork
  git rebase origin
  git diff
--stat origin/master  # optional check

If there are no differences, delete the branch:

  git checkout origin/master
  git branch
-d mywork  # will only work if has been merged

NOTE: If you haven't waited long enough after your commit, it is possible that 'git fetch' did not get your svn commit and git will continue to believe that you have local changes, which will prevent "git branch -d" from succeeding. It's best to redo the steps later, (The repo is updated every 3 minutes) but you can also instruct git to force-delete your branch.

Note that when you delete your branch, it will give you the SHA-1 hash for its tip:

    Deleted branch mywork (was 123abc0).

You can then recover the branch via:

    git checkout -b mywork 123abc0

If you forget the hash, you can find it via git reflog. (Reference: Can I recover branch after the deletion in git?)

Prevent commits to master

If you commit to master, updating will be messy.  (This is a good reason to simply delete master entirely, as noted near the top of this document.  You only need to read the remainder of this section if you don't do this.)

You can prevent this by adding a pre-commit hook that checks if you're in master and stops you from doing this. Create a file named chromium/src/.git/hooks/pre-commit and add the below to it, then mark executable. (Blink developers: add in blink directory as well.)


# Prevent commits against the 'master' branch
if [[ `git rev-parse --abbrev-ref HEAD` == 'master' ]]
'You cannot commit to the master branch!'
'Stash your changes and apply them to another branch, using:'
'git stash'
'git checkout <branch>'
'git stash apply'
exit 1

If you've accidentally uploaded a change list from master, you can clear the association of an issue number with master via:

  git cl issue 0

If you've accidentally committed to master, then, after copying your work to a new branch (e.g., make patch and then apply to new branch), you can clean up master by deleting your accidental commit as per this answer to How to undo the last Git commit? -- see more details there.

  git reset --hard HEAD~1

If gclient sync fails

  • Make sure you checked out master: run git branch
  • Run git status to make sure you don't have any uncommitted changes
  • Try running git rebase origin/master directly to get more specific errors that gclient sync might not show
  • Do the same in each subdirectory that belongs to a separate repository that you might have worked in - for example, if you hacked on WebKit? code, cd to third_party/WebKit?/Source and run git status there to make sure you're on the master branch and don't have uncommitted changes.

Sometimes you'll get the message "You have unstaged changes." when you personally don't, often due to a directory that has been moved or delete. You can fix this by moving the directory outside of the repo directory (or deleting it), and then trying gclient sync again.

It is also possible that you're getting this due to local changes (or other problems) in the depot_tools directory. You can fix these by going to depot_tools and resetting:

   git reset --hard HEAD

Working with repositories in subdirectories other than the main Chromium repository

Your source tree includes many other repositories in subdirectories - mainly in third_party, but also elsewhere. See src/DEPS for the full list.

Each subdirectory is its own git tree, so you should start a branch inside a subdirectory if you want to work there. Be sure to commit and checkout master again when you want to sync your tree again later!

Committing from repositories other than the main Chromium repository

If you wish to commit to one of these repositories, you will need to configure git svn like you did for the main Chromium repository.

However, in order to ensure that git cl dcommit will do the right thing, some additional configuration is needed in order to match the svn repository the git mirror is mirroring from.

To do so, run:

  cd third_party/some_dependency_here
  git log

And look for the line beginning with git-svn-id: . For example, if you wanted to commit to ffmpeg (src/third_party/ffmpeg), running git log would show something like git-svn-id: 4ff67af0-8c30-449e-8e8b-ad334ec8d88c

If the URL starts with svn://, the steps are very similar to SVN setup for committers, replacing every occurrence of trunk/src with whatever the path was in the git log command was (eg:trunk/deps/third_party/ffmpeg).

  cd third_party/some_dependency_here
  git svn init
--prefix=origin -T trunk/deps/third_party/some_dependency_here svn://
  git config svn
-remote.svn.fetch trunk/deps/third_party/some_dependency_here:refs/remotes/origin/master
  git fetch origin
  git svn fetch

If the URL starts with or, you will need to configure git svn to fetch from that URL, but when committing, to use svn:// If the URL was https://, use https://' instead of http://` below:

  cd third_party/some_dependency_here
  git svn init
--prefix=origin/ -T trunk/deps/third_party/some_dependency_here
  git config svn
-remote.svn.fetch trunk/deps/third_party/some_dependency_here:refs/remotes/origin/master
  git config svn
-remote.svn.pushurl svn://
  git fetch origin
  git svn fetch

The key is setting svn-remote.svn.pushurl to the read-write URL of the project, even though the URL passed to git svn init may be the read-only URL.

For projects hosted on (for example, gyp) there's slightly different incantations required. For example with gyp:

  git svn init -Ttrunk --rewrite-root=
  git config svn
-remote.svn.fetch trunk:refs/remotes/origin/master

Rolling DEPS for third party directories and other things in the DEPS file

When dealing with third-party code it is frequently the case that the code in question is hosted in a SVN repository (or anything else non-git). Chromium has put git "mirrors" in place for all such projects, so if you look in the DEPS file now you will find only git hashes! How, then, do you go about updating the DEPS file for code that doesn't live in Git? There are at least two ways to do this, shown below.

Method #1: Using the roll-dep script
  # cd to the main src directory for your checkout
  cd src
  # Create and switch to a new branch
  git new-branch depsroll
  # Run roll-dep (provided by depot_tools) giving the dep's path and the desired SVN revision number
  # (e.g., third_party/cld_2/src for 'cld2', and a revision such as 169 from Subversion)
roll-dep third_party/foo/bar REVISION_NUMBER

Method #2: Manual inspection (patch the resulting hash into the DEPS file by hand)

# cd to the main src directory for your checkout
pushd src
# Create and switch to a new branch
git new-branch depsroll
# cd to the directory listed in the DEPS file (e.g., src/third_party/cld_2/src for 'cld2')
cd third_party/foo/bar
# Fetch (but do not pull) the latest revisions from Chromium's git mirror of the remote repository
git fetch origin
# Use 'git log' to list the commits in the mirror and find the hash of the one you need
git log origin
# Go back to src/
# Patch the resulting revision into your DEPS file by hand.
Regardless of which method you follow you should now have a modified DEPS file, so just commit it and upload as normal, e.g.:
  git commit -a
git cl upload

Determining your current svn revision

  git svn info

Reverting a change

From a branch, find the Git Commit ID (SHA1) of the revision you want to revert

  cd src
  git log
  git svn find
-rev r1234567

Revert the change and commit it locally

  git revert <sha1>

Upload for review

  git cl upload


  git cl dcommit --tbr

Adding new repositories to DEPS

If you are adding a new repository to pull from, make sure that repository's svn URL can be parsed by the tools by running:

python tools/deps2git/ -o .DEPS.git

Don't manually check in changes to .DEPS.git (see "Rolling Deps" above).

Make sure that the repository in question is mirrored at To mirror a repository or add a custom URL mapping to, please file an infrastructure ticket.

Seeing strange errors using Git on Windows?

If the Git command line doesn't work for you, please ensure that your environment variables like EDITOR, HOME, and GIT_SSH are all set to strings not enclosed in double quotes. We have fixed at least one error caused by this previously. It's possible that overusing quotes in your variables will cause other errors, as well.

Curious about how git-svn works?

Check out these links:

After you read those and understand the git-svn commands and workflow, then you'll realize that all git-svn does is set up and manage a new git remote. If you don't know about git remotes, you'll want to learn more about those, too.

Using Emacs as EDITOR for "git commit" on Mac OS

Using the Cocoa version of Emacs as the EDITOR environment variable on Mac OS will cause "git commit" to open the message in a window underneath all the others. To fix this, create a shell script somewhere (call it $HOME/bin/EmacsEditor? in this example) containing the following:


# All of these hacks are needed to get "git commit" to launch a new
# instance of Emacs on top of everything else, properly pointing to

() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"

for arg in "$@"
  full_paths[$i]=$(realpath $arg)

open -nWa /Applications/ --args --no-desktop "${full_paths[@]}"

and in your .bashrc or similar,

export EDITOR=$HOME/bin/EmacsEditor

Tweaking similarity

git-cl defaults to using 50% similarity as a threshold for detecting renames. This is sometimes inappropriate, e.g., if splitting off a small file from a large file (in which case you want a smaller threshold, to avoid false negatives), or when adding a small file (in which case you want a larger threshold, to avoid false positives from common boilerplate). This is controlled by the add_git_similarity function in, and you can set threshold to a given value for a branch (saved in config for that branch), or not look for copies on a specific upload (but not saved in config for the branch):

git cl upload --similarity=80  # set threshold to 80% for this branch
git cl upload
--no-find-copies  # don't look for copies on this upload

Managed mode

Managed mode is a deprecated feature of gclient. It was conceived to give an easier workflow for newcomers to git, but turned out to be full of surprising behaviors. It has thus been deprecated, unmanaged mode is the default, and existing users of managed mode are encouraged to change to unmanaged mode.

To check which mode you are using, check .gclient (the gclient config file) and see the value of the "managed" flag. To switch to unmanaged mode from managed mode:

  • edit your .gclient and set:
  •    "managed": False,
  • update your repository by using git pull (as described above), followed by gclient sync, rather than just gclient sync.

To make the Blink repo also unmanaged, first fetch blink and then:

  • edit your .gclient and set:
  •    "managed": False,
    "custom_deps": {
    "src/third_party/WebKit": None,
  • update your repository by using git pull in Chromium, then git pull in Blink (as described above), followed by gclient sync, rather than just gclient sync.


The main difference between managed mode and unmanaged mode is that in managed mode, local branches track local master branch instead of origin/master, and gclient “manages” the branches so that they stay in sync. However in practice this leads to two master branches (local master and origin/master) that go out of sync and prevent further uploads/commits. With unmanaged mode you always have only one master: origin/master. The local master still exists but is not treated in any special way by the tools.

What's missing

Need help?

If you find yourself needing help with the new workflow, please file a bug with the infrastructure team at