Working on a project, making heavy use of Features, there is sometimes 3 devs for this application.

We have tried a few approaches, but when we merge our git branches it seems we often 'over-write' each other's feature changes. Conflicts abound, breaking the feature module making it painful to use, it seems.

Features is really an awesome timesaver for configuration for one on projects, and I am quite sure there is a way to tackle this.

Is there a workflow or procedure that reduces risks of conflicts and overwrites?

Any clues on features is welcome.

up vote 20 down vote accepted
+100

Welcome to the land of Features Configuration Management, aka FCM! It is not only about Features, and not about Configuration Management (as introduced in Drupal version 8). Instead, it is a special case of Software Configuration Management, aka SCM. Mostly because Features can be considered as a code generator, whereas that generated code needs to be migrated through multiple environments. Read on for more details.

1 - Pros and cons of using Features

Advantages of using Features

  • Automate the deployment of changes applied to a Drupal development site to one or more target Drupal (pre-) production sites (instead of manual deployment).
  • Facilitates sharing (shipping) of ongoing Drupal development between Drupal developers / site builders (eg to make some View(s) created by a views expert available to a Drupal Themer working in another development site to theme that view).
  • Great integration with both GIT and Drush for shipping a copy of the code generated by Features (on the development site) to selected target (pre-) production sites.

Disadvantages of using Features

  • Avoiding Feature Conflicts and/or managing Feature Dependencies can be challenging!
  • It's not easy to start using Features on an existing (production) site.
  • Install/enable of the Features module is easy (just a module), but to learn to use Features correctly is a major challenge.

2 - Techniques for features packaging

Using Features it is up to your own imagination how to package (compose) the content of a feature. Here are some techniques that can be used for it.

A single super feature

This is a pretty simple packaging technique: everything is packaged together in a single feature (some call it the "God" feature ...). Seems easy, pretty forward, etc. But this technique also leads to "conflicts" (as explained below) more or less right away ...

A good usecase for this appears to be when creating a "Drupal distribution", where all users of it are assumed to use the same set of modules, configuration, etc. If however such distribution consists of multiple website functionalities (to not use the word "features" ...), it seems more appropriate to split such features in multiple features, as explained below.

Based on website functionality

This packaging technique creates a separated feature for each functionality of a website, such as:

  • Feature A = implement a "*Gallery".
  • Feature B = implementg a "*Blog".
  • Feature C = implement a "*Event Calendar".

Based on Drupal admin sections

This packaging technique creates separated features for each of the (major) admin sections of a Drupal website that is used to create the site, such as:

  • All required modules are contained in feature A,
  • All base field definitions are contained in feature B,
  • All content types are contained in feature C,
  • All permissions are contained in feature D,
  • All roles are contained in feature E,
  • All variables are contained in feature F,
  • All (custom) Views are contained in feature G,
  • All (custom) Rules are contained in feature H,
  • Etc.

The above list is virtually unlimited: in the end you could even think of it as 1 feature for each Drupal admin menu option ... if you want to go that far.

IMO it is also the most recommended approach to package features.

3 - Reducing the probability of conflicts in Features and/or GIT

Do not reuse fields

Quite a few conflicts seem to be caused by reusing fields among multiple content types. E.g. in content type A you have a field with machine name field_somefield, which is also used as field in content type B with the very same machine name field_somefield but which as another field type and/or some other field setting(s) that are different.

By not reusing fields among content types, you avoid running in this issue. Have a look at an interesting naming convention for the machine name of your content types and fields as shown in table of Wrapping Information Architecture and Documentation, which is part of the articles about "Relativity Model for Drupal". For more details on that refer to my answer to "How do I model content (types) from a database-centric point of view?".

Split features depending on who works on what

If multiple people are working on a single site, the amount of conflicts can be reduced by organizing (= creating separate) features based on who is working on what. An illustration of this could be as in this example:

  • Views goes in feature A,
  • Rules goes in feature B,
  • Charts goes in feature C,
  • Anything about Theming goes in feature D,

4 - Recommended Drupal environments

Everything above should help to somehow facilitate the usage of Features. However, to ensure that things will work as expected (designed), you also need to have an appropriate set of environments (logically related Drupal websites) for basically these reasons:

  • merge functionality provided by multiple features.
  • predict and resolve conflicts.
  • end-user testing of all merged features that are certified to not have any conflicts.

In the ideal world, these logically related Drupal websites should be configured, and used, like so:

  1. Personal Dev Site - each website developer has a separated dev site. When some part of the development is ready to be shared with somebody else, an appropriate feature is created, which is shipped to the staging environment.
  2. Sandbox Site - this is a Drupal environment which only contains Drupal core, used to unit test the completeness of a single feature. Should a feature, accidentally, have some unexpected dependencies (eg some module the feature depends on, which is not enabled in the Sandbox), then this is where that dependency will become clear.
  3. Staging Site - here is where one or more features (created in a dev site) are delivered to. It could be just some hotfix for some production problem, or it could be where all development for a new release of the website is consolidated. If any conflicts between multiple features do exist, then this is the environment where they will first show up ... and need to be resolved somehow.
  4. QA Site - after the Staging environment is considered stable, it's time to move on with the relevant features and make them available also at some higher level where they can be used for QA testing, acceptance testing, volume testing, etc. At this level you should be extremely careful in allowing any additional changes (if any). Because any such change may invalidate all prior testing efforts already completed in this environment.
  5. Shadow Production Site - To prepare the activation in real production, you might want to first further promote the relevant features to an environment that is considered a copy (shadow) of your real production environment. If at this point during the migration process anything still breaks, then that is a red flag to revert some of your prior steps. Get it fixed, and try again, until all parties involved approve the changes.
  6. Production Site(s) - If you completed all prior steps, then this step should be self explaining, and pretty easy. Depending on your needs, this could be a single site, or something equivalent to Drupal's Multi-sites whereas all the sites involved are running the very same versions of all features.
  7. Baseline Site - In my experience, there are not many (if any at all) Drupal implementations where this type of site is used (also). It is simply a copy of the Production Site(s), but available to the Drupal developers, testers, etc that can be used to verify what the production sites look like, or to perform user training, etc. And any time a new development cycle is started, the components of a site that will be impacted (need to be changed) should be "copied somehow" using this Baseline Site as input, with as target a Personal Development Site.

