git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Is there something like a git format-patch --squash?
@ 2010-02-18 19:45 Avery Pennarun
  2010-02-18 19:46 ` Avery Pennarun
  2010-02-18 20:34 ` Jeff King
  0 siblings, 2 replies; 4+ messages in thread
From: Avery Pennarun @ 2010-02-18 19:45 UTC (permalink / raw)
  To: Jeff King; +Cc: Jon Seymour, Git Mailing List

On Thu, Feb 18, 2010 at 1:38 PM, Avery Pennarun <apenwarr@gmail.com> wrote:
> On Thu, Feb 18, 2010 at 12:11 AM, Jeff King <peff@peff.net> wrote:
>> One simple strategy would be to squash all side-branch development into
>> a single commit.
>
> Something like this (replace MY_START_BRANCH with your starting
> branch, and do this in a clone of your repository so you don't destroy
> anything by accident):
>
>        parent=""
>        git rev-list --first-parent --reverse  | while read commit; do
>                if [ -z "$parent" ]; then
>                        git checkout -f $commit
>                        git clean -fdx
>                else
>                        git diff $parent $commit | git apply --index
>                        git commit -C $commit
>                fi
>                parent=$commit
>        done

In the above, in the 'else' clause, what I really wanted was something like:

   git format-patch --stdout --squash $parent..$commit

with one big "| git am" at the end of the loop.

However, format-patch seems to have no way of just producing a single
patch with all the changes from a particular branch.  Is there some
other easy command that would do what I want?  It seems like something
that someone would have wanted before now.

Thanks,

Avery

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Is there something like a git format-patch --squash?
  2010-02-18 19:45 Is there something like a git format-patch --squash? Avery Pennarun
@ 2010-02-18 19:46 ` Avery Pennarun
  2010-02-18 20:34 ` Jeff King
  1 sibling, 0 replies; 4+ messages in thread
From: Avery Pennarun @ 2010-02-18 19:46 UTC (permalink / raw)
  To: Jeff King; +Cc: Jon Seymour, Git Mailing List

On Thu, Feb 18, 2010 at 2:45 PM, Avery Pennarun <apenwarr@gmail.com> wrote:
> In the above, in the 'else' clause, what I really wanted was something like:
>
>   git format-patch --stdout --squash $parent..$commit

Um, where the unstated actual problem is that format-patch has no
"--squash" option. :)

Avery

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Is there something like a git format-patch --squash?
  2010-02-18 19:45 Is there something like a git format-patch --squash? Avery Pennarun
  2010-02-18 19:46 ` Avery Pennarun
@ 2010-02-18 20:34 ` Jeff King
  2010-02-18 21:56   ` Avery Pennarun
  1 sibling, 1 reply; 4+ messages in thread
From: Jeff King @ 2010-02-18 20:34 UTC (permalink / raw)
  To: Avery Pennarun; +Cc: Jon Seymour, Git Mailing List

On Thu, Feb 18, 2010 at 02:45:54PM -0500, Avery Pennarun wrote:

> > Something like this (replace MY_START_BRANCH with your starting
> > branch, and do this in a clone of your repository so you don't destroy
> > anything by accident):
> >
> >        parent=""
> >        git rev-list --first-parent --reverse  | while read commit; do
> >                if [ -z "$parent" ]; then
> >                        git checkout -f $commit
> >                        git clean -fdx
> >                else
> >                        git diff $parent $commit | git apply --index
> >                        git commit -C $commit
> >                fi
> >                parent=$commit
> >        done
> 
> In the above, in the 'else' clause, what I really wanted was something like:
> 
>    git format-patch --stdout --squash $parent..$commit
> 
> with one big "| git am" at the end of the loop.

I don't think there is a way to do it automagically. Obviously you can
use diff (as you did) to produce the diff, but how should the many
commit messages be combined?

Worst case, you could probably do it yourself by echoing the mail
headers yourself, throwing all of the commit messages in the body, and
then doing the diff:

  me=`git var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
  (echo "From: $me"
   echo "Subject: Mega-squash of $commit"
   echo
   git log --format="%s%n%n%b" $parent..$commit
   echo ---
   git diff $parent $commit
  ) | git am

But that's totally untested (also, do you really need $parent? In
--first-parent --reverse, isn't it always going to be $commit^1?).

But I think you can do it without diff application by just re-using the
tree-state of each merge:

  git rev-list --first-parent --reverse $from..$to |
  last=$from
  while read commit; do
    last=`git cat-file commit $commit |
          sed '1,/^$/d' |
          git commit-tree $commit^{tree} -p $from`
  done
  git update-ref refs/heads/new $last

But that isn't tested either. :) You might need to replace
"$commit^{tree}" with an equivalent rev-parse.

-Peff

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Is there something like a git format-patch --squash?
  2010-02-18 20:34 ` Jeff King
@ 2010-02-18 21:56   ` Avery Pennarun
  0 siblings, 0 replies; 4+ messages in thread
From: Avery Pennarun @ 2010-02-18 21:56 UTC (permalink / raw)
  To: Jeff King; +Cc: Jon Seymour, Git Mailing List

On Thu, Feb 18, 2010 at 3:34 PM, Jeff King <peff@peff.net> wrote:
> On Thu, Feb 18, 2010 at 02:45:54PM -0500, Avery Pennarun wrote:
>> In the above, in the 'else' clause, what I really wanted was something like:
>>
>>    git format-patch --stdout --squash $parent..$commit
>>
>> with one big "| git am" at the end of the loop.
>
> I don't think there is a way to do it automagically. Obviously you can
> use diff (as you did) to produce the diff, but how should the many
> commit messages be combined?

Something like what merge --squash does would be fine, I think.

As it happens, the script I wrote ends up using the commit message
from merge commits (since those are the ones that end up including all
the patches from their side branch), which is precisely equivalent to
how it would look in a "linearizing" SCM like svn or cvs.

I happen to have merge.summary=true in my ~/.gitconfig so my merge
commits have extra information in them, though.

> Worst case, you could probably do it yourself by echoing the mail
> headers yourself, throwing all of the commit messages in the body, and
> then doing the diff:

True.  But format-patch already has the code for that, so it's kind of
error-prone to duplicate it.

> (also, do you really need $parent? In
> --first-parent --reverse, isn't it always going to be $commit^1?).

Good point.  That script was quickly hacked together after a few
iterations that previously did more important things with $parent.

> But I think you can do it without diff application by just re-using the
> tree-state of each merge:
>
>  git rev-list --first-parent --reverse $from..$to |
>  last=$from
>  while read commit; do
>    last=`git cat-file commit $commit |
>          sed '1,/^$/d' |
>          git commit-tree $commit^{tree} -p $from`
>  done
>  git update-ref refs/heads/new $last

I don't think that works, since commit-tree takes the commit message
on stdin but the other stuff via environment variables.  Which is too
bad, really, at least for this case.

Have fun,

Avery

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-02-18 21:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-18 19:45 Is there something like a git format-patch --squash? Avery Pennarun
2010-02-18 19:46 ` Avery Pennarun
2010-02-18 20:34 ` Jeff King
2010-02-18 21:56   ` Avery Pennarun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).