threads / discuss / 12791

Recording cherry-picked commits

Subject: Recording cherry-picked commits

## tl;dr

8 messages between Mar 21, 2008 and Mar 23, 2008.

replies: 7people: 4as markdown or json

Jean-Baptiste Quenot· Mar 21, 2008, 12:33 UTC · lore
Hi there,

Cherry-picking is great with Git, both with git-cherry-pick and git-cherry. I use them to pick commits from my development branch to my stable maintenance branch that goes to production.

But when a particular commit is slightly different between the two branches (due to eg a conflict resolution in my stable branch), then git-cherry still lists the commit as only present in the development branch. This is a feature, as documented in the man page, because git-cherry compares the changeset rather than the commit id.

So I'm wondering if there's a way to record the commit ID as being already picked from the development branch to the stable branch, so that it's not listed again when I provide the same arguments to cherry-pick. I was used to this kind of feature with svnmerge, a wrapper script around svn that records cherry-picked commits in a Subversion property called svnmerge-integrated on the root directory. But with Git, what is the best practice for knowing which commits you already picked?

Ideally, the set of already-picked commits would be versioned in the Git repo itself, so that other developers can watch what commits are available to pick as well.

Thanks in advance,
-- 
Jean-Baptiste Quenot
http://caraldi.com/jbq/blog/
Jean-Baptiste Quenot· Mar 22, 2008, 16:37 UTC · re: Jean-Baptiste Quenot · lore

Re: Recording cherry-picked commits

What about using a hidden ".gitcherry" file in the current branch to store the commits that have been applied? With the simple shell scripts below I'm able to achieve the same effect as svnmerge:

Wrapper around git-cherry-pick: ------------------------------------------------------------------------ #! /bin/sh -e

# Write the commit in .gitcherry, stage .gitcherry for commit and call # git-cherry-pick. If a conflict occurs, resolve it and invoke this script with # --continue, in order to commit with the original author and commit message

if test "$1" = "--continue" ; then
    cont=1
    commit=$(tail -1 .gitcherry)
else
    cont=0
    commit=$1
fi
if test $cont = 0 ; then
    echo $commit >> .gitcherry
    git add .gitcherry
    git cherry-pick $commit
else
    git commit -c $commit
fi
-------------------------------------------------------------------------

Wrapper around git-cherry: ------------------------------------------------------------------------ #! /bin/sh -e

# List all commits with git-cherry and exclude all the ones that are specified # in .gitcherry. For each commit, invoke 'git show' to print the commit message

for commit in $(git-cherry $* | sed -ne 's/^+ //p' | grep -v -f .gitcherry) ; do
    git show -s --pretty=format:"%H %s" $commit
done
------------------------------------------------------------------------
WDYT?
-- 
Jean-Baptiste Quenot
http://caraldi.com/jbq/blog/
Rafael Garcia-Suarez· Mar 22, 2008, 22:48 UTC · re: Jean-Baptiste Quenot · lore

Re: Recording cherry-picked commits

On 22/03/2008, Jean-Baptiste Quenot <jbq@caraldi.com> wrote:
> What about using a hidden ".gitcherry" file in the current branch to
>  store the commits that have been applied?  With the simple shell
>  scripts below I'm able to achieve the same effect as svnmerge:

(.gitcherry should really be at the root of the git repository, not in the current directory)

What happens to .gitcherry across merges ? I think your solution isn't robust enough.

Here's an alternate idea: store the original sha1 in the commit message, via a custom header (something like X-Cherry-Picked-From) at least in case of conflict, and have git-cherry recognize it.

(I have the same problem as you, by the way, and would really like to see it solved one way or another.)

Junio C Hamano· Mar 23, 2008, 00:37 UTC · re: Rafael Garcia-Suarez · lore

Re: Recording cherry-picked commits

"Rafael Garcia-Suarez" <rgarciasuarez@gmail.com> writes:
Show 6 quoted lines
> Here's an alternate idea: store the original sha1 in the commit
> message, via a custom header (something like X-Cherry-Picked-From) at
> least in case of conflict, and have git-cherry recognize it.
>
> (I have the same problem as you, by the way, and would really like to
> see it solved one way or another.)
"-x"?
Jean-Baptiste Quenot· Mar 23, 2008, 11:07 UTC · re: Rafael Garcia-Suarez · lore

Re: Recording cherry-picked commits

2008/3/22, Rafael Garcia-Suarez <rgarciasuarez@gmail.com>:
Show 7 quoted lines
> On 22/03/2008, Jean-Baptiste Quenot <jbq@caraldi.com> wrote:
>  > What about using a hidden ".gitcherry" file in the current branch to
>  >  store the commits that have been applied?  With the simple shell
>  >  scripts below I'm able to achieve the same effect as svnmerge:
>
> (.gitcherry should really be at the root of the git repository, not in
>  the current directory)

Yes that's what I meant. Usually I'm always at the root when I'm cherry-picking changes but you're right the script could be improved in this regard. Is there a trick to find the root repository directory?

>  What happens to .gitcherry across merges ?  I think your solution isn't robust
> enough.

The .gitcherry is merged like any other file. I'm just trying to mimic svnmerge here, not to reinvent anything. As Git does not have file metadata, I'm using a plain text file to achieve this.

