diff --git a/config/release-it.json b/config/release-it.json index 7f381a0b..e7fbfe2f 100644 --- a/config/release-it.json +++ b/config/release-it.json @@ -16,6 +16,7 @@ "tagExclude": null, "tagName": null, "tagMatch": null, + "getLatestTagFromAllRefs": false, "tagAnnotation": "Release ${version}", "tagArgs": [], "push": true, diff --git a/docs/assets/git-version-from-all-refs.svg b/docs/assets/git-version-from-all-refs.svg new file mode 100644 index 00000000..6ed00908 --- /dev/null +++ b/docs/assets/git-version-from-all-refs.svg @@ -0,0 +1,4 @@ + + + +
feature/example
feature/example
Your feature branch
Your feature branch
main
main
develop
develop
The main branch
The main branch
The development branch
The development branch
Tag: v1.0.0
Tag: v1.0.0
v1.1.0
v1.1.0
v1.1.0-rc1
v1.1.0-rc1
v1.2.0-rc1
v1.2.0-rc1
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/git.md b/docs/git.md index 477d4845..c5fd3d14 100644 --- a/docs/git.md +++ b/docs/git.md @@ -58,12 +58,14 @@ Example: `git.tagMatch: "[0-9][0-9].[0-1][0-9].[0-9]*"` ## Tag Exclude -Use `git.tagExclude` to override the normal behavior to find the latest tag. For example whendoing a major release and +Use `git.tagExclude` to override the normal behavior to find the latest tag. For example when doing a major release and you want to exclude any sort of pre-releases, use `*[-]*`, as this would exclude everything with a hyphen, which is normally used exclusively in pre-releases. Example: `git.tagExclude: *[-]*` +:bulb: N.b. `git.tagExclude` has no effect when `git.getLatestTagFromAllRefs: true` (see '[use all refs to determine latest tag](#use-all-refs-to-determine-latest-tag)'). + ## Extra arguments In case extra arguments should be provided to Git, these options are available: @@ -96,6 +98,16 @@ Use e.g. `git.tag: false` or `--no-git.tag` to skip a single step. By default, untracked files are not added to the release commit. Use `git.addUntrackedFiles: true` to override this behavior. +## Use all refs to determine latest tag + +By default, Git determines the latest tag using [`git describe`](https://git-scm.com/docs/git-describe), which finds the most recent tag _that is reachable from a commit._ If you wish to consider all tags, e.g. to include tags that point to sibling commits on different branches, then set `git.getLatestTagFromAllRefs: true` (the default is `false`). + +![Determine latest tag from all refs](assets/git-version-from-all-refs.svg) + +In the above illustration, releasing from `develop` and incrementing the semver `rc` modifier, when `git.getLatestTagFromAllRefs: false` (the default), the latest tag is `v1.1.0-rc1`, because that is the most recent tag reachable from the current commit (the red circle on `develop`). The version to release will therefore be `v1.1.0-rc2`. + +Setting `git.getLatestTagFromAllRefs: true` considers all tags (sorting them by version), whether directly reachable or not. In which case, the latest tag is `v1.1.0` from `main`, and the new version to release is `v1.2.0-rc1`. + ## Prerequisite checks ### Required branch diff --git a/lib/plugin/GitBase.js b/lib/plugin/GitBase.js index 607dc08a..39b6773c 100644 --- a/lib/plugin/GitBase.js +++ b/lib/plugin/GitBase.js @@ -94,10 +94,20 @@ class GitBase extends Plugin { const context = Object.assign({}, this.config.getContext(), { version: '*' }); const match = format(this.options.tagMatch || this.options.tagName || '${version}', context); const exclude = this.options.tagExclude ? ` --exclude=${format(this.options.tagExclude, context)}` : ''; - return this.exec(`git describe --tags --match=${match} --abbrev=0${exclude}`, { options }).then( - stdout => stdout || null, - () => null - ); + if (this.options.getLatestTagFromAllRefs) { + return this.exec( + `git -c "versionsort.suffix=-" for-each-ref --count=1 --sort=-v:refname --format="%(refname:short)" refs/tags/${match}`, + { options } + ).then( + stdout => stdout || null, + () => null + ); + } else { + return this.exec(`git describe --tags --match=${match} --abbrev=0${exclude}`, { options }).then( + stdout => stdout || null, + () => null + ); + } } async getSecondLatestTagName(latestTag) { diff --git a/lib/plugin/GitRelease.js b/lib/plugin/GitRelease.js index 0b66498d..258928f0 100644 --- a/lib/plugin/GitRelease.js +++ b/lib/plugin/GitRelease.js @@ -12,7 +12,14 @@ class GitRelease extends GitBase { getInitialOptions(options) { const baseOptions = super.getInitialOptions(...arguments); const git = options.git || defaultConfig.git; - const gitOptions = _.pick(git, ['tagExclude', 'tagName', 'tagMatch', 'pushRepo', 'changelog']); + const gitOptions = _.pick(git, [ + 'tagExclude', + 'tagName', + 'tagMatch', + 'getLatestTagFromAllRefs', + 'pushRepo', + 'changelog' + ]); return _.defaults(baseOptions, gitOptions); }