22

I have the following git history:

A --- B --- C --- D' --- E' [master]
 \
  \ --- D --- E --- F [stable]

We have a policy to cherry-pick all changes from stable to master; D' and E' are cherry-picked commits from stable branch, F is not cherry-picked (has been forgotten).

How can I get a diff that bings up F (which was not cherry-picked into master)?


We don't want use merge because:

  • cleaner history without merge commits
  • commits to stable are rare
  • we have lots of different stable branches
Niko Sams
  • 4,304
  • 3
  • 25
  • 44

2 Answers2

18

That's exactly what the git cherry command is for.

It should never miss unpicked change, but it might occasionally list a change you consider picked if the pick involved conflict resolution.

Maxwell175
  • 1,954
  • 1
  • 17
  • 27
Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
-2

Git command cannot resolve this. I have written this script, it can help.

Script 1st calculates merge base of both branches branch1 and branch2. Then it makes two lists from merge base to head of branch1 and branch2 respectively. Then it creates a hash table of commits on branch2 with commit message's md5sum. Then it go through commit list of branch1 and check if that exist in branch2 hashtable or not?

In above case branch1 is stable and branch2 is master

#!/bin/bash

## Usage: ./missing_cherrypicks.sh branch1 branch2
## This script will find commits in branch1 missing in branch2
## Final list of missing commit will be in file missing_commits_branch1_branch2.csv

branch1=$1
branch2=$2

# Calculate mergebase of branch1 and branch2
mb=`git merge-base origin/$1 origin/$2`
rm -rf missing_commits_${branch1}_${branch2}.csv
echo "COMMIT,AUTHOR,MESSAGE,FILESLIST" >> missing_commits_${branch1}_${branch2}.csv

# Get commit list on both branches from merge-base
declare -a commitlist1=`git rev-list $mb..origin/$1`
declare -a commitlist2=`git rev-list $mb..origin/$2`

## Make HashKey for branch2
declare -A CommitHash
for com2 in ${commitlist2[@]}
do
  message2=`git log --pretty=oneline $com2 | head -1| sed "s/${com2} //" | sed 's/ *$//' | cut -c1-35`
  hashkey=`echo $message2 |md5sum |xargs | awk '{print $1}'`
  CommitHash[${hashkey}]=$com2
done

# Find commits of commitlist1 and check if they are in commitlist2
for com1 in ${commitlist1[@]}
do
   message1=`git log --pretty=oneline $com1 | head -1| sed "s/${com1} //"| sed 's/ *$//'| cut -c1-35`
   hashkey1=`echo $message1 |md5sum |xargs | awk '{print $1}'`
   if [[ -z ${CommitHash[${hashkey1}]} ]]
   then
      echo "------$com1-----------"
      author=$(git show $com1 |grep ^Author:|awk -F":" '{print $2}')
      fileslist=`git diff-tree --no-commit-id --name-only -r $com1`
      fl=""
      for file in ${fileslist[@]}
      do
          fl=${fl}":"$file
      done

      echo "------$author-------"
      echo "$com1,$author,$message1,$fl" >> missing_commits_${branch1}_${branch2}.csv
   fi
done
Paul Kertscher
  • 9,416
  • 5
  • 32
  • 57
Gaurav Negi
  • 21
  • 1
  • 4
  • 1
    Could you please elaborate *how* and *why* this solves the OPs issue? Just pasting some code is not a good answer, while it may technically answer the question. – Paul Kertscher Oct 17 '17 at 05:11
  • Script 1st calculates merge base of both branches branch1 and branch2. Then it makes two lists from merge base to head of branch1 and branch2 respectively. Then it creates a hash table of commits on branch2 with message's md5sum. Then it go through commit list of branch1 and check if that exist in branch2 hash table or not. – Gaurav Negi Oct 17 '17 at 05:17
  • In above case, branch1 is stable and branch2 is master. – Gaurav Negi Oct 17 '17 at 05:22
  • Please edit your answer accordingly and don't add details as comments. – Paul Kertscher Oct 17 '17 at 05:25
  • Added details with script. – Gaurav Negi Oct 17 '17 at 05:33