Skip to content

Pick better merge base #1225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions BREAKING CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ v4.0.0
- The default keys are: master, develop, feature, release, pull-request, hotfix, support
- Just run GitVersion.exe in your project directory and it will tell you what to change your config keys to
- For example, `dev(elop)?(ment)?$` is now just `develop`, we suggest not overring regex's unless you really want to use a different convention.
- source-branches added as a configuration option for branches, it helps GitVersion pick the correct source branch

v3.0.0
- NextVersion.txt has been deprecated, only GitVersionConfig.yaml is supported
Expand Down
64 changes: 64 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,70 @@ values, but here they are if you need to:
### regex
This is the regex which is used to match the current branch to the correct branch configuration.

### source-branches
Because git commits only refer to parent commits (not branches) GitVersion sometimes cannot tell which branch the current branch was branched from.

Take this commit graph

```
* release/1.0.0 * feature/foo
| ________________/
|/
*
*
* (master)
```

By looking at this graph, you cannot tell which of these scenarios happened:

1. feature/foo branches off release/1.0.0
- Branch release/1.0.0 from master
- Branch feature/foo from release/1.0.0
- Add a commit to both release/1.0.0 and feature/foo
- release/1.0.0 is the base for feature/foo

2. release/1.0.0 branches off feature/foo
- Branch feature/foo from master
- Branch release/1.0.0 from feature/foo
- Add a commit to both release/1.0.0 and feature/foo
- feature/foo is the base for release/1.0.0

Or put more simply, you cannot tell which branch was created first, `release/1.0.0` or `feature/foo`.

To resolve this issue, we give GitVersion a hint about our branching workflows by telling it what types of branches a branch can be created from. For example, feature branches are, by default, configured to have the following source branches:

`source-branches: ['master', 'develop', 'feature', 'hotfix', 'support']`

This means that we will never bother to evaluate pull request branches as merge base options and being explicit in this way also improves the performance of GitVersion.

### is-source-branch-for
The reverse of `source-branches`. This property was introduced to keep it easy to extend GitVersion's config.

It exists to make it easier to extend GitVersion's configuration. If only `source-branches` exists and you add a new branch type, for instance `unstable/`, you then need to re-define the `source-branches` configuration value for existing branches (like feature/) to now include the new unstable branch.

A complete example:

```
branches:
unstable:
regex: ...
is-source-branch-for: ['master', 'develop', 'feature', 'hotfix', 'support']
```

Without this configuration value you would have to do:


```
branches:
unstable:
regex: ...
feature:
source-branches: ['unstable', 'develop', 'feature', 'hotfix', 'support']
release:
source-branches: ['unstable', 'develop']
etc...
```

### branches
The header for all the individual branch configuration.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,27 @@ build-metadata-padding: 4
commits-since-version-source-padding: 4
commit-message-incrementing: Enabled
branches:
develop:
mode: ContinuousDeployment
tag: alpha
increment: Minor
prevent-increment-of-merged-branch-version: false
track-merge-target: true
regex: dev(elop)?(ment)?$
source-branches: []
tracks-release-branches: true
is-release-branch: false
is-mainline: false
master:
mode: ContinuousDelivery
tag: ''
increment: Patch
prevent-increment-of-merged-branch-version: true
track-merge-target: false
regex: master
source-branches:
- develop
- release
tracks-release-branches: false
is-release-branch: false
is-mainline: true
Expand All @@ -29,6 +43,11 @@ branches:
prevent-increment-of-merged-branch-version: true
track-merge-target: false
regex: releases?[/-]
source-branches:
- develop
- master
- support
- release
tracks-release-branches: false
is-release-branch: true
is-mainline: false
Expand All @@ -39,6 +58,13 @@ branches:
prevent-increment-of-merged-branch-version: false
track-merge-target: false
regex: features?[/-]
source-branches:
- develop
- master
- release
- feature
- support
- hotfix
tracks-release-branches: false
is-release-branch: false
is-mainline: false
Expand All @@ -50,6 +76,13 @@ branches:
tag-number-pattern: '[/-](?<number>\d+)'
track-merge-target: false
regex: (pull|pull\-requests|pr)[/-]
source-branches:
- develop
- master
- release
- feature
- support
- hotfix
tracks-release-branches: false
is-release-branch: false
is-mainline: false
Expand All @@ -60,6 +93,10 @@ branches:
prevent-increment-of-merged-branch-version: false
track-merge-target: false
regex: hotfix(es)?[/-]
source-branches:
- develop
- master
- support
tracks-release-branches: false
is-release-branch: false
is-mainline: false
Expand All @@ -70,18 +107,10 @@ branches:
prevent-increment-of-merged-branch-version: true
track-merge-target: false
regex: support[/-]
source-branches:
- master
tracks-release-branches: false
is-release-branch: false
is-mainline: true
develop:
mode: ContinuousDeployment
tag: alpha
increment: Minor
prevent-increment-of-merged-branch-version: false
track-merge-target: true
regex: dev(elop)?(ment)?$
tracks-release-branches: true
is-release-branch: false
is-mainline: false
ignore:
sha: []
21 changes: 19 additions & 2 deletions src/GitVersionCore.Tests/ConfigProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,12 @@ public void RegexIsRequired()
tag: bugfix";
SetupConfigFileContent(text);
var ex = Should.Throw<GitVersionConfigurationException>(() => ConfigurationProvider.Provide(repoPath, fileSystem));
ex.Message.ShouldBe("Branch configuration 'bug' is missing required configuration 'regex'");
ex.Message.ShouldBe("Branch configuration 'bug' is missing required configuration 'regex'\n\n" +
"See http://gitversion.readthedocs.io/en/latest/configuration/ for more info");
}

