Last updated January 5, 2015.

Overview

This document contains a series of Git VCS command examples for project maintainers. Examples are based on modules, but themes, theme engines, and translations are essentially the same.

 

Before you start

Prerequisites:

Before you begin, review basic concepts about Distributed Version Control Systems in Introduction to Git. Pay special attention to the concepts of branches and tags.

Note: The brackets on this are not part of the commands, they just mark variables, so for example when you read mkdir [project_name] and your project is called Views, what you need to type is mkdir views.

 

Adding your repository to Drupal.org for the first time

Follow this procedure to add the code on your local machine to your project repository on Drupal.org for the first time. You can also find commands tailored specifically for your project by visiting your project page and clicking on the Version control tab. See Creating a new full project for details.

  1. Create a directory on your computer and change into it:

    mkdir [project_name]
    cd [project_name]

  2. Next, initialize the repository. This adds the .git directory, subdirectories and files that store your repository data.

    git init

  3. Then, add files to your repository. Use the sample command to create a .info file, or work with your actual files and directories as suits you. The key thing is to put something into your repository so you can complete the setup.

    echo "name = [Human Readable Project Name]" >project_name.info

  4. Let's make the repository on Drupal.org the default remote repository we pull from and push to. The command to do this is called "git remote add" and it takes two arguments, the first is the name we will use in our push and pull commands for this repository and the second is the actual repository URL. It's practical to make the first argument "origin" because push and pull both defaults to that name. The second argument looks like 'ssh://[username]@git.drupal.org:project/[projectname].git'.

    git remote add origin [username]@git.drupal.org:project/[project_name].git

  5. Finally, put your code on Drupal.org. Git commits are a little bit like the Ready, Set, Go of running a race. You get ready by staging your files with 'git add', get set by committing the files in your local repository with 'git commit', and go when you push your changes to the remote server with 'git push'.

    git add project_name.info
    git commit -m "Initial commit."
    git push origin master

 

Copying your repository onto Drupal.org from an existing repository

These are one-time steps for populating a Drupal.org repository from an existing Git repository (such as Github or anywhere else it might live).

# Clone the repo as a mirror from the original source
git clone --mirror [github_or_other_url]
cd [repository]
# Create a new remote using the maintainer URL from the version control tab.
git remote add newproject [maintainer_url_from_git_instructions]
# Push all the code and branches into the git.drupal.org remote
git push --all newproject

 

Cloning your Drupal.org repository

Cloning your existing Drupal.org repository can be useful when you need to copy it to a another local machine, or if you accidentally delete your existing local copy. The Version control tab of your project provides step-by-step clone commands tailored for your project, which you can copy and paste onto the command line. You can even customize the commands by selecting from existing branches.

In general, the clone command will be similar to the following:

git clone --branch [branch_name] [username]@git.drupal.org:project/[project_name].git
cd [project_name]

 

Working in your local repository

Once you have your repository created on Drupal.org and cloned locally, you can do various tasks.

Working with branches and tags

Git allows you to keep different versions of your code active on different branches, and to tag different versions of your code for release. Drupal modules use Git branches and tags in specific ways, which are described fully on other pages:

  • Read the Git Introduction if you do not understand what Git branches and tags are.
  • Read the Release naming conventions page to learn how Drupal modules should tie Git branch and tag names to released versions.

The sections below cover the Git commands used for branching and tagging, and assume you have already figured out why you are branching and tagging, and what branch/tag name you want to use.

Creating a release branch

Branches that live on Drupal.org, which you use to create public releases of your project, must follow specific release naming conventions that indicate the code's compatibility with Drupal core.

For example, if you want to create a branch called "8.x-1.x", you would use the following command: git branch 8.x-1.x. To start using that branch now that you have created it, type git checkout 8.x-1.x. You can also create and checkout a branch all in one command by typing:

git checkout -b 8.x-1.x

See also Creating a tag or branch in Git.

Creating a private, topical/feature branch

