git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Is there something like a git format-patch --squash?

From
Jeff King <peff@peff.net>
Date
Feb 18, 2010, 20:34 UTC
Message-ID
<20100218203440.GA8110@coredump.intra.peff.net>
In-Reply-To
<32541b131002181145w44d69e9eo150d08f34273cefb@mail.gmail.com>
On Thu, Feb 18, 2010 at 02:45:54PM -0500, Avery Pennarun wrote:
Show 21 quoted lines
> > 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
Previous: Avery PennarunNext: Avery Pennarun
Message 3 of 4 in “Is there something like a git format-patch --squash?”
  1. Avery PennarunFeb 18, 2010
  2. Avery PennarunFeb 18, 2010
  3. Jeff KingFeb 18, 2010
  4. Avery PennarunFeb 18, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.