4
votes

I am working on Zend Framework 2 project with Doctrine 2 dependency. Source versioning is handle by GIT. We are using GitFlow as a branching model.

The problematic situation:

Migrations on Develop branch:
001.php
002.php
003.php
004.php

Migrations on Production branch:
001.php
002.php

Let's say I need to patch and I create migration 003.php on Production branch. I also have to cherry-pick the 003.php change to Develop branch that the final result would look like this:

Migrations on Develop branch:
001.php
002.php
*003.php*
003.php
004.php

Migrations on Production branch:
001.php
002.php
*003.php*

But here is the problem. If the current migration on Develop database was 004 and 003 was added so it will not be executed.

What is the best way to handle Doctrine 2 migrations?

2
Migrations should be named with a timestamp, right down to the second. Of course, if both branches are creating migrations that touch the same db table/fields, then you may still have a conflict. Best advice is go with timestamps and a careful code review.Petar Zivkovic

2 Answers

2
votes

I am also working on a project using ZF2, Doctrine 2 and Migrations, as well as Gitflow as a branching model. So, we have the same problem with the migrations located in different branches. When this problem occurs, I handle it manually using doctrine migration tool to synchronize the migration versions:

$php public/index.php migrations:version 20150417121714 --add
$php public/index.php migrations:version 20150417202439 --remove

And then:

$php public/index.php migrations:execute 20150417121714

This solution requires some manual work but unfortunately I don't have better so far.

1
votes

I wrote a script to automate the process of migrating back all the diverging migrations in the current branch and migrating back up to the new branch you are checking out.

The above link is for Symfony, but here it is modified for ZF2 (untested as I don't use ZF2):

doctrine-checkout.sh

#!/bin/bash

# Commit ref of current HEAD
start_commit="$(git rev-parse HEAD)"

# Commit ref of what is to be checked out
dest_commit="$1"

# First common ancestor commit between the two branches
ancestor="$(git merge-base HEAD "$dest_commit")"

# Shorthand for `sudo -u nginx /home/user/project/public/index.php`
# Modify this if you don't run `php public/index.php` as `nginx`
appconsole="sudo -u nginx php $(git rev-parse --show-toplevel)/public/index.php"

# Checkout the ancestor commit to find the first common migration between the
# two branches.  Migrate backwards to this version.
git checkout "$ancestor"
ancestor_migration="$($appconsole migrations:latest)"
git checkout "$start_commit"
$appconsole migrations:migrate "$ancestor_migration"

# Checkout the destination branch and migrate back up

git checkout "$dest_commit"
$appconsole migrations:migrate

To use this, when you need to switch between feature branches, instead of running git checkout another-branch, do doctrine-checkout.sh another-branch.

If you rebase your branches so they contain commits with migrations which were previously in another branch, this will cause difficulties checking out that branch again from another branch, since it may have more recently dated migrations some commits behind the migrations the branch adds. You can git rebase -i within your feature branch and edit the commit which adds a migration to rename the migration if this is the case.