A common workflow is to develop a new feature or fix an issue in a private, topical branch or feature branch on your local machine. When you are ready to make these code changes public, you would then merge or rebase your work with the main, public branch that you push to the remote repository on Drupal.org.

Typically, for topical branches you use a branch name of [issue-number]-[short description]. To create a branch:

git checkout -b [branch_name]

Then you can edit files, apply patches, etc. Finish by committing to your branch, and then merging the changes back into the main line. (Instructions for all of these tasks are in the sections below.)

Checking out an existing branch

In Git, "check out" means to switch to using a different branch on your local clone. To switch to an existing local branch, use the command:

git checkout [branch_name]

Creating a patch

git fetch
git format-patch origin --stdout > [description]-[issue-number].patch

If you have added new files as part of your changes, you need to make git aware of them before it will be able to include them in a patch. You can do this by adding them to stage, staging your other changes, and then rolling the patch with the option '--stage':

git add [filename]
git diff --stage > [description]-[issue-number]-[comment-number].patch

Applying a patch

If you need to review/test the patch before committing it, first create a branch (see above). If not, you can work directly in the branch that you need to apply the patch to, and just checkout that branch. To apply a patch someone else has created for your project:

  • Checkout the branch or create a new one (see above).
  • Download the patch to your local machine (outside the repository).
  • Apply the patch by typing
    git apply /path/to/patch

Committing changes

After making changes (edits, adding files, applying patches, etc.) in your local repository, get your changes ready to commit with 'git add'. We recommend the '-u' flag, which looks at all the currently tracked files and stages the changes to them if they are different or if they have been removed. It does not add any new files, it only stages changes to already tracked files. This keeps you from inadvertently uploading files: git add -u

To add specific new files, you can use 'git add' with an explicit path and file name. To stage everything, files that have been removed, updated, and added, use 'git add -A'.

It is customary in the commit message to reference the node ID of the issue in your project's issue queue where the bug/feature request was raised, and to mention any contributors who helped with the code: "Issue #[issue number] by [comma-separated usernames]: [Short summary of the change]."

You would type the full commands as follows:

git add -u
git commit -m "Issue #[issue number] by [comma-separated usernames]: [Short summary of the change]."

For more details on providing history and attribution, see the related Commit messages - providing history and credit and Adding a commit author pages.

Moving and removing files from your project

While you cannot remove existing releases or actually remove files from the repository, it is possible to remove files from a branch. Sometimes a newer version of a module doesn't require a certain file anymore, or you want to reorganize the module by moving a file to another directory (or renaming it to another filename). Git allows you to accomplish this:

git mv foo.inc foo.bar.inc
git rm foo.meh.inc
git commit -m "Reorganized include files."

Checking your repository status

The git status command tells you:

  • What you would commit if you ran git commit
  • What you could add to the next commit by running git add
  • What you have committed but not pushed back to Drupal.org

Type: git status

Merging your changes back to the main branch

If you were working on an issue/feature branch, after committing, you will need to merge your changes back to the main branch. Before you do that, it's a good idea to grab the latest changes from drupal.org:

# Switch to your topical branch
git checkout my_topical_branch
# Update your repository's origin/ branches from remote repo
git fetch origin
# Merge the changes from the 7.x-1.x branch into my_topical_branch
git rebase origin/7.x-1.x
# Switch to local tracking branch
git checkout 7.x-1.x
git pull
# Merge the commits from my_topical_branch onto the 7.x-1.x branch
git rebase my_topical_branch

 

Notes:
git fetch origin retrieves all history from the "origin" remote repository without actually changing the code in your local working copy.

(You can optionally inspect the changes using git log origin/7.x-1.x before actually applying them to your local copy.)

git rebase updates your local working branch by adding commits from the branch you specify in the command on top of the current working branch.

 

Contributing changes back to drupal.org

When you are ready to make your new code publicly available, you can push the commits you made to your local release branch to Drupal.org. You can also create tags for release snapshots and push those to Drupal.org.

Pushing your code back to the repository on Drupal.org

