Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way with Git to make future merges ignore version number difference in a pom file between branches?

My team is planning to switch from Perforce to Git and I am trying to find a way to make Git ignore pom version differences between branches. This works well in Perforce and I'm not having any luck reproducing the behavior with Git.

Here are my steps:

  1. Checkout parent branch

    ndeckard@ws /c/dev/proj/testgit (master)
    $ git checkout release/1.0
    Switched to branch 'release/1.0'
    Your branch is up-to-date with 'origin/release/1.0'.
    
  2. Create child branch from it

    ndeckard@ws /c/dev/proj/testgit (release/1.0)
    $ git branch branch/FEA-650
    
  3. Switch over to new branch

    ndeckard@ws /c/dev/proj/testgit (release/1.0)
    $ git checkout branch/FEA-650
    Switched to branch 'branch/FEA-650'
    
  4. Update child branch pom version

    <version>1.0.0-FEA-650-SNAPSHOT</version>
    
  5. Add it and commit

    ndeckard@ws /c/dev/proj/testgit (branch/FEA-650)
    $ git status
    On branch branch/FEA-650
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
            modified:   pom.xml
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    ndeckard@ws /c/dev/proj/testgit (branch/FEA-650)
    $ git add pom.xml
    
    ndeckard@ws /c/dev/proj/testgit (branch/FEA-650)
    $ git commit -m "set feature branch pom version"
    [branch/FEA-650 59e156e] set feature branch pom version
    1 file changed, 1 insertion(+), 1 deletion(-)
    
  6. Switch back to parent branch

    ndeckard@ws /c/dev/proj/testgit (branch/FEA-650)
    $ git checkout release/1.0
    Switched to branch 'release/1.0'
    Your branch is up-to-date with 'origin/release/1.0'.
    
  7. Merge child branch into parent auto-accepting parent branch version (using the “ours” merge strategy)

    ndeckard@ws /c/dev/proj/testgit (release/1.0)
    $ git merge branch/FEA-650 -s ours
    Merge made by the 'ours' strategy.
    
  8. Attempt 2nd merge of child into parent (Already up-to-date.) Good. This is what I want

    ndeckard@ws /c/dev/proj/testgit (release/1.0)
    $ git merge branch/FEA-650
    Already up-to-date.
    
  9. Checkout child and merge parent into child (it fast forwards and sticks the parent branches pom version on the child). Not good. I need it to say "already up-to-date" like above and keep the child branch pom version as it already is on the child branch

    ndeckard@ws /c/dev/proj/testgit (release/1.0)
    $ git checkout branch/FEA-650
    Switched to branch 'branch/FEA-650'
    
    ndeckard@ws /c/dev/proj/testgit (branch/FEA-650)
    $ git merge release/1.0
    Updating 59e156e..2f3a2a0
    Fast-forward
    pom.xml | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
    

After step 7, I would like merges in either direction between parent and child to say (Already up-to-date.)

Is there a way with Git to make future merges ignore the version number difference in the pom file between branches?

like image 570
Nathan James Deckard Avatar asked May 22 '15 23:05

Nathan James Deckard


People also ask

What is the safest and fastest way to combine commits from two different branches?

The git merge command integrates the independent lines of development into a single branch. The command is used to combine two branches and also to merge multiple commits into one history. Once you make changes in the local repository and ready to share it with your team members, then execute git push.

Does git merge affect both branches?

No, merging does only affect one branch.

What git strategies are used to merge two branches?

Recursive. This operates on two heads. Recursive is the default merge strategy when pulling or merging one branch. Additionally this can detect and handle merges involving renames, but currently cannot make use of detected copies.


1 Answers

My initial thought is to automate your POM version numbers by partly externalizing the POM <version> computation, see further down in the answer. If you don't want to do that, then you need to re-evaluate your Git workflow.

Merging two-ways, into master and then back into the feature branch causes problems. Your git merge branch/FEA-650 -s ours using the ours strategy tells Git that you have integrated all commits and changes from the feature branch into master, including your pom.xml version change, which is lost, with master retaining its version. The master branch now considers the feature branch's HEAD to be a common ancestor (it's a parent commit on the merge), so when you merge it back into the feature branch, Git says "everything was resolved when you merged to master, there are no changes ... fast-forward".

The simple answer is that you should re-branch to a new feature branch after merging to master, giving your feature branch a new/later youngest common ancestor, then you need to somehow replay your POM <version> change. You should not continue to work on the original feature branch, since it has been merged. To pick up new changes from master you should re-branch. There seems to be some implication that you may have left changes on the feature-branch unmerged with master, otherwise you wouldn't need it anymore and could re-branch, or it might just be the <version> change commit you are interested in.

There's any number of ways to simplify/speed-up/automate the version-number management on re-branching, from externalizing (see below) to cherry-picking it from a placeholder branch, using a Maven plugin e.g. Versions Maven Plugin .

Original answer

Another approach would be to externally calculate the final/effective <version> outside your POM file, based on branch metadata or other input from your CI. This is slightly tricky to do in Maven without pre-munging pom.xml yourself after checkout, but take a look at the Maven External Version Plugin.

It hooks into the Maven lifecycle and will build a pom.xml.new-version file on the fly (which you can .gitignore), dynamically-replacing all or part of the version number, based on whatever you supply - a feature-branch name, git commit hash etc.

Build/deploy the plugin and add it to your POM:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-external-version-plugin</artifactId>
    <version>0.1.0-SNAPSHOT</version>
    <extensions>true</extensions>
    <configuration>
        <strategy hint="sysprop"/>
    </configuration>
</plugin>

... then get creative with replacing the version-string, for example you can:

mvn install -Dexternal.version-qualifier=$(git symbolic-ref --short HEAD| sed s_^master\$__)

... which will change 1.2.3-SNAPSHOT to 1.2.3-FEA-650-SNAPSHOT if the current checked-out Git branch is FEA-650. You might need to consider replacing / with - in your branch-naming strategy, depending on what Maven thinks of it (I find the /s confusing, but that's just me), or modify the sed accordingly.

At worst this would allow you to remove your version-number from of your POM, so other POM changes can be safely merged and known to be non-version-number related - if necessary you can keep version numbers in another file, using a Maven Properties Plugin to load them and replace the entire version number if required.

like image 137
javabrett Avatar answered Oct 26 '22 12:10

javabrett