{"thread":{"id":"61735","subject":"Losing the file during rebase","startedAt":"2024-07-04T14:28:42Z","lastAt":"2024-07-05T00:49:50Z","messageCount":4,"participants":["Dmytro Ovdiienko","Elijah Newren","brian m. carlson"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"498084","messageId":"SA3PR14MB6519B74CA58C9AE49DC28513E7DE2@SA3PR14MB6519.namprd14.prod.outlook.com","threadId":"61735","inReplyTo":null,"subject":"Losing the file during rebase","fromName":"Dmytro Ovdiienko","fromEmail":"dmytro.ovdiienko@iongroup.com","sentAt":"2024-07-04T14:28:40Z","receivedAt":"2024-07-04T14:28:42Z","isPatch":false,"sender":{"key":"dmytro.ovdiienko@iongroup.com","avatar":null},"body":"Hello,\n\nI'd like to report an issue. I'm not sure if it is a bug. Git just behaves not in the way as I expected.\n\n$ git --version\ngit version 2.34.1\n\n\nThe problem is that Git  is losing the file when I do rebase. Following are the steps to reproduce the issue:\n\n1. mkdir test\n2. cd test\n3. git init\n4. touch 1.cpp\n5. git add 1.cpp\n6. git commit -m \"Added 1.cpp\"\n7. touch 2.cpp\n8. touch 3.cpp\n9. git add 2.cpp 3.cpp\n10. git commit -m \"Added 2.cpp and 3.cpp\"\n11. git restore --source @~1 2.cpp\n12. git add -u\n13. git commit -m \"Delete committed 2.cpp\"\n14. git revert @\n15. git rebase -i @~3\n16. Now in the opened editor\n    a. move the last commit (revert commit) to the top of the commits list\n    b. squash/embed  (by typing 'f') the \"Delete comitted 2.cpp\" commit into the commit \"Added 2.cpp and 3.cpp\"\n17. Save and exit\n18. ls\n\nThe output is : 1.cpp 3.cpp\nExpected: 1.cpp 2.cpp 3.cpp\n\n\nIn case if at the step #16 you first do 16b, then close the editor, then start rebase again and do 16a, then all the files are on their places.\n\n\nKind regards\nDmytro Ovdiienko\n\n\nPlease access the attached hyperlink for an important electronic communications disclaimer:https://dashfinancial.com/disclaimer<https://dashfinancial.com/disclaimer/>\n\n\n"},{"id":"498095","messageId":"CABPp-BGE1aDb5Nch8kQx+uZkCvbTz6sN0m2Yad=1D4=z0C9JNA@mail.gmail.com","threadId":"61735","inReplyTo":"SA3PR14MB6519B74CA58C9AE49DC28513E7DE2@SA3PR14MB6519.namprd14.prod.outlook.com","subject":"Re: Losing the file during rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2024-07-04T21:03:18Z","receivedAt":"2024-07-04T21:03:30Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jul 4, 2024 at 7:29 AM Dmytro Ovdiienko\n<Dmytro.Ovdiienko@iongroup.com> wrote:\n>\n> Hello,\n>\n> I'd like to report an issue. I'm not sure if it is a bug. Git just behaves not in the way as I expected.\n>\n> $ git --version\n> git version 2.34.1\n>\n>\n> The problem is that Git  is losing the file when I do rebase. Following are the steps to reproduce the issue:\n>\n> 1. mkdir test\n> 2. cd test\n> 3. git init\n> 4. touch 1.cpp\n> 5. git add 1.cpp\n> 6. git commit -m \"Added 1.cpp\"\n> 7. touch 2.cpp\n> 8. touch 3.cpp\n> 9. git add 2.cpp 3.cpp\n> 10. git commit -m \"Added 2.cpp and 3.cpp\"\n> 11. git restore --source @~1 2.cpp\n> 12. git add -u\n> 13. git commit -m \"Delete committed 2.cpp\"\n> 14. git revert @\n> 15. git rebase -i @~3\n> 16. Now in the opened editor\n>     a. move the last commit (revert commit) to the top of the commits list\n>     b. squash/embed  (by typing 'f') the \"Delete comitted 2.cpp\" commit into the commit \"Added 2.cpp and 3.cpp\"\n> 17. Save and exit\n> 18. ls\n>\n> The output is : 1.cpp 3.cpp\n> Expected: 1.cpp 2.cpp 3.cpp\n>\n>\n> In case if at the step #16 you first do 16b, then close the editor, then start rebase again and do 16a, then all the files are on their places.\n\nNot a bug; I think you are expecting patches & commits to commute,\nwhen they do not.\n\nOne way to look at this, which I think you are viewing it from, is:\n   * If you start with 2.cpp, then remove 2.cpp in a commit, then\nrestore it in another commit, then you end up with 2.cpp; it _appears_\nthe last two commits are just inverses and together do nothing.\nAnd similarly,\n   * If you start with no file, then add 2.cpp in a commit, then\nremove it in another commit, then you end up with no file; it\n_appears_ the last two commits are just inverses and do nothing.\n\nHowever, if we take the last two commits above for each scenario but\ngive it a different starting point:\n  * If you start with no file, and try to play a change to remove\n2.cpp (which already doesn't exist), and then add 2.cpp, then the\nfirst commit is a no-op that does nothing while the second adds 2.cpp.\nThe last two commits are clearly not inverses.\n  * If you start with 2.cpp, then add a change which also tries to\ncreate the same 2.cpp, and then remove 2.cpp, then the first commit is\na no-op that does nothing while the second removes 2.cpp.  The last\ntwo commits are clearly not inverses.\n\nWhen you tried to rebase and swap the order of commits, you took\nthings from one of the first scenarios to one of the last two\nscenarios.\n"},{"id":"498100","messageId":"SA3PR14MB65191BDFF1F6E867969A678AE7DE2@SA3PR14MB6519.namprd14.prod.outlook.com","threadId":"61735","inReplyTo":"CABPp-BGE1aDb5Nch8kQx+uZkCvbTz6sN0m2Yad=1D4=z0C9JNA@mail.gmail.com","subject":"Re: Losing the file during rebase","fromName":"Dmytro Ovdiienko","fromEmail":"dmytro.ovdiienko@iongroup.com","sentAt":"2024-07-04T21:45:25Z","receivedAt":"2024-07-04T21:45:28Z","isPatch":false,"sender":{"key":"dmytro.ovdiienko@iongroup.com","avatar":null},"body":"Hello Elijah,\n\nThank you for reply.\n\nI guess the simpler explanation of what is happened would be the following:\n\nLet's say there are three commits: add_c1, del_c2 and add_c3.\n\nWhen they go like this \"add_c1 + del_c2 + add_c3\" at the end of execution you end up with 2.cpp. That is the case before I do rebase.\n\nWhen I change the order of commits into  \"add_c3 + add_c1 + del_c2\" (the case when I do rebase), I end up with no 2.cpp as add_c1 after add_c3 does nothing, because the file already exists. However, would be great for Git to return an error that it cannot create one more file. That is probably would be the best solution to this issue.\n\nIf I change the order of execution using the braces like in math into \"add_c3 + (add_c1 + del_c2)\", then Git first executes the content of braces and that expression gives me a no-op (first rebase), then it executes \"add_c3 + no-op\" (the second rebase). That gives me a 2.cpp at the end. That is why it works as expected when I first merge del_c2 into add_c1 and at the end I move add_c3 before add_c1.\n\n\n\nBest regards\nDima\n\n\n________________________________________\nFrom: Elijah Newren <newren@gmail.com>\nSent: Thursday, July 4, 2024 11:03 PM\nTo: Dmytro Ovdiienko <Dmytro.Ovdiienko@iongroup.com>\nCc: git@vger.kernel.org <git@vger.kernel.org>\nSubject: Re: Losing the file during rebase\n\n[You don't often get email from newren@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]\n\nCAUTION: [EXTERNAL Email]\n\n\nOn Thu, Jul 4, 2024 at 7:29 AM Dmytro Ovdiienko\n<Dmytro.Ovdiienko@iongroup.com> wrote:\n>\n> Hello,\n>\n> I'd like to report an issue. I'm not sure if it is a bug. Git just behaves not in the way as I expected.\n>\n> $ git --version\n> git version 2.34.1\n>\n>\n> The problem is that Git  is losing the file when I do rebase. Following are the steps to reproduce the issue:\n>\n> 1. mkdir test\n> 2. cd test\n> 3. git init\n> 4. touch 1.cpp\n> 5. git add 1.cpp\n> 6. git commit -m \"Added 1.cpp\"\n> 7. touch 2.cpp\n> 8. touch 3.cpp\n> 9. git add 2.cpp 3.cpp\n> 10. git commit -m \"Added 2.cpp and 3.cpp\"\n> 11. git restore --source @~1 2.cpp\n> 12. git add -u\n> 13. git commit -m \"Delete committed 2.cpp\"\n> 14. git revert @\n> 15. git rebase -i @~3\n> 16. Now in the opened editor\n>     a. move the last commit (revert commit) to the top of the commits list\n>     b. squash/embed  (by typing 'f') the \"Delete comitted 2.cpp\" commit into the commit \"Added 2.cpp and 3.cpp\"\n> 17. Save and exit\n> 18. ls\n>\n> The output is : 1.cpp 3.cpp\n> Expected: 1.cpp 2.cpp 3.cpp\n>\n>\n> In case if at the step #16 you first do 16b, then close the editor, then start rebase again and do 16a, then all the files are on their places.\n\nNot a bug; I think you are expecting patches & commits to commute,\nwhen they do not.\n\nOne way to look at this, which I think you are viewing it from, is:\n   * If you start with 2.cpp, then remove 2.cpp in a commit, then\nrestore it in another commit, then you end up with 2.cpp; it _appears_\nthe last two commits are just inverses and together do nothing.\nAnd similarly,\n   * If you start with no file, then add 2.cpp in a commit, then\nremove it in another commit, then you end up with no file; it\n_appears_ the last two commits are just inverses and do nothing.\n\nHowever, if we take the last two commits above for each scenario but\ngive it a different starting point:\n  * If you start with no file, and try to play a change to remove\n2.cpp (which already doesn't exist), and then add 2.cpp, then the\nfirst commit is a no-op that does nothing while the second adds 2.cpp.\nThe last two commits are clearly not inverses.\n  * If you start with 2.cpp, then add a change which also tries to\ncreate the same 2.cpp, and then remove 2.cpp, then the first commit is\na no-op that does nothing while the second removes 2.cpp.  The last\ntwo commits are clearly not inverses.\n\nWhen you tried to rebase and swap the order of commits, you took\nthings from one of the first scenarios to one of the last two\nscenarios.\n\n\nPlease access the attached hyperlink for an important electronic communications disclaimer:https://dashfinancial.com/disclaimer<https://dashfinancial.com/disclaimer/>\n\n\n"},{"id":"498101","messageId":"ZodDJq_SzONsP83m@tapette.crustytoothpaste.net","threadId":"61735","inReplyTo":"SA3PR14MB65191BDFF1F6E867969A678AE7DE2@SA3PR14MB6519.namprd14.prod.outlook.com","subject":"Re: Losing the file during rebase","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2024-07-05T00:49:42Z","receivedAt":"2024-07-05T00:49:50Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2024-07-04 at 21:45:25, Dmytro Ovdiienko wrote:\n> Hello Elijah,\n> \n> Thank you for reply.\n> \n> I guess the simpler explanation of what is happened would be the following:\n> \n> Let's say there are three commits: add_c1, del_c2 and add_c3.\n> \n> When they go like this \"add_c1 + del_c2 + add_c3\" at the end of\n> execution you end up with 2.cpp. That is the case before I do rebase.\n> \n> When I change the order of commits into  \"add_c3 + add_c1 + del_c2\"\n> (the case when I do rebase), I end up with no 2.cpp as add_c1 after\n> add_c3 does nothing, because the file already exists. However, would\n> be great for Git to return an error that it cannot create one more\n> file. That is probably would be the best solution to this issue.\n\nUnfortunately, that would cause a lot of spurious conflicts, since one\ntechnique that many teams use to incorporate changes is to rebase them.\nThus, if Alice has added file X to branch A and Bob has also added file\nX to branch B, and branch A gets incorporated into main, then Bob has a\nconflict.  If the contents of the file are the same, then the user will\nnot appreciate resolving this spurious conflict.\n\nNote that the behaviour you get for rebases is also the same one as you\nget for merges (which isn't exactly surprising because rebases now\nusually use the merge machinery).  If Alice creates branch A as above\nand Bob creates branch B, then once A is merged into main, B won't\nconflict for file X.  That's because if both heads in a merge contain\nthe same file with the same blob object ID (and thus the same contents),\nGit short-circuits the entire merge machinery and just incorporates that\nversion into the result, which is much faster and more efficient.\n\nIt may be that you're thinking about this process as applying one patch\non top of another, which is the way that the older git am-based approach\nused to work.  However, the modern rebase functionality is designed\naround merges internally, since this tends to avoid the brittleness of\npatches (such as misapplied hunks), it's faster, and it tends to be a\nlot more robust in a lot of cases, including with renames.\n-- \nbrian m. carlson (they/them or he/him)\nToronto, Ontario, CA\n"}]}