Everything you have done up to this point has been acting on the local clone of your repository. The final step is to get these changes back to Drupal.org. (Note: The git pull --rebase; git push approach here will work in simple workflows, but note that with many committers or with sophisticated long-running feature branches you may have to adopt a more complex workflow like the one described in the Sandbox Collaboration Guide.)

# Update with changes that another committer might have made.
git pull --rebase origin 7.x-1.x
# Push your commits back up.
git push origin 7.x-1.x

Note: If you just want to push on which you are currently working, you can use git push.
Note: Drupal.org git repository prohibits the use of "force push" for rewriting history. The only way to modify a commit is to revert the commit, make your correction, and recommit.

If you get error 22 upon trying to push, see #1110692: Co-maintainer getting permissions error on push: Cannot access URL http://git.drupal.org/project/nagios.git/, return code 22. Use

git remote -v

to examine remote settings. Remotes with "http://" will not work for pushes, an SSH-based remote URL setting is required.

Creating an official release

Once your module is stable, it's time to create an official release for it. Just as Drupal comes out with 7.0, 7.1, and such, you can (and should!) do this with your module. You do that by tagging your code.

Assuming you are already using the correct branch (see above), and that all of your changes have been committed, you can tag your code as version 7.x-1.0 with the following commands (note the -a flag is encouraged since it stores additional annotation with the tag).

git checkout  7.x-1.x
git tag 7.x-1.0

The git tag command tags the latest commit (with all the latest files) in the current branch as belonging to a particular release. Note that you can tag a release as pre-release version (unstable, beta or release candidate) by adding a suffix to the tag. For example:

git tag 7.x-1.0-unstable1
git tag 7.x-1.0-beta1
git tag 7.x-1.0-beta2
git tag 7.x-1.0-rc1

As part of tagging, Git will ask you to assign a message to the tag, similar to commit messages. Use this message for release notes, highlighting the most important changes of this release.

Finally, push the tag to the upstream repository on drupal.org:

git push origin tag 7.x-1.0

Note that for new branches and tags you can not use the simpler git push command, you need to specify the name of the remote repository (origin was set up above) and the name of the tag/branch to be pushed. git push -u origin 7.x-1.0 will make git push work again.

See also Creating a tag or branch in Git.

Adding different release branches for your module

Once a stable release of a module is created, you may want to continue to add features, leaving the original release of your module intact.

To create a branch for a new major version of your module (for example, version 2.0 of the Drupal 7.x compatible version of your module), use the following commands:

# Make sure to branch off from the correct (probably most recent) predecessor branch:
git checkout 7.x-1.x
# Branch off the next major version:
git branch 7.x-2.x
# Switch to the new branch:
git checkout 7.x-2.x

Eventually, when version 2.0 is ready to be released you would tag the 2.0 version using the following commands:

git checkout 7.x-2.x
git tag 7.x-2.0
git push origin tag 7.x-2.0

You may want to edit your project node and click the 'releases' subtab and bump the major release also.

Comments

yhager’s picture

why not just 'git pull'?

--yuval

jpetso’s picture

git pull puts upstream changes on top of your local commits, whereas rebase put your local commits on top of upstream changes. Basically, plain git pull (without --rebase option) should only ever be used by maintainers that don't have any own commits and pull in other people's changes into their upstream repository. For updating from a "central" repository though, rebase is the way to go, and also safer as it doesn't permit rebasing modified (dirty) working copies.

yhager’s picture

If I have no local commits, then pull will behave the same way as rebase.

So why is pull --rebase not the default? Maybe we should recommend to make it so by adding some .gitconfig param (is that possible)?

