{"thread":{"id":"14118","subject":"Re: why is git destructive by default? (i suggest it not be!)","startedAt":"2008-06-24T10:01:18Z","lastAt":"2016-08-14T00:43:06Z","messageCount":8,"participants":["David Jeske","Brandon Casey","Matthieu Moy","Jing Xue"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"80871","messageId":"21109.6734311015$1214304662@news.gmane.org","threadId":"14118","inReplyTo":"willow-jeske-01l5oEsvFEDjCjRW","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"David Jeske","fromEmail":"jeske@google.com","sentAt":null,"receivedAt":"2008-06-24T10:01:18Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"As a more practical question, how do I do this workflow illustrated below?\n\nIt's sort of similar to the workflow that \"git stash\" is trying to support,\nexcept that I have a bunch of commits instead of a bunch of\nuncommitted-changes.\n\nI pull a repository that looks like this:\n\n.  a<--b<--c  <--master\n\nThen I hack away to this, and then throw my own branch on the end, along with\nmaster:\n\n.  a<--b<--c<--d<--e<--f<--g  <--master (jeske)\n.                             <--feature1 (jeske)\n\nWhile the server looks like this:\n\n.  a<--b<--c<--1<--2<--3  <--master (server)\n\nI want to get my repository to look something like this:\n\n.  a<--b<--c<--1<--2<--3  <--master (jeske)\n.           \\\n.            d<--e<--f<--g   <-- feature1 (jeske)\n\nSo I can then do this:\n\n.  a<--b<--c<--1<--2<--3<--zz  <--master (jeske)\n.           \\\n.            d<--e<--f<--g   <-- feature1 (jeske)\n\n..and then push zz onto the server after 3.\n\n..and I want to do it with safe commands that won't leave any dangling\nreferences. (say if I forget to put the feature1 branch on)\n\nHow do I do that?\n"},{"id":"80911","messageId":"U-ySqQANiPRpld4kgzdXbovGgsj6LfOEdRmtTDU2yyvITSG3LnZAsQ@cipher.nrlssc.navy.mil","threadId":"14118","inReplyTo":"willow-jeske-01l5oJ=64=91FEDjCgQT","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Brandon Casey","fromEmail":"casey@nrlssc.navy.mil","sentAt":"2008-06-24T15:29:08Z","receivedAt":"2008-06-24T15:29:08Z","isPatch":false,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"David Jeske wrote:\n> As a more practical question, how do I do this workflow illustrated below?\n> \n> It's sort of similar to the workflow that \"git stash\" is trying to support,\n> except that I have a bunch of commits instead of a bunch of\n> uncommitted-changes.\n> \n> I pull a repository that looks like this:\n> \n> .  a<--b<--c  <--master\n\ngit clone <master_repo>\ncd master_repo\n\n> \n> Then I hack away to this, and then throw my own branch on the end, along with\n> master:\n> \n> .  a<--b<--c<--d<--e<--f<--g  <--master (jeske)\n> .                             <--feature1 (jeske)\n\nhack hack hack\ngit commit -a -m 'd'\nhack hack hack\ngit commit -a -m 'e'\nhack hack hack\ngit commit -a -m 'f'\nhack hack hack\ngit commit -a -m 'g'\ngit branch feature1\n\n\n> \n> While the server looks like this:\n> \n> .  a<--b<--c<--1<--2<--3  <--master (server)\n\ngit fetch\n\n> I want to get my repository to look something like this:\n> \n> .  a<--b<--c<--1<--2<--3  <--master (jeske)\n> .           \\\n> .            d<--e<--f<--g   <-- feature1 (jeske)\n\ngit reset --hard origin/master\n\nSide Note: you probably should have been developing on 'feature1' branch\nfrom the start. 'reset --hard' is a special case. If feature1 is a private\nbranch for developing in, you may want to rebase it ontop of master and retest\nbefore merging into master and pushing so that you can maintain a nice linear\nhistory when possible. Or you can just merge into master and then push.\n\n> So I can then do this:\n> \n> .  a<--b<--c<--1<--2<--3<--zz  <--master (jeske)\n> .           \\\n> .            d<--e<--f<--g   <-- feature1 (jeske)\n\nhack hack hack\ngit commit -a -m 'zz'\n\n> \n> ..and then push zz onto the server after 3.\n\ngit push\n\n> ..and I want to do it with safe commands that won't leave any dangling\n> references. (say if I forget to put the feature1 branch on)\n\n_Don't_ forget. 'reset --hard' is named that way for a reason. If you do\nforget, git makes it _easy_ to recover from.\n\nLet's say you _did_ forget. You did the 'reset --hard' on master and then\nyou committed the 'zz' change without creating the 'feature1' branch.\nYou can still create the feature1 branch since git saved the previous state\nin the reflog. It is two changes back.\n\ngit branch feature1 master@{2}\n\nIf you didn't know it was two changes back, then you can look through the\nreflog using 'git log -g master'. The commit message is there along with a\nreflog message describing what action was performed.\n\n\n\nAfter saying all of that, here is how I think you _should_ have done things.\nNotice I _did_not_ use 'reset --hard'.\n\ngit clone <master_repo>\ncd master_repo\ngit checkout -b feature1   # we create our feature branch immediately since\n                           # creating branches is so effortless in git. A\n                           # private feature branch should _always_ be created\n                           # and used for development.\nhack hack hack\ngit commit -a -m 'd'       # Make our 4 commits on the feature branch\nhack hack hack\ngit commit -a -m 'e'\nhack hack hack\ngit commit -a -m 'f'\nhack hack hack\ngit commit -a -m 'g'\ngit checkout master         # Let's go back to master\ngit pull                    # Fetch and merge the changes from the server\ngit checkout -b 'master_zz' # Create a branch for developing the zz feature\nhack hack hack\ngit commit -a -m 'zz'       # Commit the zz feature\ngit checkout master         # Go back to master\ngit merge master_zz         # Merge zz\ngit push                    # And push master out\ngit branch -d master_zz     # Now we're done with master_zz since it's all merged in\n\nNow you're in the same place you were above, you can continue developing your feature\non feature1 branch by checking it out. This is also were rebase comes in handy, since\nyou may want to rebase feature1 on top of the new current master. Once it is done and\nretested, you merge it into master and push it out.\n\n-brandon\n"},{"id":"80936","messageId":"22283.5020781078$1214329638@news.gmane.org","threadId":"14118","inReplyTo":"U-ySqQANiPRpld4kgzdXbovGgsj6LfOEdRmtTDU2yyvITSG3LnZAsQ@cipher.nrlssc.navy.mil","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"David Jeske","fromEmail":"jeske@google.com","sentAt":null,"receivedAt":"2008-06-24T17:41:57Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"\nMy takeaways from this thread:\n\n- THANKS! to all of you for the detailed discussion, and for making git. Even\nthough it's still unfamiliar to me, I really enjoy (g)it!\n\n- I don't think anyone here thinks git is beyond improvement. This discussion\ndid change my mind on a few things since my original post. I started this\ndiscussion to share my \"unacclimated usability suggestions\", because after I\nacclimate to git, I'll be telling new users that these idiosyncrasies are all\nno big deal too.  :) I still think there is value in this list of suggestions.\nI'll work on submitting patches...\n\n- improve the man page description of \"reset --hard\" (see below)\n- standardize all the potentially destructive operations (after gc) on \"-f /\n--force\" to override\n- add \"checkout\" to the git-gui history right-click menu, and make the danger\nof\n\"reset --hard\" more obvious and require a confirmation dialog (the gui\nequivilant of -f)\n\n\n----------\n\na couple more specific responses below..\n\n\n-- Rogan Dawes wrote:\n> -- David wrote:\n> > Let me guess, you're always running euid==0. :)\n> Do you also ask the gnu coreutils folks to remove the -f option from their\nutilities?\n\n-- Johannes Gilger wrote:\n> I think the name of the command \"reset\" itself is a name which should\n> prompt everyone to read a manpage before using it. [snip ]\n> Nobody complains about rm --force or anything.\n\nIsn't it nice that they standardized on \"-f\" and \"--force\" across ALL commands?\n\nI would be inclined to talk to coreutils if it was \"rm -f\", \"cp -R\" (vs cp -r),\nand \"mv --aggressive\" to do the respective non-safe versions.\n\nIt would simplify git's command-line-ui and cognitive load if it did the same\nthing. Pick one standard for \"overriding dangerous commands\", instead of\n\"danger caps\" and \"danger --reset\" and \"danger -f\". Consider branch which has\nboth \"branch -[MD]\" and \"branch -f\" in the same subcommand. What's wrong with\n\"branch -[md] -f\"?\n\nOf course --hard encourages one to read the manpage. However, git is using a\nbunch of new terms for things, and uses at least those three different methods\nto indicate command danger. Lets look at the working on the manpage:\n\n\"Matches the working tree and index to that of the tree being\nswitched\nto. Any changes to tracked files in the working tree since <commit>\nare lost.\"\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nI interpreted this as \"any [non committed changes] to tracked files in the\nworking tree since <commit> are lost.\"  I don't this this was a naive\ninterpretation. I still think that's the way it reads after this whole\nconversation.\n\nI'll work on my first patch for git:\n\n-> \"References to any working tree changes, and pulled changes, AND COMMITTED\nCHANGES to tracked files in the branch after <commit> will be dropped, causing\nthem to be removed at the next garbage collect.\".\n\n-- Brandon Casey wrote:\n> After saying all of that, here is how I think you _should_ have done things.\n> Notice I _did_not_ use 'reset --hard'.\n\nI was told that I can safely do \"git checkout origin/master\" instead of \"reset\n--hard\" to get back to the pull point, in case I didn't branch ahead of time.\nThe wrinkle being that my \"master\" branch-pointer still points to my local\nchanges, so I need to move onto a different branchname before I push if I want\nto avoid those changes going to the server, which is fine..\n\n> git clone <master_repo>\n> cd master_repo\n> git checkout -b feature1 # we create our feature branch immediately since\n> # creating branches is so effortless in git. A\n> # private feature branch should _always_ be created\n> # and used for development.\n\nI'm beginning to see why I would always work this way, though if \"private\nfeature branches should always be created and used for development\", then I'm\nunclear about why this isn't the default. git could implicitly create them when\nI checkin a change on the head of a pulled branch. (i.e. user/branchname/id, or\nsomething else). I'm reaching here, I'll need to use git more with other\ndevelopers to understand this better.\n\n-------------------\nThanks again for all the detailed responses and explanations!\n\n- David\n"},{"id":"80943","messageId":"2S4y4AAYvrk5mQlxSrErW9bgimc0ab_fh8jlpjxj84k@cipher.nrlssc.navy.mil","threadId":"14118","inReplyTo":"willow-jeske-01l5xqJDFEDjCftd","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Brandon Casey","fromEmail":"casey@nrlssc.navy.mil","sentAt":"2008-06-24T18:55:36Z","receivedAt":"2008-06-24T18:55:36Z","isPatch":false,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"David Jeske wrote:\n> My takeaways from this thread:\n> \n> - THANKS! to all of you for the detailed discussion, and for making git. Even\n> though it's still unfamiliar to me, I really enjoy (g)it!\n> \n> - I don't think anyone here thinks git is beyond improvement. This discussion\n> did change my mind on a few things since my original post. I started this\n> discussion to share my \"unacclimated usability suggestions\", because after I\n> acclimate to git, I'll be telling new users that these idiosyncrasies are all\n> no big deal too.  :) I still think there is value in this list of suggestions.\n> I'll work on submitting patches...\n> \n> - improve the man page description of \"reset --hard\" (see below)\n> - standardize all the potentially destructive operations (after gc) on \"-f /\n> --force\" to override\n\nThe thing is 'force' is not always the most descriptive word for the behavior\nthat you propose enabling with --force.\n\nFor the reset command in particular there is a --soft counterpart to --hard. They\nare both modifiers on the term 'reset' i.e. a 'soft reset' or a 'hard reset'. The\ndefault is wbat is called a 'mixed reset'.\n\n'gc' is another command that has been mentioned along with its '--aggressive' option.\n--force does not seem to make sense here either, since we are not necessarily forcing\nanything to happen in the sense of overriding some safe guard. What is happening is\nthat possibly more cpu-intensive options are being selected when repacking (compressing)\nthe repository.\n\n> Consider branch which has\n> both \"branch -[MD]\" and \"branch -f\" in the same subcommand. What's wrong with\n> \"branch -[md] -f\"?\n\nI am inclined to agree here. I'm not sure why the options for 'git branch' were\ncreated this way. I too have thought that a -f modifier on -m and -d would be\nmore intuitive.\n\n> Of course --hard encourages one to read the manpage. However, git is using a\n> bunch of new terms for things, and uses at least those three different methods\n> to indicate command danger. Lets look at the working on the manpage:\n> \n> \"Matches the working tree and index to that of the tree being\n> switched\n> to. Any changes to tracked files in the working tree since <commit>\n> are lost.\"\n> \n> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n> \n> I interpreted this as \"any [non committed changes] to tracked files in the\n> working tree since <commit> are lost.\"  I don't this this was a naive\n> interpretation. I still think that's the way it reads after this whole\n> conversation.\n\nI think the reason it only says that uncommitted changes are lost is because\nthe committed changes are not lost even though they may become unreachable\nfrom the head of the current branch. They are still reachable at least from\nthe reflog, so they are not lost. The uncommitted changes _are_ lost and are\nunrecoverable.\n\n> I'll work on my first patch for git:\n> \n> -> \"References to any working tree changes, and pulled changes, AND COMMITTED\n> CHANGES to tracked files in the branch after <commit> will be dropped, causing\n> them to be removed at the next garbage collect.\".\n\nUncommited working tree changes are gone immediately. Anything that has already\nbeen committed will be garbage collected only after it is not referenced by\nanything else in the repository. A reference will be maintained in the reflog\nfor at least 30 days (by default).\n\n> \n> -- Brandon Casey wrote:\n>> After saying all of that, here is how I think you _should_ have done things.\n>> Notice I _did_not_ use 'reset --hard'.\n> \n> I was told that I can safely do \"git checkout origin/master\" instead of \"reset\n> --hard\" to get back to the pull point, in case I didn't branch ahead of time.\n\nI think 'git checkout origin/master' would be a little odd since this is usually\na remote tracking branch. 'git checkout -b mymaster origin/master' or similar\nwould be more common. This creates a new branch named 'mymaster'.\n\n-brandon\n"},{"id":"81114","messageId":"vpqtzfhr9i3.fsf@bauges.imag.fr","threadId":"14118","inReplyTo":"willow-jeske-01l5xqJDFEDjCftd","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2008-06-25T12:20:52Z","receivedAt":"2008-06-25T12:20:52Z","isPatch":false,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"\"David Jeske\" <jeske@google.com> writes:\n\n> - standardize all the potentially destructive operations (after gc) on \"-f /\n> --force\" to override\n\nDepending on the definition of \"potentially destructive\", most\ncommands are \"potentially destructive\".\n\ngit pull loses the point where the branch used to point when the\nreflog expires.\n\ngit add loses the old content of the index.\n\n...\n\nAnd adding too many --force options removes its real value. Many\npeople type \"rm -fr\" any time they just want \"rm\", just because they\nwere annoyed by the multiple interactive confirmations of plain \"rm\"\n(if aliased to \"rm -i\"). Asking people to type --force all the time\nmake one fingers type --force mechanically, and removes all its value.\n\n-- \nMatthieu\n"},{"id":"81151","messageId":"20080625135647.wiohgih5hc0scgw0@intranet.digizenstudio.com","threadId":"14118","inReplyTo":"willow-jeske-01l5xqJDFEDjCftd","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jing Xue","fromEmail":"jingxue@digizenstudio.com","sentAt":"2008-06-25T17:56:47Z","receivedAt":"2008-06-25T17:56:47Z","isPatch":false,"sender":{"key":"jingxue@digizenstudio.com","avatar":null},"body":"\n\nQuoting David Jeske <jeske@google.com>:\n\n> - add \"checkout\" to the git-gui history right-click menu, and make the\n> danger of\n> \"reset --hard\" more obvious and require a confirmation dialog (the gui\n> equivilant of -f)\n\nIs that really necessary?  The way it works now, when I choose \"reset  \nfoo branch to here\", a dialog prompts me to pick from the three reset  \nmodes, with 'Mixed' being the default. So I'd have to explicitly pick  \n'Hard', which has a message \"discards ALL local changes\" right next to  \nit.  If people are so conditioned to ignore that, I doubt it'll take  \nvery long for them to be conditioned to just automatically confirm the  \nconfirmation dialog.\n\nThe same applies to the command line as well I guess - if having to  \nmanually type \"--hard\" does not make one stop and think about what  \nthey are doing, I can hardly see how \"--hard --force\" would do any  \nbetter.\n\nCheers.\n-- \nJing Xue\n"},{"id":"299226","messageId":"willow-jeske-01l5oJ=64=91FEDjCgQT","threadId":"14118","inReplyTo":"willow-jeske-01l5oEsvFEDjCjRW","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"David Jeske","fromEmail":"jeske@google.com","sentAt":null,"receivedAt":"2016-08-14T00:43:04Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"As a more practical question, how do I do this workflow illustrated below?\n\nIt's sort of similar to the workflow that \"git stash\" is trying to support,\nexcept that I have a bunch of commits instead of a bunch of\nuncommitted-changes.\n\nI pull a repository that looks like this:\n\n.  a<--b<--c  <--master\n\nThen I hack away to this, and then throw my own branch on the end, along with\nmaster:\n\n.  a<--b<--c<--d<--e<--f<--g  <--master (jeske)\n.                             <--feature1 (jeske)\n\nWhile the server looks like this:\n\n.  a<--b<--c<--1<--2<--3  <--master (server)\n\nI want to get my repository to look something like this:\n\n.  a<--b<--c<--1<--2<--3  <--master (jeske)\n.           \\\n.            d<--e<--f<--g   <-- feature1 (jeske)\n\nSo I can then do this:\n\n.  a<--b<--c<--1<--2<--3<--zz  <--master (jeske)\n.           \\\n.            d<--e<--f<--g   <-- feature1 (jeske)\n\n..and then push zz onto the server after 3.\n\n..and I want to do it with safe commands that won't leave any dangling\nreferences. (say if I forget to put the feature1 branch on)\n\nHow do I do that?\n"},{"id":"299228","messageId":"willow-jeske-01l5xqJDFEDjCftd","threadId":"14118","inReplyTo":"U-ySqQANiPRpld4kgzdXbovGgsj6LfOEdRmtTDU2yyvITSG3LnZAsQ@cipher.nrlssc.navy.mil","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"David Jeske","fromEmail":"jeske@google.com","sentAt":null,"receivedAt":"2016-08-14T00:43:06Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"\nMy takeaways from this thread:\n\n- THANKS! to all of you for the detailed discussion, and for making git. Even\nthough it's still unfamiliar to me, I really enjoy (g)it!\n\n- I don't think anyone here thinks git is beyond improvement. This discussion\ndid change my mind on a few things since my original post. I started this\ndiscussion to share my \"unacclimated usability suggestions\", because after I\nacclimate to git, I'll be telling new users that these idiosyncrasies are all\nno big deal too.  :) I still think there is value in this list of suggestions.\nI'll work on submitting patches...\n\n- improve the man page description of \"reset --hard\" (see below)\n- standardize all the potentially destructive operations (after gc) on \"-f /\n--force\" to override\n- add \"checkout\" to the git-gui history right-click menu, and make the danger\nof\n\"reset --hard\" more obvious and require a confirmation dialog (the gui\nequivilant of -f)\n\n\n----------\n\na couple more specific responses below..\n\n\n-- Rogan Dawes wrote:\n> -- David wrote:\n> > Let me guess, you're always running euid==0. :)\n> Do you also ask the gnu coreutils folks to remove the -f option from their\nutilities?\n\n-- Johannes Gilger wrote:\n> I think the name of the command \"reset\" itself is a name which should\n> prompt everyone to read a manpage before using it. [snip ]\n> Nobody complains about rm --force or anything.\n\nIsn't it nice that they standardized on \"-f\" and \"--force\" across ALL commands?\n\nI would be inclined to talk to coreutils if it was \"rm -f\", \"cp -R\" (vs cp -r),\nand \"mv --aggressive\" to do the respective non-safe versions.\n\nIt would simplify git's command-line-ui and cognitive load if it did the same\nthing. Pick one standard for \"overriding dangerous commands\", instead of\n\"danger caps\" and \"danger --reset\" and \"danger -f\". Consider branch which has\nboth \"branch -[MD]\" and \"branch -f\" in the same subcommand. What's wrong with\n\"branch -[md] -f\"?\n\nOf course --hard encourages one to read the manpage. However, git is using a\nbunch of new terms for things, and uses at least those three different methods\nto indicate command danger. Lets look at the working on the manpage:\n\n\"Matches the working tree and index to that of the tree being\nswitched\nto. Any changes to tracked files in the working tree since <commit>\nare lost.\"\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nI interpreted this as \"any [non committed changes] to tracked files in the\nworking tree since <commit> are lost.\"  I don't this this was a naive\ninterpretation. I still think that's the way it reads after this whole\nconversation.\n\nI'll work on my first patch for git:\n\n-> \"References to any working tree changes, and pulled changes, AND COMMITTED\nCHANGES to tracked files in the branch after <commit> will be dropped, causing\nthem to be removed at the next garbage collect.\".\n\n-- Brandon Casey wrote:\n> After saying all of that, here is how I think you _should_ have done things.\n> Notice I _did_not_ use 'reset --hard'.\n\nI was told that I can safely do \"git checkout origin/master\" instead of \"reset\n--hard\" to get back to the pull point, in case I didn't branch ahead of time.\nThe wrinkle being that my \"master\" branch-pointer still points to my local\nchanges, so I need to move onto a different branchname before I push if I want\nto avoid those changes going to the server, which is fine..\n\n> git clone <master_repo>\n> cd master_repo\n> git checkout -b feature1 # we create our feature branch immediately since\n> # creating branches is so effortless in git. A\n> # private feature branch should _always_ be created\n> # and used for development.\n\nI'm beginning to see why I would always work this way, though if \"private\nfeature branches should always be created and used for development\", then I'm\nunclear about why this isn't the default. git could implicitly create them when\nI checkin a change on the head of a pulled branch. (i.e. user/branchname/id, or\nsomething else). I'm reaching here, I'll need to use git more with other\ndevelopers to understand this better.\n\n-------------------\nThanks again for all the detailed responses and explanations!\n\n- David\n"}]}