{"thread":{"id":"37785","subject":"squash commits deep down in history","startedAt":"2014-10-23T12:34:17Z","lastAt":"2014-11-04T17:25:17Z","messageCount":5,"participants":["Henning Moll","Johannes Sixt","Jakub Narębski","Phil Hord"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"250981","messageId":"trinity-6a57d894-cc4f-4213-9c51-5c73de2501d0-1414067657189@3capp-gmx-bs48","threadId":"37785","inReplyTo":null,"subject":"squash commits deep down in history","fromName":"Henning Moll","fromEmail":"newsscott@gmx.de","sentAt":"2014-10-23T12:34:17Z","receivedAt":"2014-10-23T12:34:17Z","isPatch":false,"sender":{"key":"newsscott@gmx.de","avatar":null},"body":"Hi,\n\ni need to squash several commits into a single one in a automated way. I know that there is interactive rebase, which can also be automated using GIT_SEQUENCE_EDITOR. Unfortunately my history is very large and i need to squash deep down in the history several times. So using interactive rebase seems not to be the right tool.\n\nI wonder if i can solve this task using filter-branch? I have a file that list the SHA1s for each squash operation per line. All SHA1s of a line are in chronological order (youngest to oldest), or in other words: the first SHA1 is the child of the second, and so on.\n\n| ab4423e 3432343 3234252\n| 2324342 5232343\n| ...\n\nLets say there are N lines in that file. Each line means: squash all SHA1s of this line into the first (or last) SHA1 of this line.\nPerforming this task with rebase would require N rewritings of the history. So e.g. HEAD (but many others too) would be rewritten N times even if it is not directly part of a line. My thinking is, that a filter-branch can do this in a single rewrite and therefore would be much more performant.\n\nHow can i solve this? Any ideas?\n\nBest regards\nHenning\n"},{"id":"251000","messageId":"54496036.8080109@kdbg.org","threadId":"37785","inReplyTo":"trinity-6a57d894-cc4f-4213-9c51-5c73de2501d0-1414067657189@3capp-gmx-bs48","subject":"Re: squash commits deep down in history","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2014-10-23T20:08:22Z","receivedAt":"2014-10-23T20:08:22Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 23.10.2014 um 14:34 schrieb Henning Moll:\n> i need to squash several commits into a single one in a automated\n> way. I know that there is interactive rebase, which can also be\n> automated using GIT_SEQUENCE_EDITOR. Unfortunately my history is very\n> large and i need to squash deep down in the history several times. So\n> using interactive rebase seems not to be the right tool.\n> \n> I wonder if i can solve this task using filter-branch? I have a file\n> that list the SHA1s for each squash operation per line. All SHA1s of\n> a line are in chronological order (youngest to oldest), or in other\n> words: the first SHA1 is the child of the second, and so on.\n\nUse git-replace do construct a squashed commit that replaces the last\nchild in each run such that its parent points to the parent of the first\nin the run. Then use a git-filterbranch without filters to burn the\nparenthood into the history.\n\n-- Hannes\n"},{"id":"251002","messageId":"54497F1A.8050606@gmx.de","threadId":"37785","inReplyTo":"54496036.8080109@kdbg.org","subject":"Re: squash commits deep down in history","fromName":"Henning Moll","fromEmail":"newsscott@gmx.de","sentAt":"2014-10-23T22:20:10Z","receivedAt":"2014-10-23T22:20:10Z","isPatch":false,"sender":{"key":"newsscott@gmx.de","avatar":null},"body":"Am 23.10.2014 um 22:08 schrieb Johannes Sixt:\n> Use git-replace do construct a squashed commit that replaces the last \n> child in each run such that its parent points to the parent of the \n> first in the run. Then use a git-filterbranch without filters to burn \n> the parenthood into the history. -- Hannes \nWow, cool. Thanks a lot for the hint.\n\nI managed to do the following: Suppose i have the following history\n\n\nA - B - C - D   <-master\n\nand i want to squash B and C together. First i create a temporary branch \non A and switch to it. Then i cherry-pick B and C without commit. So all \nthe changes are merged into the index. Then i commit a single commit \n\"M\". The history now looks like\n\n   M             <-temp\n  /\nA - B - C - D   <-master\n\nUsing\n\n$ git replace C M\n\nleads to\n\n    temp\n         |\n         v\n\nA -     M - D   <-master\n\nAs far as i understand, such a repalce is something like a \"symbolic \nlink\". Is that right?\n\nThis is interesting: Before filter-branch, the deletion of the replace \nwould lead to the initial situation (ABCD). After filter-branch, the \nhistory is (AM'D'). The replace still exists but is now something like a \n\"dead link\". I may come to life again after \"git resetting\" to somewhere \nbefore filter-branch. Even \"before\" creating the replace (the replace \nref itself is not part of the history). Even if you gor before creation \nof M: The link still works as long as M is not garbage collected. I was \nvery irritated after resetting to where i commited D, and still seeing \nA-M-D.\n\nSomehow logical, somehow crazy! I am still a git learner ;-)\n\nTwo questions remain for me:\n\n1. Is there a more elegant way to build M?\n2. Having a replace \"in place\" before filter-branch: Is there a way to \nfind out what the replace is hiding? A simple \"git log C\" produces \n\"M-A\". How to get \"C-B-A\"?\n\nBest regards\nHenning\n"},{"id":"251009","messageId":"544A3B5A.6030801@gmail.com","threadId":"37785","inReplyTo":"54496036.8080109@kdbg.org","subject":"Re: squash commits deep down in history","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2014-10-24T11:43:22Z","receivedAt":"2014-10-24T11:43:22Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 2014-10-23 22:08, Johannes Sixt pisze:\n> Am 23.10.2014 um 14:34 schrieb Henning Moll:\n\n>> i need to squash several commits into a single one in a automated\n>> way. I know that there is interactive rebase, which can also be\n>> automated using GIT_SEQUENCE_EDITOR. Unfortunately my history is very\n>> large and i need to squash deep down in the history several times. So\n>> using interactive rebase seems not to be the right tool.\n>>\n>> I wonder if i can solve this task using filter-branch? I have a file\n>> that list the SHA1s for each squash operation per line. All SHA1s of\n>> a line are in chronological order (youngest to oldest), or in other\n>> words: the first SHA1 is the child of the second, and so on.\n>\n> Use git-replace do construct a squashed commit that replaces the last\n> child in each run such that its parent points to the parent of the first\n> in the run. Then use a git-filter-branch without filters to burn the\n> parenthood into the history.\n\nUsing grafts (which are only about parentage, and are purely local) with \nfilter-less git-filter-branch might be easier than git-replace.\n\nIf you have the following history:\n\n     ... <--- O <--- A <--- B <--- C <--- ...\n\nand you want to squash A, B, C into\n\n     ... <--- O <----------------- C <--- ...\n\nsimply add the following to .git/info/grafts\n\n    <sha-1 of C> <sha-1 of O>\n\nfor example with\n\n    echo \"$(git rev-parse C) $(git rev-parse C^^^)\" >>.git/info/grafts\n\nCheck if the history is correct e.g. with \"git log --graph --oneline\",\nthen use filter-branch.\n\nBTW. do you know if it is possible to run filter-branch without \nreplacing replaces?\n\n\nJust for completeness, yet another way to do scripted history rewriting \nis to use git-fast-export + some editing script (e.g. reposurgeon[1]) + \ngit-fast-import.\n\n[1]: http://www.catb.org/esr/reposurgeon/\n\n-- \nJakub Narębski\n"},{"id":"251377","messageId":"CABURp0p_VzxXjFMEqLNg0MgY55akCmUJk7mvSG7JuuLp=r8YbA@mail.gmail.com","threadId":"37785","inReplyTo":"trinity-6a57d894-cc4f-4213-9c51-5c73de2501d0-1414067657189@3capp-gmx-bs48","subject":"Re: squash commits deep down in history","fromName":"Phil Hord","fromEmail":"phil.hord@gmail.com","sentAt":"2014-11-04T17:25:17Z","receivedAt":"2014-11-04T17:25:17Z","isPatch":false,"sender":{"key":"phil.hord@gmail.com","avatar":"https://avatars.githubusercontent.com/u/123908?v=4"},"body":"On Thu, Oct 23, 2014 at 8:34 AM, Henning Moll <newsScott@gmx.de> wrote:\n> Hi,\n>\n> i need to squash several commits into a single one in a automated way. I know that there is interactive rebase, which can also be automated using GIT_SEQUENCE_EDITOR. Unfortunately my history is very large and i need to squash deep down in the history several times. So using interactive rebase seems not to be the right tool.\n>\n> I wonder if i can solve this task using filter-branch? I have a file that list the SHA1s for each squash operation per line. All SHA1s of a line are in chronological order (youngest to oldest), or in other words: the first SHA1 is the child of the second, and so on.\n>\n> | ab4423e 3432343 3234252\n> | 2324342 5232343\n> | ...\n>\n> Lets say there are N lines in that file. Each line means: squash all SHA1s of this line into the first (or last) SHA1 of this line.\n\nI've often felt there should be some simple commands to do these kinds\nof edits.  For example, it is easy to amend HEAD, but an\norder-of-magnitude more difficult to amend HEAD^.   I imagine commands\nlike this:\n\n   git rebase --reword HEAD^\n   git rebase --edit some-old-commit\n   git rebase --squash ab4423e 3432343 3234252\n\nBut each time I think of implementing one of these I am daunted by the\nmany exceptional cases.\n\n\n> Performing this task with rebase would require N rewritings of the history. So e.g. HEAD (but many others too) would be rewritten N times even if it is not directly part of a line. My thinking is, that a filter-branch can do this in a single rewrite and therefore would be much more performant.\n>\n> How can i solve this? Any ideas?\n\nI know you solved this already with filter-branch, but that seems like\na complicated solution to me.  I think the --interactive rebase would\nhave been useful for you.  You should keep in mind that you do not\nneed to repeat the command multiple times for your multiple squashes.\nFor example, if your to-do list looks like this simple example:\n\npick 0000000\npick ab4423e\npick 3432343\npick 3234252\npick 0000001\npick 0000002\npick 2324342\npick 5232343\npick 0000003\n\nI think you could get the desired effect by changing it to this:\n\npick 0000000\npick ab4423e\nsquash 3432343\nsquash 3234252\npick 0000001\npick 0000002\npick 2324342\nsquash 5232343\npick 0000003\n\nAnd then running that all in one interactive rebase.  Does that make sense?\n\nPhil\n"}]}