{"thread":{"id":"22717","subject":"Is there something like a git format-patch --squash?","startedAt":"2010-02-18T19:45:54Z","lastAt":"2010-02-18T21:56:30Z","messageCount":4,"participants":["Avery Pennarun","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"134993","messageId":"32541b131002181145w44d69e9eo150d08f34273cefb@mail.gmail.com","threadId":"22717","inReplyTo":null,"subject":"Is there something like a git format-patch --squash?","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2010-02-18T19:45:54Z","receivedAt":"2010-02-18T19:45:54Z","isPatch":false,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On Thu, Feb 18, 2010 at 1:38 PM, Avery Pennarun <apenwarr@gmail.com> wrote:\n> On Thu, Feb 18, 2010 at 12:11 AM, Jeff King <peff@peff.net> wrote:\n>> One simple strategy would be to squash all side-branch development into\n>> a single commit.\n>\n> Something like this (replace MY_START_BRANCH with your starting\n> branch, and do this in a clone of your repository so you don't destroy\n> anything by accident):\n>\n>        parent=\"\"\n>        git rev-list --first-parent --reverse  | while read commit; do\n>                if [ -z \"$parent\" ]; then\n>                        git checkout -f $commit\n>                        git clean -fdx\n>                else\n>                        git diff $parent $commit | git apply --index\n>                        git commit -C $commit\n>                fi\n>                parent=$commit\n>        done\n\nIn the above, in the 'else' clause, what I really wanted was something like:\n\n   git format-patch --stdout --squash $parent..$commit\n\nwith one big \"| git am\" at the end of the loop.\n\nHowever, format-patch seems to have no way of just producing a single\npatch with all the changes from a particular branch.  Is there some\nother easy command that would do what I want?  It seems like something\nthat someone would have wanted before now.\n\nThanks,\n\nAvery\n"},{"id":"134994","messageId":"32541b131002181146o1be5b874m1f8511abddf0aa64@mail.gmail.com","threadId":"22717","inReplyTo":"32541b131002181145w44d69e9eo150d08f34273cefb@mail.gmail.com","subject":"Re: Is there something like a git format-patch --squash?","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2010-02-18T19:46:58Z","receivedAt":"2010-02-18T19:46:58Z","isPatch":false,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On Thu, Feb 18, 2010 at 2:45 PM, Avery Pennarun <apenwarr@gmail.com> wrote:\n> In the above, in the 'else' clause, what I really wanted was something like:\n>\n>   git format-patch --stdout --squash $parent..$commit\n\nUm, where the unstated actual problem is that format-patch has no\n\"--squash\" option. :)\n\nAvery\n"},{"id":"135004","messageId":"20100218203440.GA8110@coredump.intra.peff.net","threadId":"22717","inReplyTo":"32541b131002181145w44d69e9eo150d08f34273cefb@mail.gmail.com","subject":"Re: Is there something like a git format-patch --squash?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2010-02-18T20:34:40Z","receivedAt":"2010-02-18T20:34:40Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Feb 18, 2010 at 02:45:54PM -0500, Avery Pennarun wrote:\n\n> > Something like this (replace MY_START_BRANCH with your starting\n> > branch, and do this in a clone of your repository so you don't destroy\n> > anything by accident):\n> >\n> >        parent=\"\"\n> >        git rev-list --first-parent --reverse  | while read commit; do\n> >                if [ -z \"$parent\" ]; then\n> >                        git checkout -f $commit\n> >                        git clean -fdx\n> >                else\n> >                        git diff $parent $commit | git apply --index\n> >                        git commit -C $commit\n> >                fi\n> >                parent=$commit\n> >        done\n> \n> In the above, in the 'else' clause, what I really wanted was something like:\n> \n>    git format-patch --stdout --squash $parent..$commit\n> \n> with one big \"| git am\" at the end of the loop.\n\nI don't think there is a way to do it automagically. Obviously you can\nuse diff (as you did) to produce the diff, but how should the many\ncommit messages be combined?\n\nWorst case, you could probably do it yourself by echoing the mail\nheaders yourself, throwing all of the commit messages in the body, and\nthen doing the diff:\n\n  me=`git var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`\n  (echo \"From: $me\"\n   echo \"Subject: Mega-squash of $commit\"\n   echo\n   git log --format=\"%s%n%n%b\" $parent..$commit\n   echo ---\n   git diff $parent $commit\n  ) | git am\n\nBut that's totally untested (also, do you really need $parent? In\n--first-parent --reverse, isn't it always going to be $commit^1?).\n\nBut I think you can do it without diff application by just re-using the\ntree-state of each merge:\n\n  git rev-list --first-parent --reverse $from..$to |\n  last=$from\n  while read commit; do\n    last=`git cat-file commit $commit |\n          sed '1,/^$/d' |\n          git commit-tree $commit^{tree} -p $from`\n  done\n  git update-ref refs/heads/new $last\n\nBut that isn't tested either. :) You might need to replace\n\"$commit^{tree}\" with an equivalent rev-parse.\n\n-Peff\n"},{"id":"135013","messageId":"32541b131002181356n633418e1jb608dfa71e5f8a5b@mail.gmail.com","threadId":"22717","inReplyTo":"20100218203440.GA8110@coredump.intra.peff.net","subject":"Re: Is there something like a git format-patch --squash?","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2010-02-18T21:56:30Z","receivedAt":"2010-02-18T21:56:30Z","isPatch":false,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On Thu, Feb 18, 2010 at 3:34 PM, Jeff King <peff@peff.net> wrote:\n> On Thu, Feb 18, 2010 at 02:45:54PM -0500, Avery Pennarun wrote:\n>> In the above, in the 'else' clause, what I really wanted was something like:\n>>\n>>    git format-patch --stdout --squash $parent..$commit\n>>\n>> with one big \"| git am\" at the end of the loop.\n>\n> I don't think there is a way to do it automagically. Obviously you can\n> use diff (as you did) to produce the diff, but how should the many\n> commit messages be combined?\n\nSomething like what merge --squash does would be fine, I think.\n\nAs it happens, the script I wrote ends up using the commit message\nfrom merge commits (since those are the ones that end up including all\nthe patches from their side branch), which is precisely equivalent to\nhow it would look in a \"linearizing\" SCM like svn or cvs.\n\nI happen to have merge.summary=true in my ~/.gitconfig so my merge\ncommits have extra information in them, though.\n\n> Worst case, you could probably do it yourself by echoing the mail\n> headers yourself, throwing all of the commit messages in the body, and\n> then doing the diff:\n\nTrue.  But format-patch already has the code for that, so it's kind of\nerror-prone to duplicate it.\n\n> (also, do you really need $parent? In\n> --first-parent --reverse, isn't it always going to be $commit^1?).\n\nGood point.  That script was quickly hacked together after a few\niterations that previously did more important things with $parent.\n\n> But I think you can do it without diff application by just re-using the\n> tree-state of each merge:\n>\n>  git rev-list --first-parent --reverse $from..$to |\n>  last=$from\n>  while read commit; do\n>    last=`git cat-file commit $commit |\n>          sed '1,/^$/d' |\n>          git commit-tree $commit^{tree} -p $from`\n>  done\n>  git update-ref refs/heads/new $last\n\nI don't think that works, since commit-tree takes the commit message\non stdin but the other stuff via environment variables.  Which is too\nbad, really, at least for this case.\n\nHave fun,\n\nAvery\n"}]}