Obviously, the above inventory of types of Drupal sites is like the ideal world. Depending on the size of your development team, and / or the available budgets to create and maintain them, not all of them may be used (or affordable). This inventory is modelled after best practises in the area of SCM, used in mostly all huge/global corporations (banks, airlines, etc).

5 - Related modules

Strongarm

The Strongarm module allows for exporting variables (of modules which store their settings in variables) with the Features module.

Node Export

The Node export module allows users to export nodes and then import it into another Drupal installation.

Role Export

The Role Export module allows roles to have machine_names and generates a unique role id (rid) based off of the machine_name. Roles can be exported with Features and get the exact same rid if imported on other sites.

Features Banish

The Features Banish module allows for completely excluding individual features components from the features UI and features exports. Here is a quote about it from its project page:

 This module is useful when there are features components that you want to make sure NEVER get exported. If you are using features for site building or deployment then you've probably ran into the issue of someone accidentally exporting timestamp variables like cron_last or update_last_check. You may also want to banish permissions for developer modules so they don't get caught up with the rest of the site permissions you want to export. Banished items will not show up in your feature module OR ANY OTHER FEATURES MODULE, so use with caution. For a central list of features that should never be exported, see https://www.drupal.org/node/2400531

BEAN

The Bean module makes your blocks exportable. Here is a quote about it from its project page:

Think of a Bean as a method to provide new types (compared to node this would be a content type) which then provides an add content interface to create as many blocks as you require (see screenshot below). The bean content can then be placed around the site just like any other block.

This module also works great in combination with the UUID and UUID Features Integration modules. This module only started as of D7, but it has been included with Drupal 8 core already. The video tutorial Drupal Bean module tutorial - using Bean Admin UI provides a great introduction to really understand the power of this module, and the kind of things you can do with it (by only using site building techniques, no custom coding involved).

Habitat

The Habitat module makes most sense in a Features-based workflow. Here is a quote about it from its project page:

In a multi-environment setup (e.g. prod, test, dev, local) there are some modules that you'd like to always be enabled or disabled on certain environments. Each time you sync a database down though you have to re-enable/disable the same modules. Worse, you get lazy and keep development modules enabled on production.

Habitat provides settings to enable or disable certain modules on each environment (habitat). Just set a variable with e.g. $conf['habitat'] = 'local'; in your settings.php file (the actual variable to use there is configurable for your current workflow). The disabling/enabling modules is done on hook_init.

6 - Recommended resources:

7 - Possible alternatives to using Features

If you're not able, or willing (yet), to use Features, then you may want to check to what extend the approaches/modules below may provide some type of alternative.

Manual Export/Import

These are the commonly known facilities (to avoid the word features ...) available via the admin UI, for modules such as Rules, Views, etc (incomplete list!).

Bundle copy

Some people consider the Bundle copy module as a possible alternative. It has export/import support for:

  • Node types.
  • Taxonomy.
  • User.
  • Field API fields.
  • Field groups.
  • 1
    Best answer I've ever seen. – No Sssweat May 6 '16 at 5:35
  • @NoSssweat Merci for the kudos ... but know that I consider it as still pretty incomplete. E.g. it hardly includes anything about the "lifecycle" of processing features, and it doesn't say a lot yet about things like impact analysis, auditing, release management, authorizations, and, and, and (another dozen of topics or so). – Pierre.Vriens May 6 '16 at 5:52
  • 1
    @Pierre.Vriens - Thanks! I guess I came to the same conclusion as your excellent answer the hard way. I had tried the approach of splitting by components ( views_views, dependency, etc. ) but was having conflicts when trying to generate the feature. I realized -> after -> that I probably needed to configure the feature to not check dependencies and ignore conflicts. – stefgosselin May 6 '16 at 17:19

Merge conflicts are probably going to be a given when multiple developers are integrating their configuration into a Feature. I wrote up several guidelines for reviewing feature code, but I think the most important is this:

Only commit intended code changes.

What does this mean? This means that each developer must review code before committing. There is no "magic" to prevent unintended code changes without a developer being cautious.

  • Review code changes with git diff.
  • Make a quick diff patch using git diff > blah.patch, and manually modify the patch to only include the intended configuration changes.
    • Things such as "mtime", comments in view exports in the info file need not be included in the commit.
    • I've become quite adept at reviewing blocks of configuration code diffs over time. It is easier now to spot superfluous changes in views or panels, and a quick 10dd in vim gets rid of the change in a patch (for example).
    • I think "Oh, hey, I didn't change anything to do with fields, so I won't commit featurename.features.field_base.inc."
  • Never ever use git commit -a. This is a terrible practice that should be stricken from use. Always add and commit explicitly!
  • Use git rebase on local git branches to make sure the feature is most up-to-date.
  • A git merge strategy may also help when actually doing a merge:
    • git merge -s recursive -X patience (requires git 1.7+ iirc).

Finally consider adding social restrictions to developers so that a developer must have their code reviewed before merging into trunk/stable either with patch review or pull request. People will be angry about social restrictions, but they should be angry at themselves for not reviewing their code.

  • Better than generating a patch file is using git add -p to commit specific chunks only. – donquixote Nov 8 at 14:12

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.