[Test]
public void CanProvideConfigForNewBranch()
public void SourceBranchIsRequired()
{
const string text = @"
next-version: 2.0.0
Expand All @@ -113,6 +114,22 @@ public void CanProvideConfigForNewBranch()
regex: 'bug[/-]'
tag: bugfix";
SetupConfigFileContent(text);
var ex = Should.Throw<GitVersionConfigurationException>(() => ConfigurationProvider.Provide(repoPath, fileSystem));
ex.Message.ShouldBe("Branch configuration 'bug' is missing required configuration 'source-branches'\n\n" +
"See http://gitversion.readthedocs.io/en/latest/configuration/ for more info");
}

[Test]
public void CanProvideConfigForNewBranch()
{
const string text = @"
next-version: 2.0.0
branches:
bug:
regex: 'bug[/-]'
tag: bugfix
source-branches: []";
SetupConfigFileContent(text);
var config = ConfigurationProvider.Provide(repoPath, fileSystem);

config.Branches["bug"].Regex.ShouldBe("bug[/-]");
Expand Down
12 changes: 6 additions & 6 deletions src/GitVersionCore.Tests/GitRepoMetadataProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ public void FindsCorrectMergeBaseForForwardMerge()

var develop = fixture.Repository.FindBranch("develop");
var release = fixture.Repository.FindBranch("release-2.0.0");
var releaseBranchMergeBase = new GitRepoMetadataProvider(fixture.Repository)
var releaseBranchMergeBase = new GitRepoMetadataProvider(fixture.Repository, new Config())
.FindMergeBase(release, develop);

var developMergeBase = new GitRepoMetadataProvider(fixture.Repository)
var developMergeBase = new GitRepoMetadataProvider(fixture.Repository, new Config())
.FindMergeBase(develop, release);

fixture.Repository.DumpGraph(Console.WriteLine);
Expand Down Expand Up @@ -109,10 +109,10 @@ public void FindsCorrectMergeBaseForForwardMergeMovesOn()

var develop = fixture.Repository.FindBranch("develop");
var release = fixture.Repository.FindBranch("release-2.0.0");
var releaseBranchMergeBase = new GitRepoMetadataProvider(fixture.Repository)
var releaseBranchMergeBase = new GitRepoMetadataProvider(fixture.Repository, new Config())
.FindMergeBase(release, develop);

var developMergeBase = new GitRepoMetadataProvider(fixture.Repository)
var developMergeBase = new GitRepoMetadataProvider(fixture.Repository, new Config())
.FindMergeBase(develop, release);

fixture.Repository.DumpGraph(Console.WriteLine);
Expand Down Expand Up @@ -184,10 +184,10 @@ public void FindsCorrectMergeBaseForMultipleForwardMerges()

var develop = fixture.Repository.FindBranch("develop");
var release = fixture.Repository.FindBranch("release-2.0.0");
var releaseBranchMergeBase = new GitRepoMetadataProvider(fixture.Repository)
var releaseBranchMergeBase = new GitRepoMetadataProvider(fixture.Repository, new Config())
.FindMergeBase(release, develop);

var developMergeBase = new GitRepoMetadataProvider(fixture.Repository)
var developMergeBase = new GitRepoMetadataProvider(fixture.Repository, new Config())
.FindMergeBase(develop, release);

fixture.Repository.DumpGraph(Console.WriteLine);
Expand Down
5 changes: 3 additions & 2 deletions src/GitVersionCore.Tests/GitVersionContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using LibGit2Sharp;
using NUnit.Framework;
using Shouldly;
using System.Collections.Generic;

public class GitVersionContextTests
{
Expand Down Expand Up @@ -98,8 +99,8 @@ public void UsesFirstBranchConfigWhenMultipleMatch()
VersioningMode = VersioningMode.ContinuousDelivery,
Branches =
{
{ "release/latest", new BranchConfig { Increment = IncrementStrategy.None, Regex = "release/latest" } },
{ "release", new BranchConfig { Increment = IncrementStrategy.Patch, Regex = "releases?[/-]" } }
{ "release/latest", new BranchConfig { Increment = IncrementStrategy.None, Regex = "release/latest", SourceBranches = new List<string>() } },
{ "release", new BranchConfig { Increment = IncrementStrategy.Patch, Regex = "releases?[/-]", SourceBranches = new List<string>() } }
}
}.ApplyDefaults();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using GitVersionCore.Tests;
using LibGit2Sharp;
using NUnit.Framework;
using System.Collections.Generic;

[TestFixture]
public class DevelopScenarios
Expand Down Expand Up @@ -64,7 +65,8 @@ public void CanChangeDevelopTagViaConfig()
{
"develop", new BranchConfig
{
Tag = "alpha"
Tag = "alpha",
SourceBranches = new List<string>()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ public void BranchCreatedAfterFastForwardMergeShouldInheritCorrectly()
{
Branches =
{
{ "unstable", new BranchConfig { Increment = IncrementStrategy.Minor, Regex = "unstable"} }
{
"unstable",
new BranchConfig
{
Increment = IncrementStrategy.Minor,
Regex = "unstable",
SourceBranches = new List<string>(),
IsSourceBranchFor = new [] { "feature" }
}
}
}
};

Expand Down
4 changes: 3 additions & 1 deletion src/GitVersionCore.Tests/IntegrationTests/OtherScenarios.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using GitVersion;
using LibGit2Sharp;
using NUnit.Framework;
using System.Collections.Generic;

[TestFixture]
public class OtherScenarios
Expand Down Expand Up @@ -56,7 +57,8 @@ public void AllowHavingMainInsteadOfMaster()
Tag = "useBranchName",
Increment = IncrementStrategy.Patch,
PreventIncrementOfMergedBranchVersion = true,
TrackMergeTarget = false
TrackMergeTarget = false,
SourceBranches = new List<string>()
});

using (var fixture = new EmptyRepositoryFixture())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ public void CommitOnDevelop_AfterReleaseBranchMergeToDevelop_ShouldNotResetCount
fixture.AssertFullSemver(config, "2.0.0-beta.5");
}
}

