views:

73

answers:

2

Our University provides web hosting to campus departments on servers we manage. Installing open-source third-party programs requires modifying file permissions and code in the program before it will run. (We're using suEXEC, if you're familiar.)

We currently offer WordPress via an installer script. The user uploads the newest stable release, and runs a server-side PHP script via SSH. This PHP script modifies file permissions of all files/folders, adds/removes some code in various files, and creates a few new files. This installer script is a cumbersome balancing act when a new stable version is released.

I want to start using version control (specifically git) to track our custom changes instead of relying on a script to make the changes, but am unsure of the workflow to use. I'm familiar with branching and merging, but not sure how to integrate our old changes when a new release is issued.

What should my git workflow be to integrate the new changes from the WordPress core, but also preserve our older custom changes?

+2  A: 

My general approach is to have two branches, upstream and master. Create your repository (which will start you in the master branch), check in the latest copy of the upstream code that you use, and then create the upsteram branch with git branch upstream. Also, create a tag indicating which upstream version you have imported, such as git tag wordpress-1.0. I usually use lightweight tags for this (ones without any annotations, just basically a pointer to a revision).

[wordpress-1.0]               Key: [tag]
v                                  branch
* <- upstream                      * commit
^- master 

Now, while you're still in the master branch, copy your changes in and check those in. You now have two branches, upstream which contains the pristine upstream source, and master which contains your changes, with history showing which changes you have made to upstream.

[wordpress-1.0]
v
* <- upstream
 \
  +--* <- master 

Make all of your modifications in the master branch.

[wordpress-1.0]
v
* <- upstream
 \
  +--*--*--* <- master 

When a new version of the upstream code comes along, check out your upstream branch (git checkout upstream), clear out everything but the .git directory, and copy in the new upstream version. Use git add -A to stage all of the changes in the upstream version, commit it, and tag it.

[wordpress-1.0]
|  [wordpress-1.1]
v  v
*--* <- upstream
 \
  +--*--*--* <- master 

Now, check out master, and merge in your upstream changes. At this point, you can choose how to merge, such as taking the new upstream version, taking your version, or taking merged changes, just like you do in a normal merge.

[wordpress-1.0]
|  [wordpress-1.1]
v  v
*--*--------+ <- upstream
 \           \
  +--*--*--*--* <- master 

So, all of your changes happen on master, and all upstream versions are committed exactly as is to upstream. That will let you see most easily exactly how your code differs from the upstream version, it will help keep track of which changes you've already merged with the upstream version, and so on.

[wordpress-1.0]
|  [wordpress-1.1]
|  |           [wordpress-2.0]
v  v           v
*--*--------+--*-+ <- upstream
 \           \    \ 
  +--*--*--*--*----*--* <- master 

Hope this helps, let me know if you have any further questions.

Brian Campbell
This technically works, but it sounds more logical to reapply our changes to the newest source code each time, so rebasing sounds like a better option than merging.
John Kary
+3  A: 

I would suggest keeping your changes in a branch, and rebasing that branch against the latest from WordPress whenever you update. In a rough timeline...

              +-- WordPress 1.0
              v
[master] --*--*
               \
[custom]        *--*--*     <- your customizations

When you want to update WordPress, switch to master and make a new commit with the latest souce (or use git-svn to keep master in sync):

              +-- WordPress 1.0
              |     +-- WordPress 1.1
              v     v
[master] --*--*--*--* 
               \
[custom]        *--*--*     <- your customizations

Now you can do a git rebase master custom to replay your changes against the latest, resolving any conflicts along the way. Your timeline would then look like this:

              +-- WordPress 1.0
              |     +-- WordPress 1.1
              v     v
[master] --*--*--*--* 
                     \
[custom]              *--*--*     <- your customizations

Update: To provide a bit of rationale... I like this approach for this problem because it provides a clear differentiation between code from WordPress and your customizations. When you get a new version of WordPress, you're really not interested in "integration". You're interested in re-applying your customizations to the new version of WordPress. In my view, that recustomization is most easily done commit by commit through a rebase. Any conflicts mean a customization likely broke, so the old customization commit is garbage anyway - better to just fix the problem at its source and keep the updated history clean.

After master is updated and custom is rebased and pushed, the collaborators would just rebase their work-in-progress against the latest.

This is just my opinion, as a firm rebase > merge proponent. The beauty of Git is that there's rarely one right answer. Just keep adjusting until you find something that works for you.

dahlbyk
I would recommend against this, as rebasing can cause lots of problems. It loses history (you can't go back to a version that you actually had deployed earlier, nor can you tell when you did which merges), and having your working branch rebasing all the time makes it a lot harder for you to collaborate with other people, since now they'll also need to be rebasing everything they do. Rebasing is something that's best for changes that haven't been shared with anyone else yet, or that are known to be volatile, not for rebasing your entire history on an upstream every time there's a new release.
Brian Campbell
Rebasing can cause problems if you fail to communicate, but it's totally manageable. History is only lost if you don't keep a reference to the commit - just tag the deployed version and you won't lose anything.
dahlbyk
In our case, rebasing seems like a good solution since we only share the source as a tarball. No other devs using the final product are making changes to the core like we are, so no need to share with others.
John Kary