How to Handle Xml/HTML in Git Feature Branch Workflow

How to handle xml/html in git feature branch workflow?

Git allows for custom merge drivers, selected via gitattributes per path (e.g. for all *.xml files).

What you need to find is a XML-aware merge driver, plus possibly also write a simple script to transform between Git conventions and said merge driver conventions. There is for example XML::Merge Perl module. There is XyDiff, but it looks like it lacks three-way merge (and I guess that for XML building 3-way merge from diffs like described in A Formal Investigation of Diff3 paper (PDF) wouldn't work). You can also read Matching, diffing and merging XML blog post (or article referenced therein).

Another solution would be to unset merge attribute for XML files (they would be treated like binary files wrt. merge conflicts), and use some graphical merge tool to resolve merge conflicts, perhaps via git mergetool.

Can git be made to mostly auto-merge XML order-insensitive files?

This gets pretty hard in general.

Some have attempted to use Git's union merge (which is more accessible now than it was in early days; as in that question, you just add merge=union in a .gitattributes file), but this does not work in general. It might work sometimes. Boiling it down a lot, it works if your XML is always structured so that naive line-oriented union merge produces valid XML (basically, keeping whole XML sub-elements all on one line), and you are always adding whole new XML sub-elements.

It is possible, in Git, to write a custom merge driver. Writing a useful one for XML is hard.

First we need an XML diff engine, such as Sylvain Thénault's xmldiff, to construct two string-to-string (or tree-to-tree) edits for three XML files (the merge base, local or --ours, and other or --theirs files: diff base-vs-local and base-vs-ours). This particular one looks like it works similarly to Python's difflib. (However, due to the referenced papers, it looks like it produces tree move / nesting-level operations as well as simple insert and delete. This is a natural and reasonable thing for a tree-to-tree edit algorithm to do, and probably actually desirable here.)

Then, given two such diffs, we need code to combine them. The union method is to ignore all deletions: simply add all additions to the base version (or, equivalently, add the "other" additions to the "local", or the "local" additions to the "other"). We could also combine tree insert/delete operations a la "real" (non-union-style) merges, and perhaps even declare conflicts. (And it might be nice to allow different handling of tree nesting-level-changes, driven by something vaguely like a DTD.)

These last parts are not, as far as I know anyway, done anywhere. Besides that, the Python xmldiff I linked here is a fairly big chunk of code (I have not read it anywhere near closely, nor attempted to install it, I just downloaded it and skimmed—it implements both a Myers-like algorithm, and the fancier "fast match / edit script" algorithm from the Stanford paper).

Git management with iPhone development

The storyboard files are stored as XML so you're going to run into the same types of issues that XML files have when tracked with git.

Check out this answer for more technical info on using git attributes and custom merge drivers

Storyboard XML is not that hard to read from a human perspective (compared to old XIB files) so if the changes are small and not on the same object it can be trivial to use the merge tool in Xcode to resolve conflicts.

To avoid the conflicting situations as much as possible you could set up your project to use multiple storyboard files to split things up and minimize the chances for conflicting changes to a single large storyboard. Use +storyboardWithName:bundle: to load the storyboards when needed.

Deriving maven artifact version from git branch

Update 2022: Alternative solutions were brought into existence since this answer was written 2012. While the Git-hook-based solution presented here still holds (with its pros and cons), some good answers here present plugin-based or even pure Maven solutions which I recommend to consider.


Indeed, [note 2022: unless some plugins are added to the project], Maven can't change the version of it's own project in one run with other goals. On top of it, raw Maven doesn't support arbitrary properties in the <version> tag. Therefore, a separate execution is required to run a goal which will change the version of the POM. There are various plugins which can do it. For example: versions:set goal from versions plugin - http://mojo.codehaus.org/versions-maven-plugin/set-mojo.html

So, you might execute it as follows:

mvn versions:set -DgenerateBackupPoms=false -DnewVersion=$branch-SNAPSHOT

where the $branch variable has to contain current Git branch name; it can be extracted with git rev-parse, like this:

branch=$(git rev-parse --abbrev-ref HEAD)

But still, one needs to execute it somehow. You can do manually, but it is cumbersome. So, my guess is that indeed the most robust solution would be to approach this from Git side. That is - a Git hook. Here is the complete Git post-checkout hook which will do the job (same code as above with some filtering to run the hook only when the branch is checked out, not the individual files only):

#!/bin/bash

echo 'Will change the version in pom.xml files...'

# check if the checkout was to checkout a branch
if [ $3 != '1' ]
then echo 'git checkout did not checkout a branch - quitting';exit
fi

# get current branch name
branch=$(git rev-parse --abbrev-ref HEAD)
version=$branch-SNAPSHOT

# run maven versions plugin to set new version
mvn versions:set -DgenerateBackupPoms=false -DnewVersion=$version

echo 'Changed version in pom.xml files to $version'

Put this content to the file PROJECTDIR\.git\hooks\post-checkout file. Note that the hook file should be executable to run it (chmod +x post-checkout).

Few notes about versions plugin - it is pretty flexible and supports many options and have few other goals which might be of help, depending on your project structure (do you use parent poms or not, do childs have their own versions or do they derive from parent, etc.). So, the hook above might be modified slightly to support you specific case by using other goals from versions plugin or by specifying additional parameters.

Pros:

  • Robust
  • No need to change anything in the pom.xml files themselves to make this work
  • This "functionality" can be turned off simply by deactivating the hook (remove or make not executable) - again, no changes are required in the pom.xml

Cons:

  • One can't enforce others to use a hook - it should be installed manually after the repo is cloned (or, you can provide a script to install the hook if supposed Git users are afraid of touching the stuff inside .git directory).

More elaborate version of the Bash script for the Git hook:

Hereafter is the more complicated version of the hook, which will not only set the version to the branch name, but will also preserve the suffix of the old version. For example, provided old version master-1.0-SNAPSHOT, switching to feature1 branch will change the version of the project to feature1-1.0-SNAPSHOT. This bash script suffers from few problems (requires branch names without dash symbol (-) in the name, and only takes the version of the root pom), but may give an idea of how the hook may be extended: given a mix of mvn and bash commands you can extract and update quite a lot of the information in the POM.

#!/bin/bash

echo 'Will change the version in pom.xml files...'

# check if the checkout was to checkout a branch
if [ $3 != '1' ]
then echo 'git checkout did not checkout a branch - quitting';exit
fi

# get current branch name
branch=$(git rev-parse --abbrev-ref HEAD)

# get current version of the top level pom
current_version=$(mvn help:evaluate -Dexpression=project.version | grep -v '\[.*')

# extract version suffix
suffix=$(echo $current_version | cut -d \- -f 2)

# build new version
version=$branch-$suffix

# run maven versions plugin to set new version
mvn versions:set -DgenerateBackupPoms=false -DnewVersion=$version

echo 'Changed version in pom.xml files to $version'


Related Topics



Leave a reply



Submit