Re: multiple-commit cherry-pick?

Previous thread: Workflow for sharing changes on top of often-rebased work by Mike Mazur on Wednesday, November 5, 2008 - 9:57 pm. (1 message)

Next thread: fetch --tags --no-tags by Pau Garcia i Quiles on Wednesday, November 5, 2008 - 11:42 pm. (2 messages)
To: <git@...>
Date: Wednesday, November 5, 2008 - 10:45 pm

Is there any easy way to cherry pick a _range_ of commits from some other
branch to the current branch, instead of just one?

I thought maybe git-rebase could be coerced to do this somehow, but I
couldn't figure a way. [Using git-rebase would be nice because of all the
useful tools it provides, e.g., the --abort, --continue, and -i options.]

Thanks,

-Miles

--
P.S. All information contained in the above letter is false,
for reasons of military security.
--

To: Miles Bader <miles@...>
Cc: <git@...>
Date: Thursday, November 6, 2008 - 5:37 pm

git format-patch --full-index --binary --stdout <range...> | git am -3

This will not work if you want to pick a list, not a range, of
commits.
--

To: Alex Riesen <raa.lkml@...>
Cc: Miles Bader <miles@...>, <git@...>
Date: Thursday, November 6, 2008 - 11:29 pm

Doesn't "--no-walk" + list commits individually work?

So it _should_ be possible to pick a list of commits too. Although I think
that git format-patch will reverse the order.

Linus
--

To: Linus Torvalds <torvalds@...>
Cc: Alex Riesen <raa.lkml@...>, Miles Bader <miles@...>, <git@...>
Date: Friday, November 7, 2008 - 1:00 am

Or "git show --pretty=email $commit1 $commit2" ... piped to "am"?

--

To: Junio C Hamano <gitster@...>
Cc: Alex Riesen <raa.lkml@...>, Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, <git@...>
Date: Friday, November 7, 2008 - 6:46 am

Or make git show write shell commands.

I often have commits that later need to be cherry-picked into other
branches. For these, I use a commit message that starts with the name of the
branch, like "implement-foo: make foo barfy". Later when I want to do the
cherry-picking, I use this:

git log t/whatever..master --reverse --pretty=tformat:'git cherry-pick %h #
%s' | sed 's/^\([^:]*\) \([^:]*\):/git checkout \2 \&\& \1/'

giving me output like:

git checkout implement-foo && git cherry-pick 90ce727 # make foo barfy
git checkout ...

... and I'm ready for cut'n'paste.

Michael

--
noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg -
Tel +49-911-9352-0 - Fax +49-911-9352-100
http://www.noris.de - The IT-Outsourcing Company

Vorstand: Ingo Kraupa (Vorsitzender), Joachim Astel, Hansjochen Klenk -
Vorsitzender des Aufsichtsrats: Stefan Schnabel - AG Nürnberg HRB 17689
--

To: Junio C Hamano <gitster@...>
Cc: Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, <git@...>
Date: Friday, November 7, 2008 - 3:12 am

Does not work if there are ranges given :-/
It'd be very nice to have: git show #c1..$c2 $c3 $c4 $c5..$c6

--

To: Alex Riesen <raa.lkml@...>
Cc: Miles Bader <miles@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Friday, November 7, 2008 - 2:08 pm

Yeah, we've very fundamentally never supported that. Not for show, but
also not for anything else (ie "gitk a..b c..d" does _not_ give you two
ranges).

It's easy to see why once you understand what 'a..b' really means (ie it
just expands to '^a' and 'b'), and how it's not really a "range" operation
as much as a set operation that interacts with all the other arguments
too. But unless you're very aware of that, it can be surprising.

Linus
--

To: Linus Torvalds <torvalds@...>
Cc: Miles Bader <miles@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Sunday, November 9, 2008 - 6:25 am

Oh, I am. But it is just so convenient to have range support for
commands which just show commits. Besides, git-show just errors out,
instead of producing the commits like git-log does.

--

To: Alex Riesen <raa.lkml@...>
Cc: Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Monday, November 10, 2008 - 3:58 pm

Hi,

Have fun implementing the support, and then explaining to users why this
shows only one commit:

git show HEAD^..HEAD HEAD~10

Ciao,
Dscho
--

To: Johannes Schindelin <Johannes.Schindelin@...>
Cc: Alex Riesen <raa.lkml@...>, Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, <git@...>
Date: Monday, November 10, 2008 - 4:41 pm

