Finding merge commits from tag across branches in git

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.

  • How to access my bitbucket repository if I rename it
  • How to merge a successful build of a pull request using a Jenkinsfile
  • Git plumbing - find out if there are any unstaged files in a directory quickly
  • How to git push using git-emacs?
  • GIT: What is the best workflow to this situation?
  • Is it possible in SourceTree commit only one “hunk” of changes?
  • 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?

  • Git Gui: How to exclude unnecessary files from rescan
  • Bitbucket Server Pull Request
  • PHP Git Pull from GitHub Script SSH
  • Revert after merge --squash
  • Mac OS X 10.10 merge tool git bugs
  • What should I do when git revert aborts with an error message?
  • 3 Solutions collect form web for “Finding merge commits from tag across branches in git”

    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.

    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.

    Probably the easiest way is just to maintain a list of the supported versions/branch names in the shell script?

    The reason I’m thinking this is if you add another change:

    1.6.0      eap1 eap2
    .... a---b---c---h--- master
          \       \   \
           d-------e---i--- idea-2017.1
            \       \   \
             f-------g---j--- idea-2016.3
              \       \   \
              ...     ...  etc etc
    

    You want that change (h) merged into the head of the branches shown in your diagram, i.e h is merged to e and g. The branch 2017.1 would have been pointing at e which is the right commit to merge onto.

    You could do something with walking back to find a common ancestor or something but I think that’s needlessly complex and doesn’t really buy you anything.

    Plus if you just keep a list of branches you can stop supporting old versions relatively easily.

    Git Baby is a git and github fan, let's start git clone.