In our Git process, "master" is the integration branch for topic and fix branches for the current release cycle, but we also maintain a "stable" branch where we have to backport carefully some of our fixes already successfully tested on master.
All the difficulty is that the branch has already been merged back in "master" (else it is really easy with rebase --onto)
- We don't want to change the process the other way because a) we don't want to fix everything in the "stable" branch, and b) we sometimes have to make some changes to the "stable" branch that we don't want to merge in "master".
- Clearly, we cannot merge the fix into the "stable" branch because this will backports many unwanted features.
Graph of the initial situation I describe :
I--J (stable)
/
/
/
- A - B - C - D - E - F - G (master)
\ /
X -- Y (fix/123)
Graph of the kind of situation we want to reach :
I--J (stable)
/ \
/ X'- Y' (fix/123-stable)
/
- A - B - C - D - E - F - G (master)
\ /
X -- Y (fix/123)
More complex cases are possible, such as multiple merge to complete a fix :
- A - B - C - D - E - F - G - H (master)
\ / /
X - Y ----- Z (fix/123)
But we don't allow merge into a fix branch, so we shall never have something like this :
- A - B - C - D - E - F - G (master)
\ \ /
X - Y - Z (fix/123)
To achieve this, we can cherry-pick or rebase the fix branch :
1) cherry-pick (typicaly How do I backport a commit in git?) :
git checkout -b fix/123-stable stable
git cherry-pick X Y
This seems easy, but it is not when dealing with real life examples ; there is always a risk to forget some commits, or to pick wrong ones!
2) rebase --onto (https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html) :
2.a) the "not working" way :
git rebase --onto stable master fix/123
This does nothing since fix/123 has already been merged to master! 2.b) the "not far better than cherry-pick" way :
git rebase --onto stable D fix/123
This is still kind of risky because you need to take the SHA of D (and NOT X for instance).
2.c) the "use a temporary starting ref" way :
git tag begin D
git rebase --onto stable begin fix/123
git tag -d begin
This improve the previous situation, as the tag make it easier to do it or picture it in a graphical tool, but it is still lot of manual work.
3.d) the "reset hard master before the merge" (to the first branching point) Hum, seems hard to describe and to do.
So, what I am looking for is a git portable (no bash/grep/cut/sed implied) way to either;
1) list all commits made on a branch already merged back into "master" (here X and Y, and also Z in the "multi-merged" case) to cherry-pick them easily
2) get the commit of the first branch point of a branch already merged back into "master"
2.a) this cannot be done by the "git merge-base" command because the merge is already done (even multiple time)
2.b) I've found here Finding a branch point with Git? the following bash command I tweaked a bit:
git rev-list --boundary --date-order --reverse fix/123..master | grep -m 1 - | cut -c2-
but his is not a git easy nor portable command (ie not working without Bash or Cygwin tools)