I find what Alex says somewhat silly because show is always "no walk", and
range by definition means you need to walk.

But when you give that command line, Alex could also change the command to
show the HEAD and HEAD~10, by changing the way series of range parameters
are evaluated by the revision parsing machinery. You take HEAD^..HEAD and
come up with one set (that has only one commit, HEAD), you take the next
parameter HEAD~10 and come up with another set (that also has only one
commit, HEAD~10, because show does not walk), then you take union.

I personally do not want to see that happen, though. The way multiple
"ranges" that come from separate command line parameters combine using set
operator semantics is so useful to do something like...

git log ko/master..master ^maint

which is my way to ask "Which commits on master are the ones that I
haven't pushed out? By the way, I have pushed out maint already so I do
not want to see anything that is already in maint", where ko/master tracks
what I pushed out to the public repository at k.org; this query is used to
see if I can still rewrite commits when I find typo/thinko in them.

--

To: Junio C Hamano <gitster@...>
Cc: Alex Riesen <raa.lkml@...>, Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, <git@...>
Date: Monday, November 10, 2008 - 5:34 pm

Hi,

Exactly one of my use cases, since we do not have ko/master,maint..master.

Ciao,
Dscho
--

To: Johannes Schindelin <Johannes.Schindelin@...>
Cc: Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Monday, November 10, 2008 - 4:24 pm

for cs in HEAD^..HEAD HEAD~10; do
case "$cs"; in
*..*)
git format-patch --stdout "$cs"
;;
*)
git show --pretty=email "$cs"
;;
esac
done

At least, this is what I have in mind and how I expect it to work.
--

To: Alex Riesen <raa.lkml@...>
Cc: Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Monday, November 10, 2008 - 5:31 pm

Hi,

That is not the way git-show is implemented (it uses setup_revisions() to
check for validity and to parse the arguments), and I cannot think of any
way to make this work without ugly workarounds.

Ciao,
Dscho

--

To: Johannes Schindelin <Johannes.Schindelin@...>
Cc: Alex Riesen <raa.lkml@...>, Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Friday, November 14, 2008 - 1:08 am

Would it be possible to add "range" support to a subset of commands by
using a git-range wrapper?

Hypothetical, pie-in-the-sky idea:

git range HEAD^..HEAD HEAD~10 -- show --pretty=email
git range HEAD^..HEAD HEAD~10 -- log
git range HEAD^..HEAD HEAD~10 -- cherry-pick

Which would call the given command for each of the commits found in all
the specified ranges and lists. git-range could have an internal list
of supported git subcommands that it would massage the parameter lists for.

I find this both elegant and ugly at the same time. :-)

- Chris

--

To: Chris Frey <cdfrey@...>
Cc: Alex Riesen <raa.lkml@...>, Johannes Schindelin <Johannes.Schindelin@...>, Miles Bader <miles@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Friday, November 14, 2008 - 12:11 pm

It would be better to just extend the SHA-1 arithmetic. We could do it, no
problem. It's just a SMOP.

For example, right now the arithmetic is entirely "flat", with no
precedence, no nesting, nothing but a single level of set operations. We
could extend it to be hierarchical.

So we _could_ do something like

git log {a..b} {c..d ^e}