[edit: I've read the rest of the comments, and the wiki page again - I see you removed pull alltogether. Please ignore my comment]

--yuval

TheMule’s picture

It should be noted that a rebase rewrites all history of your local commits. Maybe you don't care, but it creates new commits, leaving the old ones to be gc'ed. For one, you loose the timing info (all new commits have the date of the rebase). I'm not sure, it may mess with local branches and tags as I suspect they keep pointing at the old commits.

rebase is fine for well a defined change, a patch. You can keep rebasing your private branch, as you would maintain manually the patch as a diff that applies to the lastest release. Basicly git rebase does that for you.

I suspect the larger your project, the messier it becomes to manage things properly with constant rebasing. For sure, it becomes unmanageable very soon if you start publishing your branch for others to clone/pull.

.TM.

jpetso’s picture

BartVB replaced the two-liner

git fetch origin
git rebase origin/7.x-1.x

with

git pull --rebase origin

and I disagree on that, even if it's shorter. This is why I think so:

  • For one, this version hides the actual branch that will be used for rebasing, and I think it's always a good idea to be more explicit in order to understand and control better what is being done.
  • Second, we should not advertise pull, even if it comes with an option that makes it behave the way we like.
  • Third, the fetch/rebase split makes it very clear that if the rebase has conflicts for some reason and the user wants to bail out, only the rebase step has to be repeated, and the fetch can be left out. If the user aborts the rebase from within git pull --rebase, she has to learn the standalone rebase command as well. Better stick to commands that can be reused a lot.
  • And lastly, I think the additional documentation paragraph that I wrote below is very informative, and highlights an important part of the DVCS paradigm (i.e. "your local repository contains more stuff than just the checkout"). The one-liner doesn't allow to go into those details, because it hides the actual commands that I want to explain.

I hope you don't mind if I take the freedom and restore that one to my original version.

Pisco’s picture

I would have recommended the same change, but I agree with the points you made. Thank's for the doc.

Would it be helpful to create a script that guide one through the steps of an initial setup? One that prompts for user.name, user.email, the type (theme, module), the version (i.e 7.x-1.x) and the module name? I don't know if that's possible on Windows, but it would be fairly easy on Linux and OS X.

Jonathan Webb’s picture

If you're planning to always rebase then: `git config branch.autosetuprebase always` will make new branches use rebase instead of merge when you do a git-pull. You can also set this up for an individual branch by: `git config branch.<name>.rebase true`

mbutcher’s picture

Why use 'git branch; git checkout' instead of 'git checkout -b'?

The second is (a) more concise, and (b) far more common.

Give that you are after the "easy and quick" method, why introduce commands that we only use on rare occasions? (e.g. the edge case where we create a new branch that we *don't* want to use immediately.)

dstol’s picture

I've found that people who are very new to git often get confused with 'git checkout -b.' I agree that 99% of my use cases now are 'git checkout -b' I would err on the side of keeping it simple, hence 'git branch; git checkout.'

zhangx1a0’s picture

Cannot wait for giving a try. But some links are broken... How to apply a Git account now? thanks

flickerfly’s picture

Yeah, I'm looking forward to having a git account also. :-)

Josh The Geek’s picture

It's looking like you won't need one! See #992802: Create a module to capture the migration preferences of current d.o CVS account holders. If you have a CVS account, you will automatically have a Git account. If you don't, you won't need to apply. Currently, you will be able to create a project node, which will not have a human readable URL, just node/12345. Your first project will get extensive testing, similar to the current cvs application system. The next project will not have testing as extensive, just duplicate testing, and a quick test with Coder. Then the project will be given a human readable URL, like http://drupal.org/project/blah. Eventually, you would be given a role that automatically gives you a human readable URL. (This is what I can tell from the various Git issue queues.

Josh The Geek
Drupal.org
GitHub

flickerfly’s picture

Thanks for putting that information over here. That looks very interesting.

salvis’s picture

It would be helpful to also have the commands for cloning drupal or an existing module and for switching to the right branch.

drikc’s picture

The following references documentation page used in this page response by 'Access denied':
- create a release node: http://drupal.org/node/94151
- overview of contributions branches and tags: http://drupal.org/node/93999

Regards

makbeta’s picture

For those following the commands very closely. When creating a patch the suggested command has a typo in it. --stage should be --staged
So the following block of code:

git add [filename]
git diff --stage > [description]-[issue-number]-[comment-number].patch

should actually be as follows:

git add [filename]
git diff --staged > [description]-[issue-number]-[comment-number].patch