public void ReleaseBranchShouldUseBranchNameVersionDespiteBumpInPreviousCommit()
{
using (var fixture = new EmptyRepositoryFixture())
Expand Down Expand Up @@ -463,4 +463,53 @@ public void ReleaseBranchedAtCommitWithSemverMessageShouldUseBranchNameVersion()
fixture.AssertFullSemver("2.0.0-beta.1+1");
}
}

[Test]
public void FeatureFromReleaseBranch_ShouldNotResetCount()
{
var config = new Config
{
VersioningMode = VersioningMode.ContinuousDeployment
};

using (var fixture = new EmptyRepositoryFixture())
{
fixture.Repository.MakeACommit("initial");
fixture.Repository.CreateBranch("develop");
Commands.Checkout(fixture.Repository, "develop");
fixture.Repository.CreateBranch("release-2.0.0");
Commands.Checkout(fixture.Repository, "release-2.0.0");
fixture.AssertFullSemver(config, "2.0.0-beta.0");

// Make some commits on release
fixture.Repository.MakeCommits(10);
fixture.AssertFullSemver(config, "2.0.0-beta.10");

// Create feature from release
fixture.BranchTo("feature/xxx");
fixture.Repository.MakeACommit("feature 1");
fixture.Repository.MakeACommit("feature 2");

// Check version on release
Commands.Checkout(fixture.Repository, "release-2.0.0");
fixture.AssertFullSemver(config, "2.0.0-beta.10");
fixture.Repository.MakeACommit("release 11");
fixture.AssertFullSemver(config, "2.0.0-beta.11");

// Make new commit on feature
Commands.Checkout(fixture.Repository, "feature/xxx");
fixture.Repository.MakeACommit("feature 3");

// Checkout to release (no new commits)
Commands.Checkout(fixture.Repository, "release-2.0.0");
fixture.AssertFullSemver(config, "2.0.0-beta.11");

// Merge feature to release
fixture.Repository.MergeNoFF("feature/xxx", Generate.SignatureNow());
fixture.AssertFullSemver(config, "2.0.0-beta.15");

fixture.Repository.MakeACommit("release 13 - after feature merge");
fixture.AssertFullSemver(config, "2.0.0-beta.16");
}
}
}
Loading