{"thread":{"id":"66454","subject":"Question: behavior when reverting a commit from a shallow clone","startedAt":"2026-10-03T08:54:54Z","lastAt":"2026-10-05T18:10:20Z","messageCount":8,"participants":["Sphinx","Carlisle T. Hamlin","Patrick Steinhardt","Matt Hunter","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"554050","messageId":"CALfz8Qx63qNoSbXq7C7u+KwX4=HCL7=uOUahpXd6j7KvW_c_Eg@mail.gmail.com","threadId":"66454","inReplyTo":null,"subject":"Question: behavior when reverting a commit from a shallow clone","fromName":"Sphinx","fromEmail":"sphinx9692@gmail.com","sentAt":"2026-10-03T08:54:42Z","receivedAt":"2026-10-03T08:54:54Z","isPatch":false,"body":"Hi Git maintainers,\n\nI have been investigating Git's behavior in a particular destructive\nscenario and wanted to verify my understanding with the maintainers.\n\nConsider the following repository history:\n\nA -> B\n\nwhere A contains the repository's files and B is the current HEAD.\n\nThe repository is then cloned with:\n\ngit clone --depth=1 <repository>\n\nso only B is available locally and its parent A is not present in the\nshallow clone.\n\nIf an operation is then performed to restore/revert B, I was looking\ninto the behavior when the resulting working tree/index becomes empty\n— effectively causing all tracked files to be removed.\n\nI have gone through the Git documentation and experimented with the\nrelevant Git commands, including the behavior of shallow repositories,\nbranch deletion, working-tree changes, resets, restores, and other\ndestructive operations. Based on my investigation, I have not been\nable to find evidence that Git provides a warning or confirmation\nspecifically when an operation results in all tracked files being\nremoved or produces an empty tree.\n\nBefore drawing any conclusions, I wanted to verify this with the Git developers.\n\nIs the following understanding correct?\n\nAn empty tree is a valid Git state, so Git does not generally consider\ntransitioning from a non-empty tree to an empty tree inherently\nerroneous.\n\nGit does not have a general safeguard that warns when an operation\nwill delete all tracked files.\n\nIf there are existing safeguards, warnings, configuration options, or\nhistorical discussions that I may have missed, I would appreciate any\npointers.\n\nThe reason I am asking is that I am trying to establish precisely\nwhere Git's safety boundary is in this scenario specifically, whether\nGit itself is expected to warn about the resulting empty tree, or\nwhether detecting an unexpectedly destructive tree change is\nconsidered the responsibility of the tooling performing the operation.\n\nThanks,\nA fellow git user\n"},{"id":"554076","messageId":"54fac5f4-e49b-4384-af2c-615d7cc04ff5@gmx.com","threadId":"66454","inReplyTo":"CALfz8Qx63qNoSbXq7C7u+KwX4=HCL7=uOUahpXd6j7KvW_c_Eg@mail.gmail.com","subject":"Re: Question: behavior when reverting a commit from a shallow clone","fromName":"Carlisle T. Hamlin","fromEmail":"hamlin.carlisle@gmx.com","sentAt":"2026-10-03T19:41:47Z","receivedAt":"2026-10-03T19:41:51Z","isPatch":false,"body":"On 10/3/26 1:54 AM, Sphinx wrote:\n> Is the following understanding correct?\n> \n> An empty tree is a valid Git state, so Git does not generally consider\n> transitioning from a non-empty tree to an empty tree inherently\n> erroneous.\n> \n> Git does not have a general safeguard that warns when an operation\n> will delete all tracked files.\n> \n> If there are existing safeguards, warnings, configuration options, or\n> historical discussions that I may have missed, I would appreciate any\n> pointers.\n> \n> The reason I am asking is that I am trying to establish precisely\n> where Git's safety boundary is in this scenario specifically, whether\n> Git itself is expected to warn about the resulting empty tree, or\n> whether detecting an unexpectedly destructive tree change is\n> considered the responsibility of the tooling performing the operation.\nYou know, it seems to me that it should be reasonable for Git to assume \nthat someone with the wherewithal to set up and operate a git repository \n(or at the very least operate one that someone else set up) knows enough \nto understand what's going to happen if they obliterate the only commit \nin their tree.\n\nThere really is only *so* much holding of the hand I think we should be \nexpected to perform before it's not only insulting to the project \ndevelopers, but also to the *user*.\n\nMy two cents. I know folk use Git for all sorts of stuff. Just, maybe... \nthe sort of person who would be surprised catastrophically by this \nbehaviour... well... shouldn't.\n\n\n"},{"id":"554147","messageId":"asNKYAHSWJkFkhNn@pks.im","threadId":"66454","inReplyTo":"54fac5f4-e49b-4384-af2c-615d7cc04ff5@gmx.com","subject":"Re: Question: behavior when reverting a commit from a shallow clone","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-10-05T06:57:36Z","receivedAt":"2026-10-05T06:57:42Z","isPatch":false,"body":"On Sat, Oct 03, 2026 at 12:41:47PM -0700, Carlisle T. Hamlin wrote:\n> On 10/3/26 1:54 AM, Sphinx wrote:\n> > Is the following understanding correct?\n> > \n> > An empty tree is a valid Git state, so Git does not generally consider\n> > transitioning from a non-empty tree to an empty tree inherently\n> > erroneous.\n> > \n> > Git does not have a general safeguard that warns when an operation\n> > will delete all tracked files.\n> > \n> > If there are existing safeguards, warnings, configuration options, or\n> > historical discussions that I may have missed, I would appreciate any\n> > pointers.\n> > \n> > The reason I am asking is that I am trying to establish precisely\n> > where Git's safety boundary is in this scenario specifically, whether\n> > Git itself is expected to warn about the resulting empty tree, or\n> > whether detecting an unexpectedly destructive tree change is\n> > considered the responsibility of the tooling performing the operation.\n> You know, it seems to me that it should be reasonable for Git to assume that\n> someone with the wherewithal to set up and operate a git repository (or at\n> the very least operate one that someone else set up) knows enough to\n> understand what's going to happen if they obliterate the only commit in\n> their tree.\n> \n> There really is only *so* much holding of the hand I think we should be\n> expected to perform before it's not only insulting to the project\n> developers, but also to the *user*.\n> \n> My two cents. I know folk use Git for all sorts of stuff. Just, maybe... the\n> sort of person who would be surprised catastrophically by this behaviour...\n> well... shouldn't.\n\nThere really is no need to be this adversarial to a simple question like\nfrom the author. We want to be a welcoming community, and replies like\nthis are the exact opposite and will drive people away.\n\nThanks!\n\nPatrick\n"},{"id":"554148","messageId":"asNKZpxiuFhVkVQd@pks.im","threadId":"66454","inReplyTo":"CALfz8Qx63qNoSbXq7C7u+KwX4=HCL7=uOUahpXd6j7KvW_c_Eg@mail.gmail.com","subject":"Re: Question: behavior when reverting a commit from a shallow clone","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-10-05T06:57:42Z","receivedAt":"2026-10-05T06:57:46Z","isPatch":false,"body":"On Sat, Oct 03, 2026 at 02:24:42PM +0530, Sphinx wrote:\n> Hi Git maintainers,\n> \n> I have been investigating Git's behavior in a particular destructive\n> scenario and wanted to verify my understanding with the maintainers.\n> \n> Consider the following repository history:\n> \n> A -> B\n> \n> where A contains the repository's files and B is the current HEAD.\n> \n> The repository is then cloned with:\n> \n> git clone --depth=1 <repository>\n> \n> so only B is available locally and its parent A is not present in the\n> shallow clone.\n> \n> If an operation is then performed to restore/revert B, I was looking\n> into the behavior when the resulting working tree/index becomes empty\n> — effectively causing all tracked files to be removed.\n\nYeah, this can indeed be surprising behaviour. The reason for it is that\nin a shallow clone, we rewrite the boundary commit (so in your case B)\nso that it doesn't have any parents anymore. It thus looks like just\nanother root commit that has added all files in a single go. And the\nconsequence of that is that reverting it will then delete everything.\n\nNow arguably, Git could be improved here. We just recently had a similar\ndiscussion around maybe forbidding to \"git commit --amend\" such a\nshallow commit. Your scenario is a second one where Git should probably\nat least warn about what's happening.\n\nArguably we should even completely refuse editing such a shallow commit\nby default. I would guess that in 99% of all the cases where a user does\nit it's unintended. And for the 1% where it's actually intended we could\ngive users a way to override this safeguard.\n\n> I have gone through the Git documentation and experimented with the\n> relevant Git commands, including the behavior of shallow repositories,\n> branch deletion, working-tree changes, resets, restores, and other\n> destructive operations. Based on my investigation, I have not been\n> able to find evidence that Git provides a warning or confirmation\n> specifically when an operation results in all tracked files being\n> removed or produces an empty tree.\n> \n> Before drawing any conclusions, I wanted to verify this with the Git developers.\n> \n> Is the following understanding correct?\n> \n> An empty tree is a valid Git state, so Git does not generally consider\n> transitioning from a non-empty tree to an empty tree inherently\n> erroneous.\n\nMostly correct. A small correction though: Git considers the empty\n_root_ tree to be a valid state so that you can create a commit that\ncontains no files at all. We never write an empty sub-tree though, so\nyou cannot add an empty directory.\n\n> Git does not have a general safeguard that warns when an operation\n> will delete all tracked files.\n\nWe try hard to not lose a user's data, so especially untracked data is\nsomething we're careful about. But anything that's committed already is\nfair game, as it's trivial to restore.\n\n> If there are existing safeguards, warnings, configuration options, or\n> historical discussions that I may have missed, I would appreciate any\n> pointers.\n\nThere are none for the above use case, to the best of my knowledge.\n\n> The reason I am asking is that I am trying to establish precisely\n> where Git's safety boundary is in this scenario specifically, whether\n> Git itself is expected to warn about the resulting empty tree, or\n> whether detecting an unexpectedly destructive tree change is\n> considered the responsibility of the tooling performing the operation.\n\nI wouldn't warn about an empty tree in general. But editing a commit\nthat is a shallow boundary is something that I'd agree Git should warn\nabout, if not even refuse by default.\n\nPatrick\n"},{"id":"554165","messageId":"DLWUB05MOV7T.2XA7NG57870ZD@lfurio.us","threadId":"66454","inReplyTo":"asNKZpxiuFhVkVQd@pks.im","subject":"Re: Question: behavior when reverting a commit from a shallow clone","fromName":"Matt Hunter","fromEmail":"m@lfurio.us","sentAt":"2026-10-05T10:41:31Z","receivedAt":"2026-10-05T10:41:39Z","isPatch":false,"body":"On Mon Oct 5, 2026 at 2:57 AM EDT, Patrick Steinhardt wrote:\n> On Sat, Oct 03, 2026 at 02:24:42PM +0530, Sphinx wrote:\n>> \n>> If an operation is then performed to restore/revert B, I was looking\n>> into the behavior when the resulting working tree/index becomes empty\n>> — effectively causing all tracked files to be removed.\n>\n> Yeah, this can indeed be surprising behaviour. The reason for it is that\n> in a shallow clone, we rewrite the boundary commit (so in your case B)\n> so that it doesn't have any parents anymore. It thus looks like just\n> another root commit that has added all files in a single go. And the\n> consequence of that is that reverting it will then delete everything.\n\nSeparate question from the sidelines:  As a non shallow clone user, this\nmakes me wonder if/how these boundary commits might be munged to\npreserve original commit ids in the clone?  eg: so a fast-forward\npull still works for future content\n"},{"id":"554199","messageId":"xmqq7bjwkspu.fsf@gitster.g","threadId":"66454","inReplyTo":"DLWUB05MOV7T.2XA7NG57870ZD@lfurio.us","subject":"Re: Question: behavior when reverting a commit from a shallow clone","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-05T16:38:53Z","receivedAt":"2026-10-05T16:38:53Z","isPatch":false,"body":"\"Matt Hunter\" <m@lfurio.us> writes:\n\n> On Mon Oct 5, 2026 at 2:57 AM EDT, Patrick Steinhardt wrote:\n>> On Sat, Oct 03, 2026 at 02:24:42PM +0530, Sphinx wrote:\n>>> \n>>> If an operation is then performed to restore/revert B, I was looking\n>>> into the behavior when the resulting working tree/index becomes empty\n>>> — effectively causing all tracked files to be removed.\n>>\n>> Yeah, this can indeed be surprising behaviour. The reason for it is that\n>> in a shallow clone, we rewrite the boundary commit (so in your case B)\n>> so that it doesn't have any parents anymore. It thus looks like just\n>> another root commit that has added all files in a single go. And the\n>> consequence of that is that reverting it will then delete everything.\n>\n> Separate question from the sidelines:  As a non shallow clone user, this\n> makes me wonder if/how these boundary commits might be munged to\n> preserve original commit ids in the clone?  eg: so a fast-forward\n> pull still works for future content\n\nSomething similar to \"graft\" (and now \"replace\") is done under the\nhood, to stop history traversal machinery seeing the true parents\nof these boundary commits.  As the commit object itself (specifically\nits \"parent \" lines in the header part) is not modified in any way,\nthis does not affect object names.\n\n"},{"id":"554204","messageId":"CALfz8QxzXJ_0EC=a2AEO-_Qy+MGGnjHbE_8dBky23BLN-WnGPA@mail.gmail.com","threadId":"66454","inReplyTo":"CALfz8QzymKxvzYGWLwdtzERDm1apa8ebZEVyLne18hpTaB=D0g@mail.gmail.com","subject":"Re: Question: behavior when reverting a commit from a shallow clone","fromName":"Sphinx","fromEmail":"sphinx9692@gmail.com","sentAt":"2026-10-05T17:35:36Z","receivedAt":"2026-10-05T17:35:36Z","isPatch":false,"body":"Thanks, Patrick. That makes it much clearer.\n\nI was initially thinking of the empty tree as the potentially unsafe\npart, but from your explanation, it's clear that the empty tree itself\nisn't really the problem it's the shallow boundary that makes this\nbehavior surprising.\n\nThe absence of a safeguard specifically for editing a shallow boundary\ncommit, and the possibility of warning or refusing such operations by\ndefault, is exactly what I was trying to understand.\n\nThanks again for taking the time to explain it.\n\n\nOn Mon, Oct 5, 2026 at 10:44 PM Sphinx <sphinx9692@gmail.com> wrote:\n>\n> Thanks, Patrick. That makes it much clearer.\n>\n> I was initially thinking of the empty tree as the potentially unsafe part, but from your explanation, it's clear that the empty tree itself isn't really the problem it's the shallow boundary that makes this behavior surprising.\n>\n> The absence of a safeguard specifically for editing a shallow boundary commit, and the possibility of warning or refusing such operations by default, is exactly what I was trying to understand.\n>\n> Thanks again for taking the time to explain it.\n>\n>\n> On Mon, 5 Oct, 2026, 10:08 pm Junio C Hamano, <gitster@pobox.com> wrote:\n>>\n>> \"Matt Hunter\" <m@lfurio.us> writes:\n>>\n>> > On Mon Oct 5, 2026 at 2:57 AM EDT, Patrick Steinhardt wrote:\n>> >> On Sat, Oct 03, 2026 at 02:24:42PM +0530, Sphinx wrote:\n>> >>>\n>> >>> If an operation is then performed to restore/revert B, I was looking\n>> >>> into the behavior when the resulting working tree/index becomes empty\n>> >>> — effectively causing all tracked files to be removed.\n>> >>\n>> >> Yeah, this can indeed be surprising behaviour. The reason for it is that\n>> >> in a shallow clone, we rewrite the boundary commit (so in your case B)\n>> >> so that it doesn't have any parents anymore. It thus looks like just\n>> >> another root commit that has added all files in a single go. And the\n>> >> consequence of that is that reverting it will then delete everything.\n>> >\n>> > Separate question from the sidelines:  As a non shallow clone user, this\n>> > makes me wonder if/how these boundary commits might be munged to\n>> > preserve original commit ids in the clone?  eg: so a fast-forward\n>> > pull still works for future content\n>>\n>> Something similar to \"graft\" (and now \"replace\") is done under the\n>> hood, to stop history traversal machinery seeing the true parents\n>> of these boundary commits.  As the commit object itself (specifically\n>> its \"parent \" lines in the header part) is not modified in any way,\n>> this does not affect object names.\n\n"},{"id":"554208","messageId":"593528e2-bac3-4d9d-8374-be30e97b0028@gmx.com","threadId":"66454","inReplyTo":"asNKYAHSWJkFkhNn@pks.im","subject":"Re: Question: behavior when reverting a commit from a shallow clone","fromName":"Carlisle T. Hamlin","fromEmail":"hamlin.carlisle@gmx.com","sentAt":"2026-10-05T18:10:20Z","receivedAt":"2026-10-05T18:10:20Z","isPatch":false,"body":"On 10/4/26 11:57 PM, Patrick Steinhardt wrote:\n>> You know, it seems to me that it should be reasonable for Git to assume that\n>> someone with the wherewithal to set up and operate a git repository (or at\n>> the very least operate one that someone else set up) knows enough to\n>> understand what's going to happen if they obliterate the only commit in\n>> their tree.\n>>\n>> There really is only *so* much holding of the hand I think we should be\n>> expected to perform before it's not only insulting to the project\n>> developers, but also to the *user*.\n>>\n>> My two cents. I know folk use Git for all sorts of stuff. Just, maybe... the\n>> sort of person who would be surprised catastrophically by this behaviour...\n>> well... shouldn't.\n> > There really is no need to be this adversarial to a simple question like\n> from the author. We want to be a welcoming community, and replies like\n> this are the exact opposite and will drive people away.\n\nMy apologies; I didn't realize I was coming across as adversarial.\n\nAlso, I stand corrected - other replies to this question indicate that we *are, indeed* prepared to perform this level of hand holding. I fundamentally misunderstood the project's stance in this regard.\n\n\n"}]}