In the past, I’ve written extensively about using Git with WordPress projects. I’ve focused primarily on Git as the primary development channel, with SVN (in this case, plugins.svn.wordpress.org) used for distribution only.
In contrast, I use Git for all my local development on the BuddyPress project. In this case, BP’s “official” history is in its SVN repo. My local Git repo is just a mirror. This setup means that you need a different kind of workflow, one that gives precedence to the Subversion repository. I’ll be using BuddyPress as an example below, but a similar workflow will work for any Subversion-based project where you want to do local development in Git.
(Side note: Mark Jaquith published a similar guide on how he uses Git to do WordPress core development. His process and mine are independently derived, but they are, of necessity, conceptually similar.)
Setup
- Get Git.
- Create a local directory for your BuddyPress installation. Use git-svn-clone to pull the SVN revision history into this directory.
$ mkdir /path/to/wordpress/wp-content/plugins/buddypress $ git svn clone -T trunk -t tags -b branches http://buddypress.svn.wordpress.org /path/to/wordpress/wp-content/plugins/buddypress
Git will crawl through the entire revision history of the BuddyPress project, which will take a while.
- I generally have two active, ongoing branches in my local BP-Git repo, one corresponding to
trunk
and one corresponding to the current bugfix branch. I usemaster
(the default Git branch) fortrunk
, since that’ll be the default setup after the clone. You’ll need to create the bugfix branch manually. I use the ‘1.6.x’ naming convention for the 1.6 SVN branch, etc.$ cd /path/to/wordpress/wp-content/plugins/buddypress $ git checkout -b 1.6.x 1.6 # In other words, create a new branch, called 1.6.x, which tracks svn's 1.6 branch
- If you’ll need to do development using BP’s bbPress 1.x implementation (“Group Forums”), you’ll need to manually download bbPress 1.1 into
buddypress/bp-forums/bbpress/
Development
Day-to-day development goes something like this:
- Make sure you’re on the right branch. Most day-to-day dev happens on trunk/master, but in some cases it’s necessary to work on the current bugfix branch. Once you’re on the right branch, make sure that you have no unstaged changes, and use git-svn-rebase to get the most recent changes from upstream:
$ git checkout 1.6.x $ git svn rebase
- Create a new topic branch for this bugfixing session. I generally name it after the ticket number.
$ git checkout -b bp4453
- Fix your bug or develop your feature. Commit small changesets as desired.
- When you’re done with your development, you’ll be in one of the following situations.
- You’ve fixed the issue, and want to merge your commit history directly back into the public branch. This generally means that you fixed everything with a single changeset, or perhaps a small number of changesets that have good commit messages, etc. In that case, you can do a straight merge back to the public branch. Switch back, git-svn-rebase to make sure none of your collaborators have updated the SVN branch since you started working, and then merge.
$ git checkout 1.6.x $ git svn rebase $ git merge bp4453
- You’ve fixed the issue, but you want to reduce a large number of changesets to a single commit. You have a few options here. You can use
git rebase -i
like Mark suggests. I generally do not do this, because rebasing on publicly shared SVN branches makes me nervous. Instead, in these cases I’ll use a squashed merge, which lays all of your changes on top of the destination branch, and leaves them uncommitted.
$ git checkout 1.6.x $ git merge --squash bp4453 $ git commit -m "This is the actual commit message I want to show up on BP's SVN"
- You’ve fixed the issue, and want to merge your commit history directly back into the public branch. This generally means that you fixed everything with a single changeset, or perhaps a small number of changesets that have good commit messages, etc. In that case, you can do a straight merge back to the public branch. Switch back, git-svn-rebase to make sure none of your collaborators have updated the SVN branch since you started working, and then merge.
- You want to share your changes with others, in the form of a patch, before committing to SVN. You’ll need to use the
git diff
utility, while doing a formatting trick to make sure that it’s compatible with the standard UNIXpatch
utility used in the SVN world.$ git diff --no-prefix 1.6.x...HEAD > ~/path/to/patches/4453.01.patch
- Assuming you are ready to send some commits up to SVN:
$ git svn dcommit
- In some cases, you may have sent a commit to the bugfix branch that needs to be applied separately to the main dev branch (trunk). There’s a couple different ways you might handle this. I usually use
git-cherry-pick
:$ git checkout master $ git svn rebase $ git cherry-pick e1f2e3f # The hash of the Git commit on the bugfix branch $ git svn dcommit
Releasing
Releases follow a regular tag workflow:
$ git checkout 1.6.x $ git svn tag 1.6.2
We do some weird stuff with BuddyPress (related to mirroring on wordpress.org/extend), which is outside the scope of Git – sadly I have to use svn for some of it :'(
Some of this is specific to BP, but most can be applied to any project where you want to use Git on a project that lives in SVN. Now git out there and git er done! and other ‘git’ puns.
Pingback: Using Git locally for a Subversion-based project (like BuddyPress) | Teleogistic - Dougal Campbell's geek ramblings
So glad you dedicated a post to Git and SVN-based projects!
I’ve been doing some research about Git-SVN workflows and some posts like this one (http://stackoverflow.com/a/4238528) recommend doing this:
git merge –no-ff BRANCH_NAME_TO_MERGE
git branch -d BRANCH_NAME_TO_MERGE
git commit –amend “Commit message”
git svn dcommit
Instead of “git merge –squash BRANCH_NAME_TO_MERGE” because it preserves the history from the branch in “git log”.
I know this would only be applicable to your local Git repo, but it might be useful if you ever have to look back on previous commits down the line.
Do you have any thoughts on whether this workflow will create problems in the future?
Hi Ray – Obviously, I had you in mind when writing this 🙂
The main differences between
git merge --no-ff
andgit merge --squash
, as I understand them, are this.git merge --squash
will not actually do any commits. It generates a diff between the source branch and target branch, lays it on top of the HEAD of the target branch, and stages the changes. In contrast,git merge --no-ff
will not only give you a merge commit (that’s the--no-ff
bit), but it will also lay every changeset since the fork on top of the target branch. This can be fine if you are happy with your local commit history. But if you’re like me, then your topic branches are full of junk commits which serve about the same function as saving your game of Wolfenstein just before you go into fight a boss because you know you’re going to die like 20 times.The
git commit --amend
trick just allows you to reset the most recent commit, restage it, and then recommit it with a new commit message. So when coupled withgit merge --no-ff
, it just allows you to change the commit message “Merging branch foo into bar” to something more meaningful.Anyway, in a broader sense, I don’t think anyone looking at the history of the shared repo will particularly care whether you used a local branch to do development on a specific feature or bugfix, especially if you were the only one doing that development (you never pushed the topic branch up). In other words, allowing the merge to fast-forward seems like the desired behavior in this case – the extra merge commit doesn’t provide any real context that’s useful to future devs. In contrast,
--no-ff
*is* useful when a major shared topic branch is merged into another branch. For example, on the CUNY Academic Commons, when merging changes from a bugfix branch into the bleeding-edge master branch at release time (which is how I do it on a Git-only project, instead of cherry-picking), I generally use--no-ff
so that you could look through the log of the master branch and tell which commits came from maintenance releases.All this said, I don’t think
--no-ff
would cause any problems, but it will create extra commits in the SVN repo that don’t have much context (the merge commits). So I would avoid--no-ff
on a project like BP.Pingback: Using Git locally for a Subversion-based project (like BuddyPress) | Teleogistic
Pingback: Dougal Campbell: Using Git locally for a Subversion-based project (like BuddyPress) | Teleogistic | WordPress Planet
Thanks for sharing your git/svn workflow, Boone!
Pingback: Using Git locally for a Subversion-based project | beta robbyedwards.com
This is very helpful, thanks Boone! There’s some extraneous markup in the code snippets – I realize this is a pretty old post but it’s also the first search hit I got for “subversion clone buddypress” today.
Thanks for the heads-up, Ryan! Fixed.