and just declare that { $args } is a self-contained "subset", and
effectively becomes the same thing as "$(git rev-list $args)" but with
magic no-walking semantics (ie all walking is done only _within_ the { },
not between different groups.

You literally _can_ do it right now that way:

git log --no-walk $(git rev-list HEAD~5..HEAD~3) $(git rev-list HEAD~1..)

actually works, but that will hit argument size limits on many platforms
really quickly.

So we could make a '{ }' in the argument space basically do a SHA1
expansion of the range inside, and imply --no-walk. It's _not_ entirely
trivial, because we'd need to handle the fact that object flags are
sticky, and clear them in between invocations of multiple ranges, but it's
not _fundmanetally_ difficult. It's just that somebody would need to do
it.

Linus
--

To: Linus Torvalds <torvalds@...>
Cc: Chris Frey <cdfrey@...>, Alex Riesen <raa.lkml@...>, Johannes Schindelin <Johannes.Schindelin@...>, Miles Bader <miles@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Friday, November 14, 2008 - 2:38 pm

Le Friday 14 November 2008 17:11:41 Linus Torvalds, vous avez écrit :

I don't know if you really meant this, but entering SHA1s as is at a shell
prompt may have dangerous side effects... If not right now, then in (some not
so distant time in) the future. Consider this (I use bash 3.2, maintained by
Gentoo):

$ echo {a..c}
a b c

Who knows if some day they won't have the idea of, say,
extending "{aeb32ca..ee23ff1}" to, well... You see what I mean.

--
Francis Galiegue
ONE2TEAM
Ingénieur système
Mob : +33 (0) 6 83 87 78 75
Tel : +33 (0) 1 78 94 55 52
fge@one2team.com
40 avenue Raymond Poincaré
75116 Paris
--

To: Linus Torvalds <torvalds@...>
Cc: Chris Frey <cdfrey@...>, Alex Riesen <raa.lkml@...>, Johannes Schindelin <Johannes.Schindelin@...>, Miles Bader <miles@...>, <git@...>
Date: Friday, November 14, 2008 - 1:29 pm

Wouldn't you lose the nice streaming output (iow short latency)?

--

To: Junio C Hamano <gitster@...>
Cc: Chris Frey <cdfrey@...>, Alex Riesen <raa.lkml@...>, Johannes Schindelin <Johannes.Schindelin@...>, Miles Bader <miles@...>, <git@...>
Date: Friday, November 14, 2008 - 1:41 pm

Oh, absolutely. So the '{x}' format would be not be a replacement for
non-{} format - it would be an addition to.

But it's no different from 'a..b' in that sense: anything that sets
'revs->limited' automatically forces a synchronous revision walk. So you'd
be crazy to do

gitk {HEAD}

because
(a) there would be no point
(b) it indeed loses the streaming data and would become synchronous.

but if you already do

gitk a..b

then you're _already_ doing a revision limiter and forcing the revision
walk to be synchronous, so there would be no interactivity downside
between 'a..b' and '{a..b}'.

Linus
--

To: Junio C Hamano <gitster@...>
Cc: Chris Frey <cdfrey@...>, Alex Riesen <raa.lkml@...>, Johannes Schindelin <Johannes.Schindelin@...>, Miles Bader <miles@...>, <git@...>
Date: Friday, November 14, 2008 - 1:55 pm

Btw, the biggest problem (I think) is actually non-simple ranges and just
the _syntax_ of these things.

It's entirely reasonable to want to group a more complex expression than
just a single range. IOW, something like

gitk {..origin/pu ^origin/next} {HEAD~5..HEAD~2}

to show a union of what is in 'pu' but not master or next, and the
symmetrical difference of the current merge. It's a perfectly sensible
thing to do. And we _can_ do it right now, just with a nasty syntax:

gitk --no-walk $(git rev-list ..origin/pu ^origin/next) $(git rev-list HEAD~5..HEAD~2)

actually works. But look again at how nasty it is to parse the '{x}'
version, because the '{..}' thing now spans multiple arguments.

Linus
--

To: Linus Torvalds <torvalds@...>
Cc: Chris Frey <cdfrey@...>, Alex Riesen <raa.lkml@...>, Johannes Schindelin <Johannes.Schindelin@...>, Miles Bader <miles@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Sunday, November 16, 2008 - 5:11 am

That would probably be a job that parseopt could take care of. to some
degree.

Also { } is a poor choice as it's an expansion thingy for many shells.
zsh even refuses ` { a.. b } ` as an argument, pretending there is a
syntax error at the closing brace. [ ] looks like a safer choice, it's
used for shells supporting arrays, but only when stuck after an
identifier which won't be our case ever, so we would be probably safe.

--=20
=C2=B7O=C2=B7 Pierre Habouzit
=C2=B7=C2=B7O madcoder@debia=
n.org
OOO http://www.madism.org

To: Linus Torvalds <torvalds@...>
Cc: Chris Frey <cdfrey@...>, Alex Riesen <raa.lkml@...>, Miles Bader <miles@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Friday, November 14, 2008 - 12:59 pm

Hi,

Well, do not forget the case

git log ^HEAD^ {HEAD^..HEAD} $BLUB

Ciao,
Dscho

--

To: Chris Frey <cdfrey@...>
Cc: Alex Riesen <raa.lkml@...>, Miles Bader <miles@...>, Linus Torvalds <torvalds@...>, Junio C Hamano <gitster@...>, <git@...>
Date: Friday, November 14, 2008 - 10:00 am

Hi,

This is not really well defined is it? What about

git range HEAD -- log makefile

Where should it insert the "HEAD" argument?

Besides, I do not like how this muddies the semantics: if git range as you
proposed it became part of Git, people _would_ get confused why "git range
HEAD^..HEAD HEAD~10" interprets the range _differently_ from "git log
HEAD^..HEAD HEAD~10".

Ciao,
Dscho

--

To: Linus Torvalds <torvalds@...>
Cc: Alex Riesen <raa.lkml@...>, <git@...>
Date: Friday, November 7, 2008 - 12:38 am

Incidentally, the reason I like a rebase-based solution is that many
of the rebase features like -i, --abort, and --continue (after
conflict resolution) are very nice for the multi-cherry-pick case too,
and I'm already very familiar with their operation from using rebase.

[git-am seems to have some similar features, but I don't know how well
they work.]

-Miles

--
Do not taunt Happy Fun Ball.
--

To: Miles Bader <miles@...>
Cc: Linus Torvalds <torvalds@...>, <git@...>
Date: Friday, November 7, 2008 - 3:13 am

They work well.

--

To: Miles Bader <miles@...>
Cc: <git@...>
Date: Wednesday, November 5, 2008 - 11:24 pm

Rebase is exactly what you want. Given something like this:

o--o--o--A--B--C--o--o--X
\
o--o--D

where you want A, B, C to go on top of D:

$ git checkout -b newbranch C
$ git rebase --onto D ^A

newbranch will have <...> --D--A--B--C

Hope that helps,
Deskin Miller
--

To: Deskin Miller <deskinm@...>
Cc: Miles Bader <miles@...>, <git@...>
Date: Thursday, November 6, 2008 - 5:51 am

... and then you can merge newbranch into the existing branch that
references D, fast-forwarding the branch. And then newbranch can be
deleted.

If you don't want to use a temporary branch, you can also do (while on
the branch onto which you want to cherry-pick):

