My product is a plugin for IntelliJ. I support several versions of the underlying IntelliJ platform, and release builds of my plugin for each one since their APIs often change between versions. It's just me working on it, so I develop in master and then maintain a branch for each of the other versions. So my repo looks like this:
1.6.0 1.6.1-eap1
.... a---b---c--- master
\ \
d-------e--- idea-2017.1
\ \
f-------g--- idea-2016.3
\ \
... ... etc etc
a
is a stable release, and has been tagged with 1.6.0
. c
is an EAP (beta) release, and has been tagged with 1.6.1-eap1
. This scheme works fine for these two cases.
Occasionally I'd like to create a dev build which doesn't go into a release channel, but that users can download manually and test out if they like. I'd like to produce a dev build for each platform, since dev users could be using any IntelliJ version. The best way I can think of would be to create a branch for the dev build from, say, tag 1.6.0
(commit a
), and then corresponding branches from commits d
, f
and so on which I can merge the dev branch into and create dev builds from.
Assuming I want to write a script to create and maintain these branches, how can I find commits d
, f
and so on from the tag 1.6.0
to create the dev build branches from?
Here's what I ended up doing:
#!/bin/sh
set -e # Automatically abort if any simple command fails
die () {
echo >&2 "$@"
exit 1
}
[ "$#" -eq 2 ] || die "Usage: $0 <branch name> <tag>"
tag_commit=$(git rev-list --abbrev-commit -n 1 $2)
[ "${tag_commit}" = "" ] && die "No commit found for $2"
child_commit() {
git log --graph --pretty=format:"%h %p" --decorate -20 --first-parent $1 | grep $2 | cut -c 3-10
}
branch_2017_1=$(child_commit idea-2017.1 $tag_commit)
[ "${branch_2017_1}" = "" ] && die "No commit found for idea-2017.1"
branch_2016_3=$(child_commit idea-2016.3 $branch_2017_1)
[ "${branch_2016_3}" = "" ] && die "No commit found for idea-2016.3"
branch_2016_2=$(child_commit idea-2016.2 $branch_2016_3)
[ "${branch_2016_2}" = "" ] && die "No commit found for idea-2016.2"
branch_2016_1=$(child_commit idea-2016.1 $branch_2016_2)
[ "${branch_2016_1}" = "" ] && die "No commit found for idea-2016.1"
git branch "$1" $tag_commit
git branch "$1-2017.1" $branch_2017_1
git branch "$1-2016.3" $branch_2016_3
git branch "$1-2016.2" $branch_2016_2
git branch "$1-2016.1" $branch_2016_1
Now I'll just update my merging and release preparation scripts to optionally accept a branch series name, and I think I'll be good.
The secret sauce is in the child_commit
function, which is cribbed from here.
For the problem "find in between a
ang g
earliest commits from idea-2016.3
which was not in idea-2017
, and earliest in idea-2017
which was not in master
" solution would be to use command:
git log --oneline --source --ancestry-path master idea-2017 idea-2016.3 --not 1.6.0
output is, in history same to yours:
cf32d9f idea-2017 e
88f264c idea-2016.3 g
5bc9fa1 idea-2017 d
3f460fe idea-2016.3 f
224cac8 master c
67620cd master b
Then find latest line marked with idea-2016.3
and latest one marked with idea-2017
, that would be your commits.
Note that the output might be not desirable if there was some blocker issue due to version differences in for example f
which was fixed in subsequent f'
. So I would still consider explicit tagging.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With