{"thread":{"id":"38517","subject":"'git rebase' silently drops changes?","startedAt":"2015-02-06T21:28:00Z","lastAt":"2015-02-10T18:26:19Z","messageCount":7,"participants":["Sergey Organov","Sebastian Schuberth","Johannes Sixt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"255681","messageId":"87386ispb3.fsf@osv.gnss.ru","threadId":"38517","inReplyTo":null,"subject":"'git rebase' silently drops changes?","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2015-02-06T21:28:00Z","receivedAt":"2015-02-06T21:28:00Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hello,\n\nI recently ran into an annoying problem: 'git rebase' apparently\nsilently drops changes in non-conflicting paths of merge commits\n(git version 1.9.3). \n\nIs it a bug or feature? Is there a way to flatten history using rebase,\nyet preserve manual changes found in merge commits?\n\nHere is simplified reproduction of what I've encountered:\n\n<SCRIPT>\ngit init t\ncd t\ngit config rerere.enabled true\n\necho \"I\" > a; git add a\necho \"I\" > b; git add b\ngit commit -am \"I\"\n\ngit checkout -b test\n\necho \"B\" >> b; git commit -m \"B\" -a\n\ngit checkout master\n\necho \"A\" >> a\ngit commit -am \"A\"\n\ngit merge --no-edit test\n\n# Clean merge, but result didn't compile, so I fixed it and\n# amended the merge:\necho \"Precious!\" >> a # [!] This is modification that gets lost\ngit commit --amend --no-edit -a\ncat a\n\n# Now rebase my work.\ngit rebase -f HEAD~1\n\n# What? Where is my \"Precious\" change in \"a\"???\ncat a\n</SCRIPT>\n\nI.e., the modification marked [!] was silently lost during rebase!\n\n-- \nSergey.\n"},{"id":"255709","messageId":"54D68455.5070305@gmail.com","threadId":"38517","inReplyTo":"87386ispb3.fsf@osv.gnss.ru","subject":"Re: 'git rebase' silently drops changes?","fromName":"Sebastian Schuberth","fromEmail":"sschuberth@gmail.com","sentAt":"2015-02-07T21:32:05Z","receivedAt":"2015-02-07T21:32:05Z","isPatch":false,"sender":{"key":"sschuberth@gmail.com","avatar":"https://avatars.githubusercontent.com/u/349154?v=4"},"body":"On 06.02.2015 22:28, Sergey Organov wrote:\n\n> # Now rebase my work.\n> git rebase -f HEAD~1\n>\n> # What? Where is my \"Precious\" change in \"a\"???\n> cat a\n> </SCRIPT>\n>\n> I.e., the modification marked [!] was silently lost during rebase!\n\nJust a wild guess: Maybe because you omitted \"-p\" / \"--preserve-merges\" \nfrom \"git rebase\"?\n\n-- \nSebastian Schuberth\n"},{"id":"255767","messageId":"54D7696B.3060407@kdbg.org","threadId":"38517","inReplyTo":"54D68455.5070305@gmail.com","subject":"Re: 'git rebase' silently drops changes?","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-02-08T13:49:31Z","receivedAt":"2015-02-08T13:49:31Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 07.02.2015 um 22:32 schrieb Sebastian Schuberth:\n> On 06.02.2015 22:28, Sergey Organov wrote:\n> \n>> # Now rebase my work.\n>> git rebase -f HEAD~1\n>>\n>> # What? Where is my \"Precious\" change in \"a\"???\n>> cat a\n>> </SCRIPT>\n>>\n>> I.e., the modification marked [!] was silently lost during rebase!\n> \n> Just a wild guess: Maybe because you omitted \"-p\" / \"--preserve-merges\"\n> from \"git rebase\"?\n\nNo, that would not help. --preserve-merges repeats the merge, but does\nnot apply the amendment.\n\nIt's just how rebase works: It omits merge commits when it linearizes\nhistory.\n\nSergey, it is impossible for git rebase to decide to which rebased\ncommit the amendement applies. It doesn't even try to guess. It's the\nresponsibility of the user to apply the amendment to the correct commit.\n\n-- Hannes\n"},{"id":"255818","messageId":"87oap38cv1.fsf@osv.gnss.ru","threadId":"38517","inReplyTo":"54D7696B.3060407@kdbg.org","subject":"Re: 'git rebase' silently drops changes?","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2015-02-09T12:53:54Z","receivedAt":"2015-02-09T12:53:54Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 07.02.2015 um 22:32 schrieb Sebastian Schuberth:\n>> On 06.02.2015 22:28, Sergey Organov wrote:\n>> \n>>> # Now rebase my work.\n>>> git rebase -f HEAD~1\n>>>\n>>> # What? Where is my \"Precious\" change in \"a\"???\n>>> cat a\n>>> </SCRIPT>\n>>>\n>>> I.e., the modification marked [!] was silently lost during rebase!\n>> \n>> Just a wild guess: Maybe because you omitted \"-p\" / \"--preserve-merges\"\n>> from \"git rebase\"?\n>\n> No, that would not help. --preserve-merges repeats the merge, but does\n> not apply the amendment.\n\nReally? Why? Here the valid concern you gave below doesn't even apply!\n\nCheck... yes, git silently drops amend even with --preserve-merges\n(script to reproduce at the end[1])! How comes?\n\n> It's just how rebase works: It omits merge commits when it linearizes\n> history.\n>\n> Sergey, it is impossible for git rebase to decide to which rebased\n> commit the amendement applies. It doesn't even try to guess. It's the\n> responsibility of the user to apply the amendment to the correct\n> commit.\n\nYeah, this sounds reasonable, /except/ git even gives no warning when it\ndrops amendments. Shouldn't 'git rebase' rather consider merge amendment\na kind of conflict?\n\n\n[1] To reproduce amend drop by \"git rebase --preserve-merges\":\n\n<SCRIPT>\ngit init t\ncd t\ngit config rerere.enabled false # doesn't actually matter either way.\n\necho \"I\" > a; git add a\necho \"I\" > b; git add b\ngit commit -aqm \"I\"\ngit tag start\n\ngit checkout -b test\n\necho \"B\" >> b; git commit -m \"B\" -a\n\ngit checkout master\n\necho \"A\" >> a\ngit commit -aqm \"A\"\n\ngit merge --no-edit test\ngit branch -d test\n\n# Clean merge, but result didn't compile, so I fixed it and\n# amended the merge:\necho \"Precious!\" >> a # [!] This is modification that gets lost\ngit commit --amend --no-edit -aq\ncat a\n\n# Make a change earlier in history, to rebase my work on top of it.\ngit co -q start\ngit co -b test\necho \"C\" > c; git add c\ngit commit -aqm \"C\"\n\n# Now rebase my work.\ngit co master\ngit rebase --preserve-merges --no-fork-point test\n\n# What? Where is my \"Precious\" change in \"a\"???\ncat a\n\n</SCRIPT>\n\n-- Sergey.\n"},{"id":"255836","messageId":"54D90473.2090208@kdbg.org","threadId":"38517","inReplyTo":"87oap38cv1.fsf@osv.gnss.ru","subject":"Re: 'git rebase' silently drops changes?","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-02-09T19:03:15Z","receivedAt":"2015-02-09T19:03:15Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 09.02.2015 um 13:53 schrieb Sergey Organov:\n> Johannes Sixt <j6t@kdbg.org> writes:\n> \n>> Am 07.02.2015 um 22:32 schrieb Sebastian Schuberth:\n>>> On 06.02.2015 22:28, Sergey Organov wrote:\n>>>\n>>>> # Now rebase my work.\n>>>> git rebase -f HEAD~1\n>>>>\n>>>> # What? Where is my \"Precious\" change in \"a\"???\n>>>> cat a\n>>>> </SCRIPT>\n>>>>\n>>>> I.e., the modification marked [!] was silently lost during rebase!\n>>>\n>>> Just a wild guess: Maybe because you omitted \"-p\" / \"--preserve-merges\"\n>>> from \"git rebase\"?\n>>\n>> No, that would not help. --preserve-merges repeats the merge, but does\n>> not apply the amendment.\n> \n> Really? Why? Here the valid concern you gave below doesn't even apply!\n\n--preserve-merges was bolted on to git-rebase. The first implementation\njust re-computed the merge, and rebase would be interrupted if the merge\nwas not clean. This was good enough for many.\n\nLater --preserve-merges was abused to replay not only integration\nbranches, but branchy history in general. At that time, the feature was\ndeemed wide spread enough that changing its behavior was a no-go.\n\nThere you have it.\n\nIf you want a version of --preserve-merges that does what *you* need,\nconsider this commit:\n\n  git://repo.or.cz/git/mingw/j6t.git rebase-p-first-parent\n\nUse it like this:\n\n  git rebase -i -p --first-parent ...\n\nBeware, its implementation is incomplete: if the rebase is interrupted,\nthen 'git rebase --continue' behaves as if --first-parent were not given.\n\n>> it is impossible for git rebase to decide to which rebased\n>> commit the amendement applies. It doesn't even try to guess. It's the\n>> responsibility of the user to apply the amendment to the correct\n>> commit.\n> \n> Yeah, this sounds reasonable, /except/ git even gives no warning when it\n> drops amendments. Shouldn't 'git rebase' rather consider merge amendment\n> a kind of conflict?\n\nThere is work in progress where a merge is computed entirely in-memory\n(without relying on files in the worktree). It could be used to detect\nwhether there are any changes beyond the automatic merge results, and\nthey could be warned about.\n\n-- Hannes\n"},{"id":"255880","messageId":"87pp9ivvir.fsf@osv.gnss.ru","threadId":"38517","inReplyTo":"54D90473.2090208@kdbg.org","subject":"Re: 'git rebase' silently drops changes?","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2015-02-10T11:46:52Z","receivedAt":"2015-02-10T11:46:52Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 09.02.2015 um 13:53 schrieb Sergey Organov:\n\n[...]\n\n> If you want a version of --preserve-merges that does what *you* need,\n> consider this commit:\n>\n>   git://repo.or.cz/git/mingw/j6t.git rebase-p-first-parent\n>\n> Use it like this:\n>\n>   git rebase -i -p --first-parent ...\n\nThanks a lot, this sounds promising! I've read the message for this\ncommit and it mentions no drawbacks. Are you aware of any?\n\n> Beware, its implementation is incomplete: if the rebase is interrupted,\n> then 'git rebase --continue' behaves as if --first-parent were not\n> given.\n\nJust never did get round to it, or something more fundamental?\n\nTo be useful for me, it also needs a support for 'git pull' to pass this\nflag to 'git rebase', but that I think I can easily fix myself.\n\n>>> it is impossible for git rebase to decide to which rebased\n>>> commit the amendement applies. It doesn't even try to guess. It's the\n>>> responsibility of the user to apply the amendment to the correct\n>>> commit.\n>> \n>> Yeah, this sounds reasonable, /except/ git even gives no warning when it\n>> drops amendments. Shouldn't 'git rebase' rather consider merge amendment\n>> a kind of conflict?\n>\n> There is work in progress where a merge is computed entirely in-memory\n> (without relying on files in the worktree). It could be used to detect\n> whether there are any changes beyond the automatic merge results, and\n> they could be warned about.\n\nNice to hear there are chances to improve this in the future.\n\nThanks again!\n\n-- Sergey.\n"},{"id":"255889","messageId":"54DA4D4B.5010902@kdbg.org","threadId":"38517","inReplyTo":"87pp9ivvir.fsf@osv.gnss.ru","subject":"Re: 'git rebase' silently drops changes?","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-02-10T18:26:19Z","receivedAt":"2015-02-10T18:26:19Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 10.02.2015 um 12:46 schrieb Sergey Organov:\n> Johannes Sixt <j6t@kdbg.org> writes:\n> \n>> Am 09.02.2015 um 13:53 schrieb Sergey Organov:\n> \n> [...]\n> \n>> If you want a version of --preserve-merges that does what *you* need,\n>> consider this commit:\n>>\n>>   git://repo.or.cz/git/mingw/j6t.git rebase-p-first-parent\n>>\n>> Use it like this:\n>>\n>>   git rebase -i -p --first-parent ...\n> \n> Thanks a lot, this sounds promising! I've read the message for this\n> commit and it mentions no drawbacks. Are you aware of any?\n\nExcept for this...\n\n>> Beware, its implementation is incomplete: if the rebase is interrupted,\n>> then 'git rebase --continue' behaves as if --first-parent were not\n>> given.\n\n... not anything that I would care about. Of course, you can't rebase\nbranchy history when this option is specified, but that's the whole point.\n\n> Just never did get round to it, or something more fundamental?\n\nNothing fundamental. Just has to store the option in the rebase state\nlike all the other options.\n\n-- Hannes\n"}]}