>  Here's an alternate idea: store the original sha1 in the commit
>  message, via a custom header (something like X-Cherry-Picked-From) at
>  least in case of conflict, and have git-cherry recognize it.

I like your idea of filtering on commit messages, that makes sense and it voids the use of .gitcherry, and thus better preserves the diffs.

Here is the updated git-cherry-pick wrapper. Note that we repeat the commit log in the message, and we're loosing the author information. Keeping the author would require to change git-commit to allow combining -C and -F. Also it seems that -C and -t are incompatible, although git-commit does not error out.

Junio suggests to use git-cherry's -x flag, but it is not written upon conflict, so it's useless for the current usecase about properly handling conflicts during cherry-picking.

------------------------------------------------------------------------ #! /bin/sh -e

# Record the commit id in .git/CHERRY_COMMIT, and call git-cherry-pick without # actually committing. If a conflict occurs, resolve it and invoke this script # with --continue. The commit log is then fed to git commit. # # FIXME find the root repository directory

if test "$1" = "--continue" ; then
    cont=1
    commit=$(cat .git/CHERRY_COMMIT)
else
    cont=0
    commit=$1
fi
if test $cont = 0 ; then
    echo $commit > .git/CHERRY_COMMIT
    git cherry-pick -n $commit
fi

git log -1 $commit | git commit -F - rm -f .git/CHERRY_COMMIT ------------------------------------------------------------------------

And the updated git-cherry wrapper: ------------------------------------------------------------------------ #! /bin/sh -e

# List all commits with git-cherry and exclude all the ones that are already # part of the change log of the current branch. For each available commit, # invoke 'git show' to print the commit message.

tempfile=$(tempfile -p $(basename $0)) git log --pretty=format:%s | sed -ne 's/^commit \([a-z0-9]\{40\}\)$/\1/p' > $tempfile

for commit in $(git-cherry $* | sed -ne 's/^+ //p' | grep -v -f $tempfile) ; do
    git show -s --pretty=format:"%H %s" $commit
done

rm -f $tempfile ------------------------------------------------------------------------

Cheers,
-- 
Jean-Baptiste Quenot
http://caraldi.com/jbq/blog/
Johannes Schindelin· Mar 23, 2008, 12:11 UTC · re: Jean-Baptiste Quenot · lore

Re: Recording cherry-picked commits

Hi,
On Sun, 23 Mar 2008, Jean-Baptiste Quenot wrote:
Show 12 quoted lines
> 2008/3/22, Rafael Garcia-Suarez <rgarciasuarez@gmail.com>:
> > On 22/03/2008, Jean-Baptiste Quenot <jbq@caraldi.com> wrote:
> >  > What about using a hidden ".gitcherry" file in the current branch 
> >  > to store the commits that have been applied?  With the simple shell 
> >  > scripts below I'm able to achieve the same effect as svnmerge:
> >
> > (.gitcherry should really be at the root of the git repository, not in 
> > the current directory)
> 
> Yes that's what I meant.  Usually I'm always at the root when I'm 
> cherry-picking changes but you're right the script could be improved in 
> this regard.  Is there a trick to find the root repository directory?

Actually, you should not store it in the root of the working tree, but in the git dir (because it should never be tracked!), and then you can make it non-hidden:

	file="$(git rev-parse --git-dir)"/cherry
Show 6 quoted lines
> > What happens to .gitcherry across merges ?  I think your solution 
> > isn't robust enough.
> 
> The .gitcherry is merged like any other file.  I'm just trying to
> mimic svnmerge here, not to reinvent anything.  As Git does not have
> file metadata, I'm using a plain text file to achieve this.

Ah, I see, so you _want_ to track it. I do not like this idea personally, but then, I will not use .gitcherry anyway.

	file="$(git rev-parse --show-cdup)"/.gitcherry

Hth, Dscho

Rafael Garcia-Suarez· Mar 23, 2008, 13:57 UTC · re: Johannes Schindelin · lore

Re: Recording cherry-picked commits

On 23/03/2008, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
Show 5 quoted lines
> Actually, you should not store it in the root of the working tree, but in
>  the git dir (because it should never be tracked!), and then you can make
>  it non-hidden:
>
>         file="$(git rev-parse --git-dir)"/cherry

But this way, how can it be shared among several repositories? (without patching git-clone itself, that might be a solution.) The use case being many commiters cherry-picking patches from a development branch to a maintainance one.

Johannes Schindelin· Mar 23, 2008, 14:12 UTC · re: Rafael Garcia-Suarez · lore

Re: Recording cherry-picked commits

Hi,
On Sun, 23 Mar 2008, Rafael Garcia-Suarez wrote:
Show 8 quoted lines
> On 23/03/2008, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > Actually, you should not store it in the root of the working tree, but in
> >  the git dir (because it should never be tracked!), and then you can make
> >  it non-hidden:
> >
> >         file="$(git rev-parse --git-dir)"/cherry
> 
> But this way, how can it be shared among several repositories?
As I said, I would not want it shared.  Or tracked.
You can still do what you want to, though.

Ciao, Dscho

← back to recent threads