git reset --hard C
git rebase --onto ORIG_HEAD A^

Which should get you the same result, without using a temporary branch.

Björn
--

To: Björn <B.Steinbrink@...>
Cc: Deskin Miller <deskinm@...>, <git@...>
Date: Thursday, November 6, 2008 - 8:14 am

Is that safe...? Doesn't git-rebase also set ORIG_HEAD?

-Miles

--
Twice, adv. Once too often.
--

To: Miles Bader <miles@...>
Cc: Deskin Miller <deskinm@...>, <git@...>
Date: Thursday, November 6, 2008 - 8:26 am

One of the first things rebase does is validating and resolving its
arguments. And that's happening before any actions that would touch
ORIG_HEAD. Though I'm not sure if it's always been like that.

Björn
--

To: Björn <B.Steinbrink@...>
Cc: Deskin Miller <deskinm@...>, <git@...>
Date: Friday, November 7, 2008 - 1:09 am

Ah, I see.

Hmm, I guess using rebase --abort isn't a very good idea in this case
though... :-/

Kind of a shame, since it's nice being to just abort the whole operation
if it turns out you did something wrong and aren't sure how to recover.

Thanks,

-Miles

--
Kilt, n. A costume sometimes worn by Scotchmen [sic] in America and Americans
in Scotland.
--

To: Miles Bader <miles@...>
Cc: Deskin Miller <deskinm@...>, <git@...>
Date: Friday, November 7, 2008 - 7:03 am

Why not? I mean, ok, you end up at C, and not where you have been before
the reset --hard, but there's the reflog to help you get back to
whatever previous state of the branch it is that you want.

Björn
--

To: Björn Steinbrink <B.Steinbrink@...>
Cc: Deskin Miller <deskinm@...>, <git@...>
Date: Friday, November 7, 2008 - 7:46 am

I just mean it's not a trivial way to get back to the state before the
multi-cherry-pick -- you need to know the details of what's going on,
and handle the rest of the cleanup manually.

So, for instance, if you were to package up the above commands in a
shell script, the abort issue is one of those rough edges which would
prevent it from being as convenient as a real git command. [A
hypothetical extension of the cherry-pick command to handle multiple
commits would presumably offer a "cherry-pick --abort" option that did
everything magically.]

-Miles

--
Do not taunt Happy Fun Ball.
--

Previous thread: Workflow for sharing changes on top of often-rebased work by Mike Mazur on Wednesday, November 5, 2008 - 9:57 pm. (1 message)

Next thread: fetch --tags --no-tags by Pau Garcia i Quiles on Wednesday, November 5, 2008 - 11:42 pm. (2 messages)