= Development Workflow for Trac The public branches listed in TracDownload#LatestDevelopmentSourceCode should remain bug free and always usable from an end-user perspective, as we support installing directly from the branches. To achieve this, we follow the practices listed below. == Initial code review Except for trivial fixes, it's usually a good idea to start with a patch or an experimental branch, to provide some visibility of the changes to the other contributors. A patch is always attached to a ticket. If there is no ticket, then create one and attach the patch to it. When there are many iterations or spin-off changes needed, it's a good idea to start a branch, either in the svn [source:sandbox] for those who have the commit permission or inside an external DVCS repository, by forking our Mercurial or Git mirrors (see TracRepositories). == Integration in release branches We commit bug fixes first on one of the stable branches, eg [source:branches/0.12-stable], then merge the fix to later branches using svn's mergeinfo support. Merging in this direction (//porting// or //forward porting//) makes it quite easy to merge all pending changes from one stable branch to the next, eg [source:branches/0.12-stable 0.12-stable] to [source:branches/1.0-stable 1.0-stable], then to [source:trunk]. This workflow is much simpler than the opposite one, //back porting//, which involves cherry-picking or careful "blocking" of changes which shouldn't be merged back. The SCM tools have generally better support for merging in this forward direction, even Subversion since v1.5. Here's a walk through example. We start by hacking on [source:branches/0.12-stable 0.12-stable]: {{{#!sh 0.12-stable$ ed trac/attachment.py # or your other favorite editor 0.12-stable$ make test ... (all is good) 0.12-stable$ svn ci -m "0.12.6dev: fixed ... (#xyz)" }}} Now we want to port all the pending changes to [source:branches/1.0-stable]: {{{#!sh 0.12-stable$ cd ../1.0-stable 1.0-stable$ svn merge ^/branches/0.12-stable 1.0-stable$ make test ... xxx 1.0-stable$ # some fixes needed for API changes 1.0-stable$ svn ci -m "1.0.2dev: Merged from 0.12-stable." }}} Now we want to port all the pending changes to [source:trunk]: {{{#!sh 1.0-stable$ cd ../trunk trunk$ svn merge ^/branches/1.0-stable trunk$ make test ... xxx trunk$ # some fixes needed for API changes trunk$ svn ci -m "1.1.2dev: Merged from 1.0-stable." }}} Among the possible porting related fixes that should be done when porting: - Use Python idioms adapted to the minimal version on the branch, eg for Trac 0.12 the baseline is Python 2.4, for Trac 1.0 and trunk it's 2.5; this means that among other things we can use `with ...` as appropriate. - Use newer APIs and conventions, eg the DatabaseApi#Trac0.13API; see the ApiChanges subpage for the corresponding target branch. '''Note''': you can always review what are the pending changes in Trac by looking at the `svn:mergeinfo` property which shows the '''eligible''' set of changesets, when viewing the target branch in the TracBrowser, eg [source:trunk]. == Pushing from a DVCS to SVN If the changes were staged in a Git or Hg repository, some additional steps are needed to commit the changes to Subversion. The steps will be described for a Git repository, but will be similar for an Hg repository. You should first interactively rebase (`git rebase -i`) your changes to get them in a form that is appropriate for committing to the Subversion repository. In doing so, consider how you'd like the changes to be represented in the repository history, taking into account that we frequently interrogate the repository history to discover the cause of regressions or understand the purpose and intent of code. For example, logically related changesets may be squashed if they were staged as multiple changesets to ease the process of codereview. However, unrelated changes and refactorings should be pushed as separate changesets, so they don't obfuscate other changesets. Next, reword your log messages in a form that is appropriate for committing to the Subversion repository, prefixing each log message with the target version (e.g. `1.0.10dev:`), and referencing the appropriate ticket(s). See the [/log log] for examples. Once you've interactively rebased your Git branch and prepared your log messages, the process to push changes to Subversion is: * Checkout an svn working copy of the branch you'll be committing to * Rebase your staging branch against the HEAD of the branch you'll be committing to * Copy the svn metadata directory (`.svn`) of the working copy into the root of your git repository * Step through checkouts of your repository changesets and push each of them into Subversion Here are the same steps described in command line form: {{{#!sh $ svn checkout trac-svn-wc $ cp -r trac-svn-wc/.svn trac-git-repos/ $ cd trac-git-repos $ git status -sb ## tXYZ $ git checkout tXYZ~3 $ git log --format="%B" > commit.txt $ svn add ...; svn del ... $ svn ci -F commit.txt $ git checkout tXYZ~2 ... $ git checkout tXYZ~1 ... $ git checkout tXYZ ... }}}