{"thread":{"id":"14112","subject":"Re: why is git destructive by default? (i suggest it not be!)","startedAt":"2008-06-24T02:01:19Z","lastAt":"2016-08-14T00:46:00Z","messageCount":100,"participants":["David Jeske","Nicolas Pitre","Avery Pennarun","Jan Krüger","Jeff King","Jakub Narebski","Lea Wiemann","Fedor Sergeev","Rogan Dawes","Johannes Gilger","Theodore Tso","Boaz Harrosh","Brandon Casey","Steven Walter","Junio C Hamano","Johannes Schindelin","Matthias Kestenholz","Johannes Sixt","Anton Gladkov","Ian Hilt","Craig L. Ching","Petr Baudis","Andreas Ericsson","Björn Steinbrink","Matthieu Moy","David Kastrup","Jon Loeliger","しらいしななこ"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"80805","messageId":"29266.7213514962$1214273195@news.gmane.org","threadId":"14112","inReplyTo":"jeske@willow=01l5V7waFEDjChmh","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-24T02:01:19Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"As a new user, I'm finding git difficult to trust, because there are operations\nwhich are destructive by default and capable of inadvertently throwing hours or\ndays of work into the bit bucket.\n\nMore problematic, those commands have no discernible pattern that shows their\ndanger, and they need to be used to do typical everyday things. I'm starting to\nfeel like I need to use another source control system on top of the git\nrepository in case I make a mistake.  My philosophy is simple, I never never\nnever want to throw away changes, you shouldn't either. Disks are cheaper than\nprogrammer hours. I can understand wanting to keep things tidy, so I can\nunderstand ways to correct the 'easily visible changes', and also avoid pushing\nthem to other trees, but I don't understand why git needs to delete things.\n\nFor example, the following commands seem capable of totally destroying hours or\ndays of work. Some of them need to be used regularly to do everyday things, and\nthere is no pattern among them spelling out danger.\n\ngit reset --hard          : if another branch name hasn't been created\ngit rebase\ngit branch -D <branch>    : if branch hasn't been merged\ngit branch -f <new>       : if new exists and hasn't been merged\ngit branch -m <old> <new> : if new exists and hasn't been merged\n\nI've heard from a couple users that the solution to these problems is to \"go\ndig what you need out of the log, it's still in there\". However, it's only in\nthere until the log is garbage collected. This either means they are\ndestructive operations, or we expect \"running without ever collecting the log\"\nto be a valid mode of operation... which I doubt is the case.\n\nQuestion: How about assuring ALL operations can be done non-destructivly by\ndefault? Then make destructive things require an explicit action that follows a\ncommon pattern.\n\nSuggestion Illustration\n-----------------------\n\nBelow is one illustration of how these commands could be changed to be entirely\nnon-destructive, while retaining the current functionality. It also allows you\nto destroy stuff if you have lawyers breathing down your neck, or really really\ncan't afford the hard drive space for a couple lines of text (though I'll\npersonally make a donation to anyone in this state!) :)\n\n1) Require the \"--destroy\" flag for ANY git operation which is capable of\ndestroying data such that it is unrecoverable. A narrow view of this is to only\nconsider checked-in repository data, and not metadata, such as the location of\na branchname. However, the broad view would be to include all/most metadata.\n\n2) Make a pattern for branch names which are kept in the local tree, not\nincluded in push/pull, not modifiable without first renaming, and not shown by\ndefault when viewing all branch history. For example, \"local-<date>-*\"\n\n3) make 'git reset --hard <commit>' safe\n\nAutomatically commit working set and make a branch name (if necessary) to avoid\nchanges being thrown away. The branch name could be of the form\n\"local-<date>-reset-<user>-<date>\". If the user really wants to destroy it,\nthey could use the dangerous version \"git reset --hard --destroy\", or they\ncould just \"git branch -d --destroy <branchname>\" afterwords. Most users would\ndo neither.\n\n4) make 'git rebase' safe\n\n'rebase' would make a branch name before performing its operation, assuring it\nwas easy to get back to the previous state. Currently, \"git rebase\" turns this:\n\nA---B---C topic\n/\nD---E---F---G master\n\nInto this:\n\nA'--B'--C' topic\n/\nD---E---F---G master\n\n.. and in turn destroys the original changes. It would instead create this:\n\nA--B--C (x)    A'--B'--C' (y)\n/              /\nD---E------F-------G master\n\n(x) - local-<date>-rebase-topic-<commit for G>\n(y) - topic\n\n5) make 'git branch' follow rule 1 above (safe without --destroy)\n\nUsing any of the following commands without --destroy would cause them to\ncreate a branch \"local-<date>-rename-<old branch name>\", to prevet the\ndestruction of the old branch location:\n\ngit branch -d <branchname>\ngit branch -M <old> <new>\ngit branch -f <branchname>\n"},{"id":"80818","messageId":"alpine.LFD.1.10.0806232213360.2979@xanadu.home","threadId":"14112","inReplyTo":"willow-jeske-01l5cKsCFEDjC=91MX@videotron.ca","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2008-06-24T02:17:41Z","receivedAt":"2008-06-24T02:17:41Z","isPatch":false,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Tue, 24 Jun 2008, David Jeske wrote:\n\n> I've heard from a couple users that the solution to these problems is to \"go\n> dig what you need out of the log, it's still in there\". However, it's only in\n> there until the log is garbage collected. This either means they are\n> destructive operations, or we expect \"running without ever collecting the log\"\n> to be a valid mode of operation... which I doubt is the case.\n\nWhy not?\n\n> Question: How about assuring ALL operations can be done non-destructivly by\n> default?\n\n\tgit config --global gc.reflogexpire \"2 years\"\n\n\nNicolas\n"},{"id":"80823","messageId":"153.722326695238$1214278017@news.gmane.org","threadId":"14112","inReplyTo":"alpine.LFD.1.10.0806232213360.2979@xanadu.home","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-24T02:21:44Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Nicolas Pitre wrote:\n>> or we expect \"running without ever collecting the log\"\n>> to be a valid mode of operation... which I doubt is the case.\n>\n> Why not?\n\nIs see the hole I left in my logic, so let me restate.\n\n... or we expect \"human parsing of the the log\" is a valid common\nuser-interface for non-git developers.\n"},{"id":"80824","messageId":"alpine.LFD.1.10.0806232356340.2979@xanadu.home","threadId":"14112","inReplyTo":"willow-jeske-01l5e9cgFEDjCh3F@videotron.ca","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2008-06-24T04:03:52Z","receivedAt":"2008-06-24T04:03:52Z","isPatch":false,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Tue, 24 Jun 2008, David Jeske wrote:\n\n> -- Nicolas Pitre wrote:\n> >> or we expect \"running without ever collecting the log\"\n> >> to be a valid mode of operation... which I doubt is the case.\n> >\n> > Why not?\n> \n> Is see the hole I left in my logic, so let me restate.\n> \n> ... or we expect \"human parsing of the the log\" is a valid common\n> user-interface for non-git developers.\n\nThe reflog is one of the primary user interface for all git users. \nPlease just try:\n\n\tgit reflog\n\nand see for yourself.\n\nAnd if you want more details, then just try:\n\n\tgit log -g\n\nYou may even try any combination of flags in addition to -g with\n'git log'.\n\nI hope you'll feel much safer then.\n\n\nNicolas\n"},{"id":"80827","messageId":"31555.0678795718$1214283260@news.gmane.org","threadId":"14112","inReplyTo":"alpine.LFD.1.10.0806232356340.2979@xanadu.home","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-24T04:49:55Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Nicolas Pitre wrote:\n> I hope you'll feel much safer then.\n\nI moved a branch around and then deleted it, and I don't see any record in the\nreflog of where it was, or that it ever was.\n\nAm I missing something about how branches are used? I see some language in \"git\ntag\" about how attempts are made to assure that others can't move around\nsemi-immutable tags during push, but I don't see any such language about\nbranches. What prevents someone from accidentally deleting an old branch that\nnobody is watching, but is important to the history and then not noticing as gc\nsilently deletes the old deltas?\n\nI've had need to pull out versions several years old multiple times in my\ncareer, so this is the kind of thing I'm thinking about.\n\ngit config --global gc.reflogexpire            \"10 years\"'\ngit config --global gc.reflogexpireunreachable \"10 years\"\n\nMakes me feel safer that the data will be in there, but even with the reflog\nand access to the repository, I doubt I could FIND the place an old branch was\nsupposed to be if it was inadvertently deleted in a 2-million line source tree.\nAm I just looking in the wrong places?\n"},{"id":"80831","messageId":"32541b130806232220r292d691cn5bf5f9976126aa29@mail.gmail.com","threadId":"14112","inReplyTo":"1978205964779154253@unknownmsgid","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2008-06-24T05:20:06Z","receivedAt":"2008-06-24T05:20:06Z","isPatch":false,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On 6/24/08, David Jeske <jeske@google.com> wrote:\n> I moved a branch around and then deleted it, and I don't see any record in the\n>  reflog of where it was, or that it ever was.\n>\n>  Am I missing something about how branches are used? I see some language in \"git\n>  tag\" about how attempts are made to assure that others can't move around\n>  semi-immutable tags during push, but I don't see any such language about\n>  branches. What prevents someone from accidentally deleting an old branch that\n>  nobody is watching, but is important to the history and then not noticing as gc\n>  silently deletes the old deltas?\n>\n>  I've had need to pull out versions several years old multiple times in my\n>  career, so this is the kind of thing I'm thinking about.\n\ngit branches are actually a very different concept from branches in,\nsay, subversion.\n\nIn subversion, a branch is normally created so that you can do\nparallel development, and then you merge whole batches of changes\n(with 'svn merge') from one branch into another.  When you do this,\nyou create a single new commit in the destination branch that contains\n*all* the changes.  So if you want to look back in history to see who\ndid which part of the change for what reason, you have to go back to\nthe branch you merged *from*.  Thus, it's very important in subversion\nthat old branches never disappear.\n\ngit's philosophy is different.  Branches are really just \"temporary\ntags\".  A merge operation doesn't just copy data from one branch to\nanother: it actually joins the two histories together, so you can then\ntrace back through the exact history of the merged branches, commit by\ncommit.  \"git log\" will show each checkin to *either* branch\nindividually, instead of just one big \"merge\" checkin.\n\nThe end result is that even if you delete the source branch after\ndoing a merge, nothing is actually lost.  Thus, there's no reason for\ngit to try to make branches impossible to lose, as they are in svn.\nIn the event that you really needed that branch pointer, it's in the\nreflog, as a few people have pointed out.\n\nAnother way to think of it is that svn's concept of a \"branch\" is\nactually the \"reflog\" in git.  (svn records which data a particular\nbranch name points to over time, just like git's reflog does.)  git\nbranches are something else entirely; a git branch always points at\nonly a single commit, and has no history of its own.\n\nDoes that help?  Perhaps it only confuses the issue :)\n\nHave fun,\n\nAvery\n"},{"id":"80832","messageId":"20080624072409.5d499722@neuron","threadId":"14112","inReplyTo":"willow-jeske-01l5g9o4FEDjCXMB","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jan Krüger","fromEmail":"jk@jk.gs","sentAt":"2008-06-24T05:24:09Z","receivedAt":"2008-06-24T05:24:09Z","isPatch":false,"sender":{"key":"jk@jk.gs","avatar":"https://avatars.githubusercontent.com/u/1774?v=4"},"body":"Hi David,\n\n\"David Jeske\" <jeske@google.com> wrote:\n> I moved a branch around and then deleted it, and I don't see any\n> record in the reflog of where it was, or that it ever was.\n\nIf a branch you're trying to delete is not part (or, more correctly,\nan ancestor) of your current branch, you'll get a warning that you have\nto explicitly bypass by using -D rather than -d.\n\nStill, after deleting the branch, its old tip will very likely show up\nin the reflog for HEAD (at the point you last worked on the branch),\neven if the branch name won't show up anywhere. After locating the\ncommit in there it's a simple case of git checkout -b whatever\nHEAD@{123} to get back that branch.\n\n> What prevents someone from accidentally deleting an old branch that\n> nobody is watching, but is important to the history and then not\n> noticing as gc silently deletes the old deltas?\n\nOne thing to keep in mind is that deleting your branch locally won't\nrid you of remote copies of it, so anything that you considered worth\nsharing will probably survive even if you accidentally bypassed Git's\nwarning about deleting branches.\n\nBest,\nJan\n"},{"id":"80839","messageId":"30722.0091614456$1214290702@news.gmane.org","threadId":"14112","inReplyTo":"32541b130806232220r292d691cn5bf5f9976126aa29@mail.gmail.com","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-24T06:46:14Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"Thanks for all the helpful responses...\n\n-- Avery Pennarun wrote:\n> git's philosophy is different. Branches are really just \"temporary\n> tags\". A merge operation doesn't just copy data from one branch to\n> another: it actually joins the two histories together, so you can then\n> trace back through the exact history of the merged branches, commit by\n> commit. \"git log\" will show each checkin to *either* branch\n> individually, instead of just one big \"merge\" checkin.\n\nIf branches are \"temporary tags\" how do I see the actual code they had working\nin their branch before they merged it?\n\nI'm reading about rebase, and it sounds like something I would want to forever\ndisallow on my git repository, because it looks like it rewrites history and\nmakes it impossible to get to the state of the tree they actually had working\nbefore the merge. However, something you say below both clarifies and confuses\nthis.\n\nAm I understanding this wrong?\n\n> The end result is that even if you delete the source branch after\n> doing a merge, nothing is actually lost.\n\n..and what if you never merge? That branch-pointer points to useful information\nabout a development attempt, but it was never merged. (imagine a different\ndevelopment path was taken) They never created a tag because it's not clear\nwhen that work was \"done\" (unlike a release, which is much more well\nunderstood). What prevents someone from deleting the branch-pointer or moving\nit to a different part of the tree, causing that set of changes to be a\ndangling ref lost in a sea of refs. Later when someone goes back looking for\nit, how would they ever find it in a sea of tens of thousands of checkins?\n\n> Thus, there's no reason for git to try to make branches impossible\n> to lose, as they are in svn.\n\nBefore I set the GC times to \"100 years\", there was a HUGE reason for git to\nmake those branch-pointers impossible to lose, because by default if you lose\nthem git actually garbage collects them and throws the diffs away after 90\ndays!\n\n> Another way to think of it is that svn's concept of a \"branch\" is\n> actually the \"reflog\" in git. (svn records which data a particular\n> branch name points to over time, just like git's reflog does.) git\n> branches are something else entirely; a git branch always points at\n> only a single commit, and has no history of its own.\n\nThat's sort of helpful, and sort of confusing. I think of git's branches as\n\"branch pointers to the head of a linked-list of states of the tree\".\n\nAs long as you keep those refs without deleting them, and you keep that branch\npointer to the head, you can walk back through the history of that branch. If\nmultiple developers are working in the branch (and not using rebase, and not\ngarbage collecting), can't you even go track down the working state of their\nlocal clients while they were working before they merged?\n\nIf I'm understanding all that right, it's exactly the kind of functionality I\nwant -- the ability to reproduce the state of all working history, exactly as\nit was when the code was actually working in someone's client a long time ago,\nbefore they merged it to the mainline. Except the standard model seems to be to\nlet the system \"garbage collect\" all that history, and toss it away as\nunimportant -- and in some cases it seems to even provide developers with ways\nto more aggressively assure garbage collection makes it disappear.\n\nAm I expecting too much out of git? It doesn't really feel like a source\ncontrol system for an organization that wants to save everything, forever, even\nwhen those people and trees and home directories disappear. It feels like a\ndistributed patch manager that is much more automatic than sending around\ndiffs, but isn't overly concerned with providing access to old history. (which,\nduh, is no surprise given that's what I expect it's doing for linux kernel)\n"},{"id":"80840","messageId":"20080624072455.GF19224@sigill.intra.peff.net","threadId":"14112","inReplyTo":"willow-jeske-01l5izRzFEDjCdyL","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-06-24T07:24:55Z","receivedAt":"2008-06-24T07:24:55Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jun 24, 2008 at 06:35:16AM -0000, David Jeske wrote:\n\n> If branches are \"temporary tags\" how do I see the actual code they had\n> working in their branch before they merged it?\n\nYou look at the shape of the history. But if it is really an important\nevent for you to say \"this was the state right before some merge of\ninterest\", then by all means, tag it with a real tag. Or don't delete\nthe branch.\n\nHave you tried running gitk on the kernel or git repositories?\n\n> I'm reading about rebase, and it sounds like something I would want to\n> forever disallow on my git repository, because it looks like it\n> rewrites history and makes it impossible to get to the state of the\n> tree they actually had working before the merge. However, something\n> you say below both clarifies and confuses this.\n\nIt does throw away the state before the rebase (well, there is no longer\na pointer to it; it is still recoverable via the reflog). But for most\npush/pull collaboration, you probably want to be using merge. Rebase is\nmore useful for people who are more accustomed to a patch-based\nworkflow.\n\n> > The end result is that even if you delete the source branch after\n> > doing a merge, nothing is actually lost.\n> \n> ..and what if you never merge? That branch-pointer points to useful\n> information about a development attempt, but it was never merged.\n> (imagine a different development path was taken) They never created a\n> tag because it's not clear when that work was \"done\" (unlike a\n> release, which is much more well understood). What prevents someone\n> from deleting the branch-pointer or moving it to a different part of\n> the tree, causing that set of changes to be a dangling ref lost in a\n> sea of refs. Later when someone goes back looking for it, how would\n> they ever find it in a sea of tens of thousands of checkins?\n\nIf it's not merged, then don't delete the branch pointer! And \"git\nbranch -d\" will even refuse to do the deletion, unless you force it with\n\"git branch -D\".\n\nAnd keep in mind that when you clone repos, you clone the branch\npointer. So if you have a centralized server that your developers push\nand pull from, a stray \"git branch -D\" from one developer _doesn't_ ruin\nit for the rest of them. All that does is delete the branch from their\nlocal repo, but it still exists in the central repo and for all of the\nother developers. But it's not clear to me what sort of developer\ntopology you're interested in.\n\n> Before I set the GC times to \"100 years\", there was a HUGE reason for git to\n> make those branch-pointers impossible to lose, because by default if you lose\n> them git actually garbage collects them and throws the diffs away after 90\n> days!\n\nI think most people are comfortable with \"if I have an unmerged branch,\nit stays forever. If I accidentally delete my branch, I have 30 days to\npull the tip out of my reflog\". Sure, it's _possible_ to lose work. But\nyou could also accidentally \"rm -rf\" your .git directory. If you want an\nextra layer of protection, push your work periodically to a backup repo.\n\n> That's sort of helpful, and sort of confusing. I think of git's branches as\n> \"branch pointers to the head of a linked-list of states of the tree\".\n\nMore or less true (they aren't linked-list, but arbitrary DAGs --\ncommits can have more than one parent (i.e., a merge) and can have many\nchildren (i.e., many people build off in different directions from one\nspot)).\n\n> If I'm understanding all that right, it's exactly the kind of\n> functionality I want -- the ability to reproduce the state of all\n> working history, exactly as it was when the code was actually working\n> in someone's client a long time ago, before they merged it to the\n> mainline. Except the standard model seems to be to let the system\n> \"garbage collect\" all that history, and toss it away as unimportant --\n> and in some cases it seems to even provide developers with ways to\n> more aggressively assure garbage collection makes it disappear.\n\nI think you are confusing two aspects of history.\n\nThere is the commit DAG, which says \"at some time T, the files were at\nsome state S, and the commit message by author A was M\". And those\ncommits form a chain so you can see how the state of the files\nprogressed. And anything that is reachable through that history will\nalways be kept by git, and you can always go back to any point.\n\nBut we also give particular names to some points, like \"this is tag\nv1.0\" or \"this is the head of the experimental line of development\". We\ncall those refs.  Git remembers those names until you ask it not to (by\ndeleting the ref).  And there is a history to those names, like\n\"experimental was at some commit C1. Then somebody committed and it was\nat C2. And then they did a git-reset and it was at C3\". And that history\nis encapsulated in the reflog, and is purely local to each repository\n(since git is distributed, it makes no sense to talk about \"where the\nexperimental name pointed\" without talking about a specific repo).\n\nAnd the ref history is what gets garbage collected. Most people are fine\nwith that, because they care about the actual commit history, and the\nreflog is just a convenient way of saying \"oops, what was happening\nyesterday?\" But if you really care, then by all means, set the reflog\nexpiration much higher.\n\n> Am I expecting too much out of git? It doesn't really feel like a\n> source control system for an organization that wants to save\n> everything, forever, even when those people and trees and home\n> directories disappear. It feels like a distributed patch manager that\n> is much more automatic than sending around diffs, but isn't overly\n> concerned with providing access to old history. (which, duh, is no\n> surprise given that's what I expect it's doing for linux kernel)\n\nGit _will_ remember content forever, _if_ you put into git. So if you\nare saying \"git won't remember work that employee X did after he is\ngone\", that isn't true. X's work will be part of the commit DAG and will\nbe a part of everybody's repo. If you are saying \"I blew away employee\nX's home directory, and he had a git repo in it, why didn't git save\nthat data?\" then the problem is that you deleted the repo! If you are\nconcerned about that situation, have employee X push his work to a repo\nthat doesn't get deleted.\n\n-Peff\n"},{"id":"80844","messageId":"m3mylbl0xb.fsf@localhost.localdomain","threadId":"14112","inReplyTo":"32541b130806232220r292d691cn5bf5f9976126aa29@mail.gmail.com","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-24T07:54:38Z","receivedAt":"2008-06-24T07:54:38Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"It looks like for some reason not all messages made it to git mailing\nlist, at least when using GMane to read git mailing list.  Strange...\n\n\"Avery Pennarun\" <apenwarr@gmail.com> writes:\n> On 6/24/08, David Jeske <jeske@google.com> wrote:\n\n>> I moved a branch around and then deleted it, and I don't see any\n>> record in the reflog of where it was, or that it ever was.\n\nDeleting branch (BTW. git prints warning when deleting branch can\nresult in [temporary] loss of [easy access to] some commits) deletes\nits reflog[*1*], but you can still use HEAD reflog (\"what was checked\nout\" reflog).\n\n>> Am I missing something about how branches are used? I see some\n>> language in \"git tag\" about how attempts are made to assure that\n>> others can't move around semi-immutable tags during push, but I\n>> don't see any such language about branches. What prevents someone\n>> from accidentally deleting an old branch that nobody is watching,\n>> but is important to the history and then not noticing as gc\n>> silently deletes the old deltas?\n\nBTW. branches _deletions_ are not by default transferred (even if\nusing globbing refspecs, which is not default); you have to use \n\"git remote prune <remote nick>\" to remove remote-tracking branches\nwhich track branches that got deleted on remote.\n\nBesides nobody and nothing can fully protect you from your stupidity.\nYou can \"accidentally\" do 'rm -rf .git' for example :-/\n\n>> I've had need to pull out versions several years old multiple times\n>> in my career, so this is the kind of thing I'm thinking about.\n\nThe answer is: don't delete branches accidentally ;-).\n\nSeriously, in any sane workflow you have several long lasting\nbranches, be it 'maint', 'master', 'next' or be it 'maintenance',\n'stable'/'mainline'/'trunk', 'devel', into whose you merge in\n[temporary, short lived] topic branches when topic is ready for\ninclusion.  And you NEVER delete such branches (git can't protect you\nfrom deletion any more than Linux can protect you if you do \"rm -rf ~\"). \n\nAny commit for whose there is parentage line from one of those\nlong-lived \"development\" branches would be protected from pruning\nduring git-gc run.\n\n> git branches are actually a very different concept from branches in,\n> say, subversion.\n> \n> In subversion, a branch is normally created so that you can do\n> parallel development, and then you merge whole batches of changes\n> (with 'svn merge') from one branch into another.  When you do this,\n> you create a single new commit in the destination branch that contains\n> *all* the changes.  So if you want to look back in history to see who\n> did which part of the change for what reason, you have to go back to\n> the branch you merged *from*.  Thus, it's very important in subversion\n> that old branches never disappear.\n> \n> git's philosophy is different.  Branches are really just \"temporary\n> tags\".\n\nI'd rather say thay branches (refs/heads branches) are \"growth points\"\nof graph (diagram) of revisions (versions).  (This graph is called DAG\nin git documentation, because it is Directed Acyclic Graph).\n\nBut it is true that in git branches are just _pointers_ to the DAG\nof commits.  All data is kept in the content addressed object database\nwhich is git repo storage, and parentage links are contained in commit\nobjects.\n\n> A merge operation doesn't just copy data from one branch to\n> another: it actually joins the two histories together, so you can then\n> trace back through the exact history of the merged branches, commit by\n> commit.  \"git log\" will show each checkin to *either* branch\n> individually, instead of just one big \"merge\" checkin.\n\nLet me help explain that using some ASCII-art diagram.  You need to\nuse fixed-width (non-proportional) font to view it correctly.  Time\nflows from the left to right.\n\nLet's assume that we have the following state: some history on branch\n'master': \n\n       object database              refs information\n    /-------------------\\        /---------------------\\\n   \n     .<---.<---.<---A             <--- master <=== HEAD\n\nFor the commits the \"<---\" arrow means that commit on the right side\nof arrow has commit on the left hand side of arrow as its parent\n(saved in the multi-valued \"parent\" field in the commit object).  For\nthe references \"<---\" arrow means that branch master points to given\ncommit, and \"<===\" means symbolic reference, i.e. that ref points to\ngiven branch (you can think of it as symlink, and it was some time ago\nimplemented as such).\n\nNow assume that we created new branch 'test', and we have comitted\nsome revisions being on it:\n\n     .<---.<---.<---A             <--- master\n                     \\\n                      \\-B<---C    <--- test     <=== HEAD\n\nLet's assume that we, or somebody else, did some work on 'master'\nbranch (to not confuse you with the \"fast-formward\" issue):\n\n     .<---.<---.<---A<---X<---Y    <--- master\n                     \\\n                      \\--B<---C    <--- test     <=== HEAD\n\nNow we have finished feature which we tried to develop in 'test', so\nwe merge changes back to 'master':\n\n     .<---.<---.<---A<---X<---Y<---M       <--- master <=== HEAD\n                     \\            /\n                      \\--B<---C<-/         <--- test\n\nNote how merge commit 'M' has two parents.\n\nNow if we were to delete branch 'test' now:\n\n     .<---.<---.<---A<---X<---Y<---M       <--- master [<=== HEAD]\n                     \\            /\n                      \\--B<---C<-/\n\nit is only pointer that gets deleted (and reflog[*1*]).  All commits\nwhich were on this branch are 'reachable', so they never would get\ndeleted, even if [HEAD] reflog expires[*2*].\n\n> The end result is that even if you delete the source branch after\n> doing a merge, nothing is actually lost.  Thus, there's no reason for\n> git to try to make branches impossible to lose, as they are in svn.\n> In the event that you really needed that branch pointer, it's in the\n> reflog, as a few people have pointed out.\n\ns/in the reflog/in the HEAD reflog/.\n\nSee above for explanation with pictures (or if you want some graphics,\ntake a look at presentations linked from GitLinks page and/or\nGitDocumentation page on git wiki, http://git.or.cz/gitwiki/).\n\nHTH\n\nFootnotes:\n==========\n[*1*] There was an effort to create some sort of 'Attic' / 'trash can'\nfor deleted reflogs, but I guess it got stalled.  There is techical\nissue caused by the fact that reflogs are stored as files, and you can\nhave so caled file<->directory conflict, when you deleted branch\n'foo', and created branch 'foo/bar'.\n\n[*2*] You can always write \"never\" as time to expire, and it even\nworks now ;-)\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"80847","messageId":"26121.2761899971$1214294979@news.gmane.org","threadId":"14112","inReplyTo":"20080624072455.GF19224@sigill.intra.peff.net","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-24T08:04:38Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Jeff King wrote:\n> I think you are confusing two aspects of history.\n>\n> There is the commit DAG, which says \"at some time T, the files were at\n> some state S, and the commit message by author A was M\". And those\n> commits form a chain so you can see how the state of the files\n> progressed. And anything that is reachable through that history will\n\nokay.\n\n> always be kept by git, and you can always go back to any point.\n\n..are you saying that if I reset --hard, or delete a branch ref, or do a\nrebase, and then do a GC beyond the GC timeout, that git will NEVER throw away\nany of those DAGs? (the actual source diffs committed)\n\n> And the ref history is what gets garbage collected. Most people are fine\n> with that, because they care about the actual commit history, and the\n> reflog is just a convenient way of saying \"oops, what was happening\n> yesterday?\" But if you really care, then by all means, set the reflog\n> expiration much higher.\n\nMy (possibly flawed) understanding was that it drops any DAG sections that are\nnot referenced by valid refs which are older than the GC timeout.\n\nIt came from wording like this in the docs:\n\n\"The optional configuration variable gc.reflogExpireUnreachable\ncan be set to indicate how long historical reflog entries which\nare not part of the current branch should remain available in\nthis repository. These types of entries are generally created\nas a result of using git commit --amend or git rebase and are the\ncommits prior to the amend or rebase occurring. Since\nthese changes are not part of the current project most users\n^^^^^^^^^^^^^\nwill want to expire them sooner. This option defaults to 30 days.\"\n\nIn the above, I resolve \"these changes\" to \"commits prior to the amend\" in the\nprevious sentence.\n\n\"git-gc tries very hard to be safe about the garbage it collects.\nIn particular, it will keep not only objects referenced by your\ncurrent set of branches and tags, but also objects referenced by\nthe index, remote tracking branches, refs saved by\ngit-filter-branch(1) in refs/original/, or reflogs (which may\nreferences commits in branches that were later amended or rewound).\"\n\nIn the above, I resolve \"keep .. only objects referenced by your current set of\nbranches and tags [and some other stuff]\" to \"commmits in the DAG pointed to by\nrefs [and other stuff]\".\nAre you saying this GC process will never collect source diffs in the DAG?\n"},{"id":"80850","messageId":"4860ACC9.3050407@gmail.com","threadId":"14112","inReplyTo":"willow-jeske-01l5e9cgFEDjCh3F","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Lea Wiemann","fromEmail":"lewiemann@gmail.com","sentAt":"2008-06-24T08:14:01Z","receivedAt":"2008-06-24T08:14:01Z","isPatch":false,"sender":{"key":"lewiemann@gmail.com","avatar":null},"body":"David Jeske wrote:\n> ... or we expect \"human parsing of the the log\" is a valid common\n> user-interface for non-git developers.\n\nAs a side note, the reflog is not only a valid user interface, but an \nimportant one: As a local developer that feeds patches to the mailing \nlist, I frequently change the history in my local repository (using \nrebase, reset and am, or pull --rebase) to keep the commits clean when \nthey finally get merged upstream.  I *want* and *need* at least basic \nversioning for the various states my history is in.\n\nIOW, I not only make changes to the tree and commit them to my master \nbranch, but I also make changes to my master branch and \"commit\" them to \n(store them in) the reflog.\n\nThat's not an interesting use case if you're working on a branch that \nother people pull from, but for a local clone it's very useful.  (And \nit's a feature I haven't seen in any VCSes, FWIW.)\n\nBest,\n\n     Lea\n"},{"id":"80851","messageId":"20080624081601.GA2692@sigill.intra.peff.net","threadId":"14112","inReplyTo":"willow-jeske-01l5kbGzFEDjCX3J","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-06-24T08:16:02Z","receivedAt":"2008-06-24T08:16:02Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jun 24, 2008 at 07:31:31AM -0000, David Jeske wrote:\n\n> ..are you saying that if I reset --hard, or delete a branch ref, or do a\n> rebase, and then do a GC beyond the GC timeout, that git will NEVER throw away\n> any of those DAGs? (the actual source diffs committed)\n\nNo. Git keeps the reachable DAG. So if the DAG is part of development\nthat is merged into one of your long running branches, or if you keep\naround the branch that points to it, it will never go away.\n\n> My (possibly flawed) understanding was that it drops any DAG sections\n> that are not referenced by valid refs which are older than the GC\n> timeout.\n\nYes. So the way to \"forget\" about some history is to stop referencing\nit. And then, after a grace period, it will be removed.\n\n> Are you saying this GC process will never collect source diffs in the\n> DAG?\n\nNo, but it will only remove unreferenced things. And things only become\nunreferenced through explicit user action. So you don't have to worry\nabout git GCing your work unexpectedly. You do have to worry about git\nGCing things you have explicitly told it to delete.\n\n-Peff\n"},{"id":"80853","messageId":"47013.6552271017$1214295841@news.gmane.org","threadId":"14112","inReplyTo":"m3mylbl0xb.fsf@localhost.localdomain","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-24T08:16:15Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"To re-ask the same question I asked in my last post, using your ascii\npictures...\n\n\nLet's assume we're here..\n\n.<---.<---.<---A<---X<---Y    <--- master\n\\\n\\--B<---C    <--- customer_A_branch <=== HEAD\n\n\nAnd this person and everyone else moves their head pointers back to master\nwithout merging:\n\n\n.<---.<---.<---A<---X<---Y    <--- master              <=== HEAD\n\\\n\\--B<---C    <--- customer_A_branch\n\n\nNow, five years down the road, our tree looks like:\n\n\n.<---A<---X<---Y<---.<--.<--.(3 years of changes)<---ZZZ<--- master  <=== HEAD\n\\\n\\--B<---C   <--- customer_A_branch\n\nAnd someone does:\n\ngit-branch -f customer_A_branch ZZZ\n\nTo bring us to:\n\n.<---A<---X<---Y<---.<--.(3 years of changes)<---ZZZ<--- master  <=== HEAD\n\\                                           \\\n\\--B<---C                                   \\-- customer_A_branch\n\n\n..at this point, will a GC keep \"B<--C\", or garbage collect the commits and\nthrow them away?\n"},{"id":"80857","messageId":"15381.9593288519$1214297235@news.gmane.org","threadId":"14112","inReplyTo":"20080624081601.GA2692@sigill.intra.peff.net","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-24T08:37:41Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"This is mostly moot since I've understood that it's easy to set git to never\nGC. I guess I'm curious about why those GC fields would ever be set to anything\nother than never?\n\n-- Jeff King wrote:\n> No. Git keeps the reachable DAG. So if the DAG is part of development\n> that is merged into one of your long running branches, or if you keep\n> around the branch that points to it, it will never go away.\n\nRight, that's what I thought.\n\nI'm not primarily concerned with what developers can do to their local git\nrepositories. I'm concerned with what the default sync operations can let them\ndo to the crown-jewels in the 'central organization repositories' which\neveryone is periodically pushing to.\n\nI like that deleting a branch in your repo does not cause it to be deleted in\nother repos. Presumably in an  organization we could prevent the central repo\nfrom ever accepting branch deletes from developers. (without some kind of\nauthorization)\n\nDoes it have the same protection for all operations that can cause DAGs to be\ndangling? For example, if they branch -f\" and push the branch?\n\n---\n\nAgain it's simple enough for me to just set the GC times to \"never\" on the\nserver, and I find git pretty pleasing because I'm a\nshort-attention-span-comitter. On a perforce or cvs repository, I frequently\ntar up subtrees between commits, so i don't lose my work -- git is light-years\nahead of this.\n\nQuite a bit of my fear of losing data came from some issues in the git-gui. I'm\ntrying out git on a windows project, and windows-shells just don't work right,\nso I'm using the \"Git Gui\". It turns out right-clicking on a history entry in\nthe gui has no checkout option, and the only option it does have which will let\nyou move the tree to that place is \"reset --hard\".. since this was the easiest\nthing to find in the GUI, I assumed it was the right way to do it, and then all\nmy more recent changes disappeared. It doesn't seem to have reflog\nfunctionality, so I couldn't find any way to get back all my changes. I ended\nup having an old history window that I did another reset --head in back to the\nlatest change, but I got scared about what git was doing underneath. The docs\nclearly explained that it will garbage collect dangling refs, and frankly the\ninformation about how often this happens is buried so deep I had no idea what\nthe frequency was.\n"},{"id":"80867","messageId":"m3ej6nkw2u.fsf@localhost.localdomain","threadId":"14112","inReplyTo":"15381.9593288519$1214297235@news.gmane.org","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-24T09:39:20Z","receivedAt":"2008-06-24T09:39:20Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"\"David Jeske\" <jeske@google.com> writes:\n\n> This is mostly moot since I've understood that it's easy to set git\n> to never GC. I guess I'm curious about why those GC fields would\n> ever be set to anything other than never?\n\nBecause not everybody has unlimited quota / unlimited disk space?\nBesides growing repository, reflogs also grow even if you shitch\nbetween some limited set of commits.\n\nNote however that IIRC reflogs are not enabled by default for bare\nrepositories, and public repositories should be bare (without working\ndirectory).  But see receive.denyNonFastForwards below.\n\n> -- Jeff King wrote:\n> >\n> > No. Git keeps the reachable DAG. So if the DAG is part of development\n> > that is merged into one of your long running branches, or if you keep\n> > around the branch that points to it, it will never go away.\n> \n> Right, that's what I thought.\n> \n> I'm not primarily concerned with what developers can do to their\n> local git repositories. I'm concerned with what the default sync\n> operations can let them do to the crown-jewels in the 'central\n> organization repositories' which everyone is periodically pushing\n> to.\n> \n> I like that deleting a branch in your repo does not cause it to be\n> deleted in other repos. Presumably in an organization we could\n> prevent the central repo from ever accepting branch deletes from\n> developers. (without some kind of authorization)\n> \n> Does it have the same protection for all operations that can cause\n> DAGs to be dangling? For example, if they branch -f\" and push the\n> branch?\n\ngit-config(1)\n\n  receive.denyNonFastForwards::\n        If set to true, git-receive-pack will deny a ref update which is\n        not a fast forward. Use this to prevent such an update via a push,\n        even if that push is forced. This configuration variable is\n        set when initializing a shared repository.\n\nThat is even more than protection against leaving some commits\ndangling.  This makes working on top of published branches safe.\n\nIf such all-or-nothing policy is not for you, you can always set-up\nhooks, like shown for example in contrib/hooks/update-paranoid\n\nOr you can use different workflow, where maintainer _pulls_ from other\ndevelopers or groups of developers, or apply (git-am) patches from\nemail.  This way if you screw up, it would be your fault for not\nhaving backups ;-)\n\n[...]\n> Quite a bit of my fear of losing data came from some issues in the\n> git-gui. I'm trying out git on a windows project, and windows-shells\n> just don't work right, so I'm using the \"Git Gui\". It turns out\n> right-clicking on a history entry in the gui has no checkout option,\n\nThis might be result of the fact that in older versions of git you\ncould not checkout arbitrary commit.  You now can use so called\n\"detached HEAD\" (when current branch pointer points directly to the\ncommit, instead of pointing to current branch [name]); note however\nthat comitting on top of detached HEAD is discouraged.\n\n> and the only option it does have which will let you move the tree to\n> that place is \"reset --hard\".. since this was the easiest thing to\n> find in the GUI, I assumed it was the right way to do it, and then\n> all my more recent changes disappeared. It doesn't seem to have\n> reflog functionality, so I couldn't find any way to get back all my\n> changes.\n\nThere is always ORIG_HEAD, which predates reflog introduction, and\ncontains only old \"version\", as in\n\n  $ git reset --hard ORIG_HEAD\n\n\nThat said, it would be nice if git-gui had some reflog interface.\n\n> [...] The docs clearly explained that it\n> will garbage collect dangling refs, and frankly the information\n> about how often this happens is buried so deep I had no idea what\n> the frequency was.\n\ngit-gc(1), section called (suprise, suprise) \"Configuration\".\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"80870","messageId":"alpine.WNT.1.10.0806241343170.3824@theodor","threadId":"14112","inReplyTo":"willow-jeske-01l5lTEoFEDjCVta@brm-avmta-1.central.sun.com","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Fedor Sergeev","fromEmail":"fedor.sergeev@sun.com","sentAt":"2008-06-24T10:01:18Z","receivedAt":"2008-06-24T10:01:18Z","isPatch":false,"sender":{"key":"fedor.sergeev@sun.com","avatar":null},"body":"\nOn Tue, 24 Jun 2008, David Jeske wrote:\n> This is mostly moot since I've understood that it's easy to set git to never\n> GC. I guess I'm curious about why those GC fields would ever be set to anything\n> other than never?\n\nOn Tue, 24 Jun 2008, David Jeske wrote:\n> My philosophy is simple, I never never\n> never want to throw away changes, you shouldn't either. Disks are cheaper than\n> programmer hours. I can understand wanting to keep things tidy, so I can\n> understand ways to correct the 'easily visible changes', and also avoid pushing\n> them to other trees, but I don't understand why git needs to delete things.\n\nIt looks like you are severely restricting your own way of thinking about\na source code management as a source code backup system only.\n\nWhile this might be a valid mindset for a gatekeeper on a public \nrepository it way way restrictive for a developer that wants to have a \nsystem that helps him doing a job.\nAnd, say, for me, for my own job, ability to experiment *safely* and \neffectively, ability to try out different histories is the most valuable\nasset that git brings to the world of SCMs.\n\nMy collegues that were forced to use Mercurial for their job are really \nunhappy about Mercurial's habbit of not modifying history at all.\nAfter a certain amount of time just looking at the history of an actively \ndeveloped project causes a headache.\n\n\nWhen you speak about allowing/disallowing destructive actions you actually\nspeak about policies.\nDifferent organizations, different repositories have different policies.\nAnd git is very flexible in allowing you to implement all those different\npolicies as you wish it.\n\nAnd whether default policy should allow people to experiment freely or not\nis a very delicate question, which I would not really have enough courage\nto speculate on.\n\nregards,\n   Fedor.\n\nP.S. Saying all that, I would really like to have an easy way to tie non-default\npolicies to repositories so it propagates on clones. It is really helpful\nin big organizations. But thats another story.\n"},{"id":"80869","messageId":"e80d075a0806240324j79f872d3t1db9dfb87dc2d37c@mail.gmail.com","threadId":"14112","inReplyTo":"alpine.WNT.1.10.0806241343170.3824@theodor","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"David Jeske","fromEmail":"jeske@google.com","sentAt":"2008-06-24T10:24:00Z","receivedAt":"2008-06-24T10:24:00Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"On Tue, Jun 24, 2008 at 3:01 AM, Fedor Sergeev <Fedor.Sergeev@sun.com> wrote:\n> It looks like you are severely restricting your own way of thinking about\n> a source code management as a source code backup system only.\n>\n> While this might be a valid mindset for a gatekeeper on a public repository\n> it way way restrictive for a developer that wants to have a system that\n> helps him doing a job.\n\nOdd. I've never been a gatekeeper. I'm just a developer who has burned\nhimself enough times that I want a tool (i.e. source control) to help\nprevent me from ever destroying anything I create. I like that git is\ndoing nicer things with merge tracking than older systems, and that\nit's easier for distributed teams to move changes around in more\ninteresting ways than \"up to the server\" and \"down from the server\".\nHowever, I also want it to provide the guarantee that \"if I don't\ntouch the files in .git, it'll never lose my commits\", which sadly\nisn't true by default. I'm glad I can easily change the GC policy, but\nI question why this isn't the default.\n\nIn another discussion about this, one of my coworkers pointed out that\nmaking the GC default \"never\" would be much safer for new users, and\nnew users don't really need to worry about collecting things until\ntheir repositories get bigger anyhow.\n\nI also think that it would be simpler to understand for everyone if\nevery operation which can cause a dangling graph node require the\nexact same override method (i.e. -f is fine, the capitalization as in\n-d -> -D is fine, some --force or --hard is fine, but currently the\nsystem is using three different methods in three different places)\n"},{"id":"80875","messageId":"28156.2147582465$1214307807@news.gmane.org","threadId":"14112","inReplyTo":"200806241322.14224.jnareb@gmail.com","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-24T11:21:57Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Jakub Narebski wrote:\n> If they are using '-f', i.e. force, they should know and be sure what\n> they are doing; it is not much different from 'rm -f *'.\n\nSure, no problem. I don't want the ability to \"rm -f *\". I'm raising my hand\nand saying \"I don't want the power to do these things, so just turn off all the\ngit commands that could be destructive and give me an alternate way to do the\nworkflows I need to do\". Just like a normal user on a unix machine doesn't run\naround with the power to rm -f /etc all the time, even though they may be able\nto su to root.\n\nLet me guess, you're always running euid==0. :)\n"},{"id":"80873","messageId":"200806241322.14224.jnareb@gmail.com","threadId":"14112","inReplyTo":"willow-jeske-01l5kwGPFEDjCc7b","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-24T11:22:12Z","receivedAt":"2008-06-24T11:22:12Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"David Jeske wrote:\n\n> To re-ask the same question I asked in my last post, using your ascii\n> pictures...\n> \n> \n> Let's assume we're here..\n> \n> .<---.<---.<---A<---X<---Y    <--- master\n>  \\\n>   \\--B<---C                   <--- customer_A_branch <=== HEAD\n> \n> \n> And this person and everyone else moves their head pointers back\n> to master without merging:\n\nYou could simply say: they stop working on 'customer_A_branch' branch\n(moving HEAD poter is simply switching to / checking out / working on\ndifferent branch).\n \n> .<---.<---.<---A<---X<---Y    <--- master              <=== HEAD\n>  \\\n>   \\--B<---C                   <--- customer_A_branch\n> \n> \n> Now, five years down the road, our tree looks like:\n> \n> \n> .<---.<---.<---A<---X<---Y<--.(3 years of changes).--ZZZ  <--- master  <=== HEAD\n>  \\\n>   \\--B<---C   <--- customer_A_branch\n> \n> And someone does:\n> \n> git-branch -f customer_A_branch ZZZ\n\nIf they are using '-f', i.e. force, they should know and be sure what\nthey are doing; it is not much different from 'rm -f *'.\n\nIf reflog for 'customer_A_branch' expired it would be hard to go back\nto old 'customer_A_branch', and impossible after garbage collector\npruned history.\n\nWhat you _should do_, if you want to preserve old 'customer_A_branch'\npointer is to *tag* it, e.g. something like 'Attic/customer_A_branch';\nif you use annotated tags you can even state why do you want to keep\nold work, and why old work wasn't merged into long-lived branch, and\nwhy the work was abandoned.\n\n\n-- \nJakub Narebski\nPoland\n"},{"id":"80879","messageId":"200806241413.24111.jnareb@gmail.com","threadId":"14112","inReplyTo":"200806241322.14224.jnareb@gmail.com","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-24T12:13:23Z","receivedAt":"2008-06-24T12:13:23Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Jakub Narebski wrote:\n> David Jeske wrote:\n\n> > Now, five years down the road, [...] someone does:\n> > \n> >  $ git-branch -f customer_A_branch ZZZ\n> \n> If they are using '-f', i.e. force, they should know and be sure what\n> they are doing; it is not much different from 'rm -f *'.\n> \n> If reflog for 'customer_A_branch' expired it would be hard to go back\n> to old 'customer_A_branch', and impossible after garbage collector\n> pruned history.\n\nActually it is not true.  In the case of \"git branch -f <branch>\", which\nis the case which wouldn't be covered by protecting reflogs when\ndeleting branches (saving them to some kind of \"attic\") git _saves_\nold branch pointer to reflog, so \"git log -g <branch>\" would work\nas expected.\n\nThe reflog entry looks like the following:\n\n   0c52414d... 80b4c7e5.. A U Thor <author@example.com> 1214306246 +0200 \\\n\tbranch: Reset from ZZZ\n\n(where of course there are full SHA-1 of commits, instead of shortened\nones, and everything is in single line, without line continuation.)\n \n> What you _should do_, if you want to preserve old 'customer_A_branch'\n> pointer is to *tag* it, e.g. something like 'Attic/customer_A_branch';\n> if you use annotated tags you can even state why do you want to keep\n> old work, and why old work wasn't merged into long-lived branch, and\n> why the work was abandoned.\n\nThis of course is still valid.\n\n-- \nJakub Narebski\nPoland\n"},{"id":"80882","messageId":"4860E63B.6040709@dawes.za.net","threadId":"14112","inReplyTo":"28156.2147582465$1214307807@news.gmane.org","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Rogan Dawes","fromEmail":"lists@dawes.za.net","sentAt":"2008-06-24T12:19:07Z","receivedAt":"2008-06-24T12:19:07Z","isPatch":false,"sender":{"key":"lists@dawes.za.net","avatar":null},"body":"David Jeske wrote:\n> -- Jakub Narebski wrote:\n>> If they are using '-f', i.e. force, they should know and be sure what\n>> they are doing; it is not much different from 'rm -f *'.\n> \n> Sure, no problem. I don't want the ability to \"rm -f *\". I'm raising my hand\n> and saying \"I don't want the power to do these things, so just turn off all the\n> git commands that could be destructive and give me an alternate way to do the\n> workflows I need to do\". Just like a normal user on a unix machine doesn't run\n> around with the power to rm -f /etc all the time, even though they may be able\n> to su to root.\n> \n> Let me guess, you're always running euid==0. :)\n\nDo you also ask the gnu coreutils folks to remove the -f option from \ntheir utilities?\n\nThere is a basic assumption that folks that are using tools have at \nleast made an attempt to understand what it is that they are doing, \nbefore e.g. waving a chainsaw around.\n\nOne thing that I haven't seen addressed in this thread is the fact that \nif you have a dirty working directory, and you \"git reset --hard\", \nwhatever was dirty (not yet in the index, or committed) will be blown \naway, and no amount of reflog archeology will help you get it back.\n\nAny changes that had been staged in the index WILL exist in the object \ndirectories as dangling objects, and can be retrieved through judicious \nuse of \"git fsck\" and \"git show\", but will certainly be a painful \nexercise if there was an extensive set of changes.\n\nRogan\n"},{"id":"80880","messageId":"200806241421.17670.jnareb@gmail.com","threadId":"14112","inReplyTo":"willow-jeske-01l5pWdEFEDjCjLX","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-24T12:21:17Z","receivedAt":"2008-06-24T12:21:17Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"David Jeske wrote:\n> -- Jakub Narebski wrote:\n>>\n>> If they are using '-f', i.e. force, they should know and be sure what\n>> they are doing; it is not much different from 'rm -f *'.\n\nBy the way, reflog (even if expired) would protect you in this\nsituation; I have checked wrongly that it does not (chronological\nvs. reverse chronological order, and not paying attention to\ntimestamps).\n\n> Sure, no problem. I don't want the ability to \"rm -f *\". [...]\n\nIt is very useful command when deleting larger number of files;\nI have \"alias rm='rm -i'\", and confirming every single file quickly\ngets annoying.\n\n> Just like a normal user on a unix machine doesn't run \n> around with the power to rm -f /etc all the time, even though they may be able\n> to su to root.\n\nExample was about \"rm -f *\", i.e. removing contents of current directory;\nyou should be careful when doing it, for example if you are in currect\nrepository.\n \nSome older versions of UNIX supposedly could hose every hidden file you own\nupwards if you did \"rm -rf .*\", as they matched '..' (parent directory)\nagainst '.*'.\n\n> Let me guess, you're always running euid==0. :)\n\nNo.  I almost never login as root, using 'sudo', 'sudo su -', or relying\non applications asking for root credentials if required (for example when\ninstalling new version of git).\n\nLet me guess: no sharp knives in kitchen? ;-P\n-- \nJakub Narebski\nPoland\n"},{"id":"80886","messageId":"20080624123527.GA6149@dualtron.vpn.rwth-aachen.de","threadId":"14112","inReplyTo":"4860E63B.6040709@dawes.za.net","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Johannes Gilger","fromEmail":"heipei@hackvalue.de","sentAt":"2008-06-24T12:35:27Z","receivedAt":"2008-06-24T12:35:27Z","isPatch":false,"sender":{"key":"heipei@hackvalue.de","avatar":"https://avatars.githubusercontent.com/u/6072?v=4"},"body":"On 24/06/08 14:19, Rogan Dawes wrote:\n> One thing that I haven't seen addressed in this thread is the fact that if \n> you have a dirty working directory, and you \"git reset --hard\", whatever \n> was dirty (not yet in the index, or committed) will be blown away, and no \n> amount of reflog archeology will help you get it back.\n\nI think the name of the command \"reset\" itself is a name which should \nprompt everyone to read a manpage before using it. I could understand \nthat if \"status\" did something destructive people would get upset.\nOther than that, git reset itself doesn't do anything destructive. Yeah, \ngit reset --hard does, but hello, this is *reset* and *hard*, someone \nusing this must really want what's about to happen. Nobody complaines \nabout rm --force or anything.\n\nAs for putting safety-measure everywhere, I think that any further \nrestricting of commands would be nonsense and just hindering the \nworkflow. git is not something with a GUI and a recycle-bin. And it \nstill is really hard to accidentaly lose anything in git.\n\nRegards,\nJojo\n\n-- \nJohannes Gilger <heipei@hackvalue.de>\nhttp://hackvalue.de/heipei/\nGPG-Key: 0x42F6DE81\nGPG-Fingerprint: BB49 F967 775E BB52 3A81  882C 58EE B178 42F6 DE81\n"},{"id":"80888","messageId":"4860ECC1.9020608@dawes.za.net","threadId":"14112","inReplyTo":"20080624123527.GA6149@dualtron.vpn.rwth-aachen.de","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Rogan Dawes","fromEmail":"lists@dawes.za.net","sentAt":"2008-06-24T12:46:57Z","receivedAt":"2008-06-24T12:46:57Z","isPatch":false,"sender":{"key":"lists@dawes.za.net","avatar":null},"body":"Johannes Gilger wrote:\n> On 24/06/08 14:19, Rogan Dawes wrote:\n>> One thing that I haven't seen addressed in this thread is the fact that if \n>> you have a dirty working directory, and you \"git reset --hard\", whatever \n>> was dirty (not yet in the index, or committed) will be blown away, and no \n>> amount of reflog archeology will help you get it back.\n> \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. I could understand \n> that if \"status\" did something destructive people would get upset.\n> Other than that, git reset itself doesn't do anything destructive. Yeah, \n> git reset --hard does, but hello, this is *reset* and *hard*, someone \n> using this must really want what's about to happen. Nobody complaines \n> about rm --force or anything.\n> \n> As for putting safety-measure everywhere, I think that any further \n> restricting of commands would be nonsense and just hindering the \n> workflow. git is not something with a GUI and a recycle-bin. And it \n> still is really hard to accidentaly lose anything in git.\n> \n> Regards,\n> Jojo\n> \n\nRight. I was simply pointing out to the original poster that for all the \ntalk about reflogs, if you use \"reset --hard\", all bets are off. I was \nnot complaining about the existence of that option, or its name . . .\n\nI agree that adding nanny-guards to git would be counter productive.\n\nRogan\n"},{"id":"80891","messageId":"20080624131315.GD7639@mit.edu","threadId":"14112","inReplyTo":"e80d075a0806240324j79f872d3t1db9dfb87dc2d37c@mail.gmail.com","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2008-06-24T13:13:15Z","receivedAt":"2008-06-24T13:13:15Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Tue, Jun 24, 2008 at 03:24:00AM -0700, David Jeske wrote:\n> Odd. I've never been a gatekeeper. I'm just a developer who has burned\n> himself enough times that I want a tool (i.e. source control) to help\n> prevent me from ever destroying anything I create.\n\nIt sounds like the main problem is that you need to learn more about\nhow to use the your tools.  If you use the tools right, the number of\ntimes that you you'll accidentally overwrite a branch pointer is quite\nrare; and generally you notice right away; the default GC period of 30\ndays is a L-O-N-G time, and in practice its more than enough time for\nsomeone to notice that they screwed up.\n\nSo a couple of tips\n\n1) \"git reflog show <branch name>\" is a great way to only look at\nchanges to a particular branch.  (\"git log -g\" or \"git reflog show\"\ndefaults to showing the reflog for HEAD)\n\n2) A number of accidents with \"git rebase\" happen because people\nforget which branch they are on.  So having your command line prompt\ntell you which branch you are on is really helpful.  Google \"git\nprompt shell\" for some examples of how to do this.\n\nI do something like this:\n\nfunction __prompt_git()\n{\n\tlocal git_dir ref br top;\n\tgit_dir=$(git-rev-parse --git-dir 2> /dev/null) || return\n\tref=$(git-symbolic-ref HEAD 2> /dev/null) || return\n\tbr=${ref#refs/heads/}\n\ttop=$(cat $git_dir/patches/$br/current 2>/dev/null) \\\n\t\t  && top=\"/$top\"\n\t\t  echo \"[$br$top]\"\n}\n\nif [ $UID = 0 ]; then\nu=\"${LOGNAME}.root\"\np=\"#\"\nelse\nu=\"$LOGNAME\";\np=\"%\"\nfi\nif [ $SHLVL != 1 ]; then\ns=\", level $SHLVL\"\nfi\nPS1=\"<${u}@${HOSTNAME}> {\\${PWD}}$s  \\$(__prompt_git)\\n\\!$p \"\nunset u s\n\n\t\t\t\t\t\t\t- Ted\n"},{"id":"80929","messageId":"48612ABE.6000104@panasas.com","threadId":"14112","inReplyTo":"willow-jeske-01l5cKsCFEDjC=91MX","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Boaz Harrosh","fromEmail":"bharrosh@panasas.com","sentAt":"2008-06-24T17:11:26Z","receivedAt":"2008-06-24T17:11:26Z","isPatch":false,"sender":{"key":"bharrosh@panasas.com","avatar":"https://gravatar.com/avatar/347e426f8ca0409f6891ceeefd4c3c2d8769608382323057efeaa362b4c3dbf3?d=mp&s=160"},"body":"David Jeske wrote:\n> As a new user, I'm finding git difficult to trust, because there are operations\n> which are destructive by default and capable of inadvertently throwing hours or\n> days of work into the bit bucket.\n> \n> More problematic, those commands have no discernible pattern that shows their\n> danger, and they need to be used to do typical everyday things. I'm starting to\n> feel like I need to use another source control system on top of the git\n> repository in case I make a mistake.  My philosophy is simple, I never never\n> never want to throw away changes, you shouldn't either. Disks are cheaper than\n> programmer hours. I can understand wanting to keep things tidy, so I can\n> understand ways to correct the 'easily visible changes', and also avoid pushing\n> them to other trees, but I don't understand why git needs to delete things.\n> \n> For example, the following commands seem capable of totally destroying hours or\n> days of work. Some of them need to be used regularly to do everyday things, and\n> there is no pattern among them spelling out danger.\n> \n> git reset --hard          : if another branch name hasn't been created\n\ngit reset --hard is special see below\n\n> git rebase\n> git branch -D <branch>    : if branch hasn't been merged\n> git branch -f <new>       : if new exists and hasn't been merged\n> git branch -m <old> <new> : if new exists and hasn't been merged\n> \nThe rest of the commands are recoverable from the log as people said\nbut \"git reset --hard\" is not and should be *fixed*!\n\nI use git reset --hard in to separate and distinct functions.\nOne - to move current branch head around from place to place.\nTwo - Throw away work I've edited\n\nIt has happened to me more then once that I wanted the first\nand also got the second as an un-warned bonus, to the dismay \nof my bosses. (What do I care if I need to write all this code\nagain)\n\nI would like git-reset --hard to refuse if a git-diff HEAD\n(both staged and unstaged) is not empty. with a -f / -n logic\nlike git-clean. (like git-clean none default config file override)\n\nNow I know that the first usage above could be done with\ngit-branch -f that_branch the_other_branch. But that can\nnot be preformed on the current branch and local changes\nare not lost.\n\nLots of other potentially destructive git-commands check for local\nchanges and refuse to operate. To remedy them git-reset --hard\nis recommended. I would prefer if there was a git-reset --clean -f/-n\nfor the first case and git reset --hard only for the second usage\ncase.\n\nMy $0.017\nBoaz\n"},{"id":"80931","messageId":"48612CB0.2070303@panasas.com","threadId":"14112","inReplyTo":"48612ABE.6000104@panasas.com","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Boaz Harrosh","fromEmail":"bharrosh@panasas.com","sentAt":"2008-06-24T17:19:44Z","receivedAt":"2008-06-24T17:19:44Z","isPatch":false,"sender":{"key":"bharrosh@panasas.com","avatar":"https://gravatar.com/avatar/347e426f8ca0409f6891ceeefd4c3c2d8769608382323057efeaa362b4c3dbf3?d=mp&s=160"},"body":"Boaz Harrosh wrote:\n> David Jeske wrote:\n>> As a new user, I'm finding git difficult to trust, because there are operations\n>> which are destructive by default and capable of inadvertently throwing hours or\n>> days of work into the bit bucket.\n>>\n>> More problematic, those commands have no discernible pattern that shows their\n>> danger, and they need to be used to do typical everyday things. I'm starting to\n>> feel like I need to use another source control system on top of the git\n>> repository in case I make a mistake.  My philosophy is simple, I never never\n>> never want to throw away changes, you shouldn't either. Disks are cheaper than\n>> programmer hours. I can understand wanting to keep things tidy, so I can\n>> understand ways to correct the 'easily visible changes', and also avoid pushing\n>> them to other trees, but I don't understand why git needs to delete things.\n>>\n>> For example, the following commands seem capable of totally destroying hours or\n>> days of work. Some of them need to be used regularly to do everyday things, and\n>> there is no pattern among them spelling out danger.\n>>\n>> git reset --hard          : if another branch name hasn't been created\n> \n> git reset --hard is special see below\n> \n>> git rebase\n>> git branch -D <branch>    : if branch hasn't been merged\n>> git branch -f <new>       : if new exists and hasn't been merged\n>> git branch -m <old> <new> : if new exists and hasn't been merged\n>>\n> The rest of the commands are recoverable from the log as people said\n> but \"git reset --hard\" is not and should be *fixed*!\n> \n> I use git reset --hard in to separate and distinct functions.\n> One - to move current branch head around from place to place.\n> Two - Throw away work I've edited\n> \n> It has happened to me more then once that I wanted the first\n> and also got the second as an un-warned bonus, to the dismay \n> of my bosses. (What do I care if I need to write all this code\n> again)\n> \n> I would like git-reset --hard to refuse if a git-diff HEAD\n> (both staged and unstaged) is not empty. with a -f / -n logic\n> like git-clean. (like git-clean none default config file override)\n> \n> Now I know that the first usage above could be done with\n> git-branch -f that_branch the_other_branch. But that can\n> not be preformed on the current branch and local changes\n> are not lost.\n> \n> Lots of other potentially destructive git-commands check for local\n> changes and refuse to operate. To remedy them git-reset --hard\n> is recommended. I would prefer if there was a git-reset --clean -f/-n\n> for the first case and git reset --hard only for the second usage\n> case.\nSorry\ngit-reset --clean -f/-n for removing local changes\ngit reset --hard for moving HEAD on a clean tree only\n> \n> My $0.017\n> Boaz\n> \n"},{"id":"80938","messageId":"B7VXwxfjnTa8aYUBhy6fPK8N4wDq9i91R-fo4xot3lQCjt87hBafoQ@cipher.nrlssc.navy.mil","threadId":"14112","inReplyTo":"48612ABE.6000104@panasas.com","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:18:34Z","receivedAt":"2008-06-24T18:18:34Z","isPatch":false,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"Boaz Harrosh wrote:\n\n> I use git reset --hard in to separate and distinct functions.\n> One - to move current branch head around from place to place.\n\nWhy?\n\n> Two - Throw away work I've edited\n\nThis is valid.\n\n> It has happened to me more then once that I wanted the first\n> and also got the second as an un-warned bonus, to the dismay \n> of my bosses.\n\nWhy are you using 'git reset' to do this? Why not just checkout\nthe branch? I think you are using 'reset' in ways it is not\nintended to be used. Is there something in the documentation that\nled you to believe that 'reset --hard' should be used to switch\nbranches? I do see an example of such a thing in everyday.txt.\nIt deals with setting 'pu' branch to the tip of the 'next' branch,\nbut the 'pu' branch has a special meaning in git.\n\nIt seems like you are using 'reset' when you should be using 'checkout'.\n\nFor example:\n\n$ git branch\n* mybranch\n  master\n  next\n  maint\n  pu\n\nIf I have 'mybranch' checked out and I want to make a change on top of\nthe 'next' branch, I wouldn't do 'git reset --hard next', I would either\n'git checkout next' or 'git checkout -b next-feature next' or something\nsimilar.\n\nIf I've already merged the changes from mybranch back into upstream, then\nit's safe to delete it.\n\nI recommend adopting a branch naming scheme where the branch name describes\nthe task that is to be accomplished. i.e. 'foo' is a bad branch name.\n\nbtw, you are not saving anything by trying to reuse branch names. All\na branch is, is a file with a 40 byte string and a newline. So creating\na branch entails writing 41 bytes to a file. Deleting a branch entails\ndeleting a single file that is only 41 bytes small.\n\nI suggest trying to adjust your work flow so that 'reset --hard' is not necessary.\n\n-brandon\n"},{"id":"80948","messageId":"m31w2mlki4.fsf@localhost.localdomain","threadId":"14112","inReplyTo":"48612CB0.2070303@panasas.com","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-24T19:08:31Z","receivedAt":"2008-06-24T19:08:31Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Boaz Harrosh <bharrosh@panasas.com> writes:\n\n\n> Sorry\n> git-reset --clean -f/-n for removing local changes\n> git reset --hard for moving HEAD on a clean tree only\n\nWouldn't \"git reset <commit-ish>\" be enough then?  It modifies where\ncurrent branch points to (as opposed to git-checkout modifying what is\nthe current branch), and it modifies index.  What it doesn't modify is\nworking directory, but it is clean already.\n\nSo the solution is: don't use `--hard'.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"80974","messageId":"26999.3299422369$1214338338@news.gmane.org","threadId":"14112","inReplyTo":"m31w2mlki4.fsf@localhost.localdomain","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-24T20:09:06Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"> -- David Jeske wrote:\n>> - improve the man page description of \"reset --hard\"\n>> - standardize all the potentially destructive operations\n>> (after gc) on \"-f/--force\" to override\n>\n> The thing is 'force' is not always the most descriptive word\n> for the behavior that you propose enabling with --force.\nI'm not talking about switching \"git reset --hard\" to \"git reset -f\". I'm\ntalking about requiring a \"-f\" option to \"git reset --hard\" when it would\ndestroy or dangle information.\n\n(a) If you have a clean working directory which is fully checked in and has\nanother branch tag other than the current branch tag, then \"git reset --hard\n<commitish>\" is non-destructive, and would complete happily.\n\n(b) If you have local modifications to working files it would complain \"hey,\nyour working files are dirty, 'reset --hard' will blow them away, either revert\nthem or use -f\". This is what Boaz asked for, and I doubt it would change along\nwould alter workflow much for people who are using \"git reset --hard\" to toss\nattempted patches (since they were fully committed anyhow), or even undo a\nclone or pull operation. If people use it as a combo \"revert and reset\", they\nwould notice.\n\n(c) If the current location is only pointed to by the current branch (which you\nare going to move with 'reset --hard') tell the user that those changes will be\ndangling and will be eligible for garbage collection if they move the branch.\nWhat to do in this case seems more controversial. I would prefer for this to\nerror with \"either label these changes with 'branch', or use 'reset --hard -f'\nto force us to leave these in the reflog unnamed\".  --- Some here say that\nbeing in the reflog is enough, and the -f is overkill here. If we define\ndestructive as dropping code-commits, then that's true. If we define\ndestructive as leaving code-commits unreferenced, then -f is warranted.\nPersonally, I'd rather git help me avoid dropping the NAMES to tips, because\neven with GC-never, I don't really want to find myself crawling through SHA1\nhashes and visualization trees to find them later, when git could have reminded\nme to name a branch that would conveniently show up in 'git branch'. It's easy\nenough to avoid dropping the names, or force git to not care with '-f'. I\npersonally would like to avoid dealing with reflog or SHA1 hashes 99% of the\ntime.\n\n> 'gc' is another command that has been mentioned along\n> with its '--aggressive' option.\n\nThis was an accident. When I made my \"mv --aggressive\" joke I was NOT intending\nto reference \"gc --aggressive\", that is just a coincidence. I was trying to\nmake up another 'semi-dangerous sounding name that might or not might be\ndestructive\". It's comical that it's in use for gc. I don't see any\nrelationship between \"gc --aggressive\" and destructive behavior.\n\nHowever, there IS a situation to require a \"-f\" on a, because again, \"-f\" would\nbe required for operations which destroy commits. If we think commits being in\nthe reflog is good enough to hold onto them, and users are thinking that items\nbeing in the reflog are 'safe', then a GC where reflog entry expiration is\ngoing to cause DAG entries to be removed could print an error like:\n\nerror: the following entries are beyond the expiration time,\n...<base branchname>/<commit-ish>: 17 commits, 78 lines, 3 authors\n...use diff <commit-ish> , to see the changes\n...use gc -f, to cause them to be deleted\n\nThis wouldn't happen very often, and would make \"gc\" a safe operation even on\ntrees with shorter expiration time. In fact, if this were the way it worked, I\nmight set my GC back from never to \"30 days\", because this would not only allow\nme to safely cleanup junk, but it would also allow me to catch unnamed and\ndangling references before they became so old I didn't remember what to name\nthem.\n\nThis would make a \"non forced gc\" safe from throwing away commits, but still\nmake it really easy to do so for people who want to. Likewise, we could make\nany \"auto-gc\" that happens not forced by default.\n"},{"id":"80992","messageId":"FmVFerrNVumRho9GZZwRiHrXV_hb12J_P_hSYUBnFhcCFiMGdtdCrg@cipher.nrlssc.navy.mil","threadId":"14112","inReplyTo":"willow-jeske-01l61=64jMFEDjCiBE","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Brandon Casey","fromEmail":"casey@nrlssc.navy.mil","sentAt":"2008-06-24T21:42:49Z","receivedAt":"2008-06-24T21:42:49Z","isPatch":false,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"David Jeske wrote:\n>> -- David Jeske wrote:\n>>> - improve the man page description of \"reset --hard\"\n>>> - standardize all the potentially destructive operations\n>>> (after gc) on \"-f/--force\" to override\n>> The thing is 'force' is not always the most descriptive word\n>> for the behavior that you propose enabling with --force.\n> I'm not talking about switching \"git reset --hard\" to \"git reset -f\". I'm\n> talking about requiring a \"-f\" option to \"git reset --hard\" when it would\n> destroy or dangle information.\n\nI only have the same advice I gave to Boaz. I think you should try to adjust\nyour workflow so that 'git reset' is not necessary. It seems that for the\nfunctions you're trying to perform, 'checkout' and 'branch' should be used rather\nthan 'reset'.\n\nAgain, as I mentioned to Boaz, there is really no benefit to reusing a single\nbranch name if that is what you are trying to do. The cost of branching in git\nis 41 bytes i.e. nil. The cost of updating the working directory which happens\nduring the 'reset --hard' is exactly the same whether I do\n'reset --hard <some_branch>' or 'checkout -b new_branch <some_branch>'.\n\nIn nearly every case where I, personally, have used 'reset --hard', I was using\nit because I didn't care what the current state of the working directory or the\nindex were. They were wrong and I was resetting to the right state. I believe\nthis was the intended use for the command.\n\nI'm not sure why you want to use reset so often. If there is something in the\ndocumentation that led you to want to use reset maybe it can be changed so that\nother users are not led in the same way.\n\nAbout the reflog..\nThe reflog is not a storage area. It's just a log, like /var/log/messages. It is\nthere to provide a way to recover from mistakes. Mistakes are usually recognized\nfairly quickly. If you have not realized that you have made a mistake after 30\ndays, it may be pretty hard to recover from since people have imperfect memories.\nIf we did not garbage collect the reflog it would just continue to grow appending\nuseless piece of information after useless piece of information.\n\n-brandon\n"},{"id":"80996","messageId":"20080624222105.GA24549@dervierte","threadId":"14112","inReplyTo":"willow-jeske-01l61=64jMFEDjCiBE","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Steven Walter","fromEmail":"stevenrwalter@gmail.com","sentAt":"2008-06-24T22:21:05Z","receivedAt":"2008-06-24T22:21:05Z","isPatch":false,"sender":{"key":"stevenrwalter@gmail.com","avatar":"https://avatars.githubusercontent.com/u/79127?v=4"},"body":"On Tue, Jun 24, 2008 at 08:04:30PM -0000, David Jeske wrote:\n> I'm not talking about switching \"git reset --hard\" to \"git reset -f\". I'm\n> talking about requiring a \"-f\" option to \"git reset --hard\" when it would\n> destroy or dangle information.\n\nI think you're asking for something like the following...\n-- \n-Steven Walter <stevenrwalter@gmail.com>\nFreedom is the freedom to say that 2 + 2 = 4\nB2F1 0ECC E605 7321 E818  7A65 FC81 9777 DC28 9E8F \n"},{"id":"80997","messageId":"1214346098-24584-1-git-send-email-stevenrwalter@gmail.com","threadId":"14112","inReplyTo":"20080624222105.GA24549@dervierte","subject":"[PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Steven Walter","fromEmail":"stevenrwalter@gmail.com","sentAt":"2008-06-24T22:21:38Z","receivedAt":"2008-06-24T22:21:38Z","isPatch":true,"sender":{"key":"stevenrwalter@gmail.com","avatar":"https://avatars.githubusercontent.com/u/79127?v=4"},"body":"Give \"reset --hard\" a -f (force) flag, without which it will refuse to\nproceed if there are changes in the index or working tree.\n\nSigned-off-by: Steven Walter <stevenrwalter@gmail.com>\n---\n builtin-reset.c |   24 +++++++++++++++++++++++-\n 1 files changed, 23 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex f34acb1..6ee8448 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -11,8 +11,10 @@\n #include \"tag.h\"\n #include \"object.h\"\n #include \"commit.h\"\n+#include \"diff.h\"\n #include \"run-command.h\"\n #include \"refs.h\"\n+#include \"revision.h\"\n #include \"diff.h\"\n #include \"diffcore.h\"\n #include \"tree.h\"\n@@ -165,12 +167,26 @@ static void prepend_reflog_action(const char *action, char *buf, size_t size)\n \t\twarning(\"Reflog action message too long: %.*s...\", 50, buf);\n }\n \n+/* Stolen from builtin-revert.c... */\n+static int index_is_dirty(void)\n+{\n+\tstruct rev_info rev;\n+        read_cache();\n+\tinit_revisions(&rev, NULL);\n+\tsetup_revisions(0, NULL, &rev, \"HEAD\");\n+\tDIFF_OPT_SET(&rev.diffopt, QUIET);\n+\tDIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);\n+\trun_diff_files(&rev, 1);\n+\treturn !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);\n+}\n+\n enum reset_type { MIXED, SOFT, HARD, NONE };\n static const char *reset_type_names[] = { \"mixed\", \"soft\", \"hard\", NULL };\n \n int cmd_reset(int argc, const char **argv, const char *prefix)\n {\n-\tint i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;\n+\tint i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0,\n+            force = 0;\n \tconst char *rev = \"HEAD\";\n \tunsigned char sha1[20], *orig = NULL, sha1_orig[20],\n \t\t\t\t*old_orig = NULL, sha1_old_orig[20];\n@@ -184,6 +200,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\t\t\"reset HEAD, index and working tree\", HARD),\n \t\tOPT_BOOLEAN('q', NULL, &quiet,\n \t\t\t\t\"disable showing new HEAD in hard reset and progress message\"),\n+\t\tOPT_BOOLEAN('f', NULL, &force,\n+\t\t\t\t\"proceed even if there are uncommitted changes\"),\n \t\tOPT_END()\n \t};\n \n@@ -225,6 +243,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tif (reset_type == HARD && is_bare_repository())\n \t\tdie(\"hard reset makes no sense in a bare repository\");\n \n+        if (reset_type == HARD && !force && index_is_dirty()) {\n+                die(\"Uncommitted changes; re-run with -f to trash them\");\n+        }\n+\n \t/* Soft reset does not touch the index file nor the working tree\n \t * at all, but requires them in a good order.  Other resets reset\n \t * the index file to the tree object we are switching to. */\n-- \n1.5.6.dirty\n"},{"id":"81001","messageId":"7vwskea2ik.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"1214346098-24584-1-git-send-email-stevenrwalter@gmail.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-24T22:31:31Z","receivedAt":"2008-06-24T22:31:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steven Walter <stevenrwalter@gmail.com> writes:\n\n> @@ -225,6 +243,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>  \tif (reset_type == HARD && is_bare_repository())\n>  \t\tdie(\"hard reset makes no sense in a bare repository\");\n>  \n> +        if (reset_type == HARD && !force && index_is_dirty()) {\n> +                die(\"Uncommitted changes; re-run with -f to trash them\");\n> +        }\n> +\n\nPlease don't.  With your change, does the testsuite even pass?\n\n\"reset --hard\" has *ALWAYS* meant to be destructive --- discarding\npotential local cruft is the whole point of the operation.\n\nLearn the lingo, and get over it.\n"},{"id":"81004","messageId":"31710.7249437415$1214347705@news.gmane.org","threadId":"14112","inReplyTo":"FmVFerrNVumRho9GZZwRiHrXV_hb12J_P_hSYUBnFhcCFiMGdtdCrg@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-24T22:43:44Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Brandon Casey wrote:\n> I only have the same advice I gave to Boaz. I think you should try to adjust\n> your workflow so that 'git reset' is not necessary. It seems that for the\n> functions you're trying to perform, 'checkout' and 'branch' should be used\n> rather than 'reset'.\n\nEven when I change my workflow to avoid 'reset', I believe that the\nuser-interface of git will be stronger if it is a simpler expression of the\nsame functionality. One way to simplify it is to use convention that is\nstandardized across a set of tools so we don't have to learn every little\nnuance of every little feature independently.\n\nTwo things I'd like to make it easy for users to never do are:\n- delete data\n- cause refs to be dangling\n\nTherefore, I'd like a simple convention I can apply across all commands, so\nthat if users never do them, they'll never do either of the above things. I'm\nnot alone.\n\nI think some of the impedance mismatch between my suggestions, and current\nusage, has to do with where I'd like to be next. This is a meaty topic, I'll\nstart another thread on \"policy and mechanism for less-connected clients\".\n\n> I'm not sure why you want to use reset so often. If there is something in the\n> documentation that led you to want to use reset maybe it can be changed so\nthat\n> other users are not led in the same way.\n\nYes, it's a problem in the git-gui and the \"reset --hard\" documentation. I'm\nworking on a patch.\n"},{"id":"81012","messageId":"20080624225442.GA20361@mit.edu","threadId":"14112","inReplyTo":"FmVFerrNVumRho9GZZwRiHrXV_hb12J_P_hSYUBnFhcCFiMGdtdCrg@cipher.nrlssc.navy.mil","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2008-06-24T22:54:42Z","receivedAt":"2008-06-24T22:54:42Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Tue, Jun 24, 2008 at 04:42:49PM -0500, Brandon Casey wrote:\n> Again, as I mentioned to Boaz, there is really no benefit to reusing\n> a single branch name if that is what you are trying to do. The cost\n> of branching in git is 41 bytes i.e. nil.\n\nThe main reason that I find for reusing a branch name is for my\nintegration branch.  I have a script which basically does:\n\ngit checkout integration\ngit reset --hard origin\ngit merge branch-A\ngit merge branch-B\ngit merge branch-C\ngit merge branch-D\n\nI suppose I could have avoided the use of git reset with something\nlike this:\n\ngit update-index --refresh --unmerged > /dev/null\nif git diff-index --name-only HEAD | read dummy; then\n\techo \"There are local changes; refusing to build integration branch!\"\n\texit 1\nfi\ngit update-ref refs/heads/integration origin\ngit checkout integration\ngit merge branch-A\ngit merge branch-B\ngit merge branch-C\ngit merge branch-D\n\nInstead, I've just learned to be careful and my use of git reset\n--hard is mainly for historical reasons.  But the point is, I can very\neasily think of workflows where it makes sense to reuse a branch name,\nmost of them having to do with creating integration branches which are\nbasically throwaways after I am done testing or building that combined\ntree.\n\n\t\t\t\t\t\t\t- Ted\n"},{"id":"81014","messageId":"7vod5qa0tu.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"20080624225442.GA20361@mit.edu","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-24T23:07:57Z","receivedAt":"2008-06-24T23:07:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> The main reason that I find for reusing a branch name is for my\n> integration branch.  I have a script which basically does:\n>\n> git checkout integration\n> git reset --hard origin\n> git merge branch-A\n> git merge branch-B\n> git merge branch-C\n> git merge branch-D\n>\n> I suppose I could have avoided the use of git reset with something\n> like this:\n>\n> git update-index --refresh --unmerged > /dev/null\n> if git diff-index --name-only HEAD | read dummy; then\n> \techo \"There are local changes; refusing to build integration branch!\"\n> \texit 1\n> fi\n> git update-ref refs/heads/integration origin\n> git checkout integration\n> git merge branch-A\n> git merge branch-B\n> git merge branch-C\n> git merge branch-D\n>\n> Instead, I've just learned to be careful and my use of git reset\n> --hard is mainly for historical reasons.\n\nThis makes it sound as if avoiding \"reset --hard\" is a good thing, but I\ndo not understand why.\n\nThe reason you have the diff-index check in the second sequence is because\nupdate-ref does not have the \"local changes\" check either.  You could have\nused the same diff-index check in front of \"reset --hard\".\n\nMoreover, in your original sequence above, doesn't \"git checkout\nintegration\" list your local changes when you have any, and wouldn't that\nbe a clue enough that the next \"reset --hard origin\" would discard them?\n\n> ...  But the point is, I can very\n> easily think of workflows where it makes sense to reuse a branch name,\n> most of them having to do with creating integration branches which are\n> basically throwaways after I am done testing or building that combined\n> tree.\n\nAbsolutely.\n"},{"id":"81035","messageId":"20080625022610.GB20361@mit.edu","threadId":"14112","inReplyTo":"7vod5qa0tu.fsf@gitster.siamese.dyndns.org","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2008-06-25T02:26:10Z","receivedAt":"2008-06-25T02:26:10Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Tue, Jun 24, 2008 at 04:07:57PM -0700, Junio C Hamano wrote:\n> > Instead, I've just learned to be careful and my use of git reset\n> > --hard is mainly for historical reasons.\n> \n> This makes it sound as if avoiding \"reset --hard\" is a good thing, but I\n> do not understand why.\n\nWell, it was Brandon Casey who was asserting that git reset --hard was\nevil, which I generally don't agree with.  I do use workflows that use\nit a fair amount, usually because its more convenient to type \"git\ncheckout <foo>; git reset --hard <baz>\" than something involving \"git\nupdate-ref refs/heads/<foo> <baz>\".  The former has more characters\nthan the latter, and involves more disk I/O since it mutates the\nworking directory; but it's something about needing to type\n\"refs/heads/\" such that I generally tend to type \"git checkout....\ngit reset\".  I can't explain why; maybe it's just psychological.\n\nThe reason why I've been thinking that I should change my shell script\nfrom:\n\n\tgit checkout integration\n\tgit reset --hard <foo>\n\nto:\n\n\tgit update-ref ref/heads/integration HEAD\n\tgit checkout integration\n\nIs actually because the first tends to touch more files in the working\ndirectory than the second (because if the integration branch is a week\nor two old, the git checkout unwinds the global state by two weeks,\nand then the git reset --hard has to bring the state back up to\nrecentcy; the second generally involves a smaller set of files\nchanging).  That's a very minor point, granted.\n\n> The reason you have the diff-index check in the second sequence is because\n> update-ref does not have the \"local changes\" check either.  You could have\n> used the same diff-index check in front of \"reset --hard\".\n\nDefinitely true.  The reason why I don't have this check is because\nI'm generally careful and I run a \"git stat\" to make sure there are no\nlocal changes in the tree before I run the script.\n\n> Moreover, in your original sequence above, doesn't \"git checkout\n> integration\" list your local changes when you have any, and wouldn't that\n> be a clue enough that the next \"reset --hard origin\" would discard them?\n\n... because it's in a shell script; being fundamentally lazy, instead\nof typing that sequence over and over again, I've scripted it.  :-)\n\n\t     \t  \t \t     \t   - Ted\n"},{"id":"81069","messageId":"20080625052929.GA23079@dualtron.vpn.rwth-aachen.de","threadId":"14112","inReplyTo":"1214346098-24584-1-git-send-email-stevenrwalter@gmail.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Gilger","fromEmail":"heipei@hackvalue.de","sentAt":"2008-06-25T05:29:29Z","receivedAt":"2008-06-25T05:29:29Z","isPatch":true,"sender":{"key":"heipei@hackvalue.de","avatar":"https://avatars.githubusercontent.com/u/6072?v=4"},"body":"On 24/06/08 18:21, Steven Walter wrote:\n> Give \"reset --hard\" a -f (force) flag, without which it will refuse to\n> proceed if there are changes in the index or working tree.\n\nOh no. I can only agree and repeat myself, as I think this is nonsense. \ngit is a tool, and like every tool you can hurt yourself with it if you \ndon't read the manual and follow really simple guidelines. I used git \nreset --hard on a test-repo before using it on my real code, and it has \nnever bit me since. Why do we have --hard then? It would be \"An option \nwhich does nothing unless you also specify -f on the command-line\".\n\nJust my opinion, but I think quite a few people feel the same\nRegards,\nJojo\n\n-- \nJohannes Gilger <heipei@hackvalue.de>\nhttp://hackvalue.de/heipei/\nGPG-Key: 0x42F6DE81\nGPG-Fingerprint: BB49 F967 775E BB52 3A81  882C 58EE B178 42F6 DE81\n"},{"id":"81095","messageId":"48620897.5040708@panasas.com","threadId":"14112","inReplyTo":"m31w2mlki4.fsf@localhost.localdomain","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Boaz Harrosh","fromEmail":"bharrosh@panasas.com","sentAt":"2008-06-25T08:57:59Z","receivedAt":"2008-06-25T08:57:59Z","isPatch":false,"sender":{"key":"bharrosh@panasas.com","avatar":"https://gravatar.com/avatar/347e426f8ca0409f6891ceeefd4c3c2d8769608382323057efeaa362b4c3dbf3?d=mp&s=160"},"body":"Jakub Narebski wrote:\n> Boaz Harrosh <bharrosh@panasas.com> writes:\n> \n> \n>> Sorry\n>> git-reset --clean -f/-n for removing local changes\n>> git reset --hard for moving HEAD on a clean tree only\n> \n> Wouldn't \"git reset <commit-ish>\" be enough then?  It modifies where\n> current branch points to (as opposed to git-checkout modifying what is\n> the current branch), and it modifies index.  What it doesn't modify is\n> working directory, but it is clean already.\n> \n\nDoes not work. only --hard will do the job. The working directory is not\ntouched and if you'll do a git-diff you'll see the diff between old-head\nto new-head. But what I want is to start-hack or merge on new-head.\n\n> So the solution is: don't use `--hard'.\n> \n\nthe closest to git reset --hard that I can think of is:\n\nLets say I have\n$ git-branch -a\n* mybranch\nremote/master\n\nI can\n$ git reset --hard remote/master\nOr I can\n$ git-checkout -b temp_mybranch remote/master\n$ git-branch -M temp_mybranch mybranch\n\nThe second will complain if I have local changes.\nI have just written 2 scripts. One \"git-reset\" that\nwill filter out --hard before calling the original.\nSecond \"git-reset--hard\" that will do the above.\n\nStupid me no more. It will not happen to me again.\nJust those poor new users out there, I guess you have to\nfall off your bike at least once.\n\nBoaz\n"},{"id":"81096","messageId":"200806251058.54319.jnareb@gmail.com","threadId":"14112","inReplyTo":"20080625022610.GB20361@mit.edu","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-06-25T08:58:52Z","receivedAt":"2008-06-25T08:58:52Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Wed, 25 Jun 2008, Theodore Tso wrote:\n\n> The reason why I've been thinking that I should change my shell script\n> from:\n> \n>         git checkout integration\n>         git reset --hard <foo>\n> \n> to:\n> \n>         git update-ref ref/heads/integration HEAD\n>         git checkout integration\n\nHmmmm.... Wouldn't it be easier on fingers to use\n\n          git reset --soft integration\n\n-- \nJakub Narebski\nPoland\n"},{"id":"81098","messageId":"48620C1A.6000509@panasas.com","threadId":"14112","inReplyTo":"7vwskea2ik.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Boaz Harrosh","fromEmail":"bharrosh@panasas.com","sentAt":"2008-06-25T09:12:58Z","receivedAt":"2008-06-25T09:12:58Z","isPatch":true,"sender":{"key":"bharrosh@panasas.com","avatar":"https://gravatar.com/avatar/347e426f8ca0409f6891ceeefd4c3c2d8769608382323057efeaa362b4c3dbf3?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Steven Walter <stevenrwalter@gmail.com> writes:\n> \n>> @@ -225,6 +243,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>>  \tif (reset_type == HARD && is_bare_repository())\n>>  \t\tdie(\"hard reset makes no sense in a bare repository\");\n>>  \n>> +        if (reset_type == HARD && !force && index_is_dirty()) {\n>> +                die(\"Uncommitted changes; re-run with -f to trash them\");\n>> +        }\n>> +\n> \n> Please don't.  With your change, does the testsuite even pass?\n> \n> \"reset --hard\" has *ALWAYS* meant to be destructive --- discarding\n> potential local cruft is the whole point of the operation.\n> \n\nI was under the impression that --hard means working-directory-also\nas opposed to tree-and-index-only. Nothing to do with \ndestructive-discarding. If it is then something is missing.\nI need 2 distinct functions. You combine to functions under\none command.\n\n> Learn the lingo, and get over it.\n> \n\nI did lern the lingo and got bitten. I wanted to do one thing\nalso got the other one.\n\nthere is:\ngit-reset --clean - destructive-discarding any local changes\ngit-reset --hard - move tree index and working directory to new head\n\nHow can I separate between them, Please\n\nBoaz\n"},{"id":"81099","messageId":"7vzlp93mgy.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"200806251058.54319.jnareb@gmail.com","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T09:14:37Z","receivedAt":"2008-06-25T09:14:37Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> On Wed, 25 Jun 2008, Theodore Tso wrote:\n>\n>> The reason why I've been thinking that I should change my shell script\n>> from:\n>> \n>>         git checkout integration\n>>         git reset --hard <foo>\n>> \n>> to:\n>> \n>>         git update-ref ref/heads/integration HEAD\n>>         git checkout integration\n>\n> Hmmmm.... Wouldn't it be easier on fingers to use\n>\n>           git reset --soft integration\n\nThat does not do anything close to what Ted is doing, does it?\n\nAnyway, here is how I conclude my git day:\n\n\tgit checkout next\n        ... merge more and test\n        ... be happy that next is in very good shape ;-)\n        git branch -f pu\n        git checkout pu\n        git merge ... merge other topics to rebuild pu\n        git merge ...\n        ...\n\nwhich is probably a bit less error prone then update-ref, if you type from\nthe command line like I do.\n"},{"id":"81100","messageId":"7vr6al3m24.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"48620C1A.6000509@panasas.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T09:23:31Z","receivedAt":"2008-06-25T09:23:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Boaz Harrosh <bharrosh@panasas.com> writes:\n\n> Junio C Hamano wrote:\n> \n>> \"reset --hard\" has *ALWAYS* meant to be destructive --- discarding\n>> potential local cruft is the whole point of the operation.\n>\n> I was under the impression that --hard means working-directory-also\n> as opposed to tree-and-index-only. Nothing to do with \n> destructive-discarding.\n\nThen you should revise your impression, as it is simply *WRONG*.  When\nI say something about history of git, I know what I am talking about ;-)\n\nReset has been about nuking local changes from the very beginning.  That\nis why it removes MERGE_HEAD, rr-cache/MERGE_RR as well as removing\nconflicted stages in the index and reverts local changes from the worktree.\n\nIt is \"my worktree state is a mess, and I cannot even describe nor care\nwhich paths are dirty --- just get rid of the local changes so that I can\nstart working cleanly from a checkout of HEAD\".\n"},{"id":"81104","messageId":"4862171F.6070505@panasas.com","threadId":"14112","inReplyTo":"7vr6al3m24.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Boaz Harrosh","fromEmail":"bharrosh@panasas.com","sentAt":"2008-06-25T09:59:59Z","receivedAt":"2008-06-25T09:59:59Z","isPatch":true,"sender":{"key":"bharrosh@panasas.com","avatar":"https://gravatar.com/avatar/347e426f8ca0409f6891ceeefd4c3c2d8769608382323057efeaa362b4c3dbf3?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Boaz Harrosh <bharrosh@panasas.com> writes:\n> \n>> Junio C Hamano wrote:\n>>\n>>> \"reset --hard\" has *ALWAYS* meant to be destructive --- discarding\n>>> potential local cruft is the whole point of the operation.\n>> I was under the impression that --hard means working-directory-also\n>> as opposed to tree-and-index-only. Nothing to do with \n>> destructive-discarding.\n> \n> Then you should revise your impression, as it is simply *WRONG*.  When\n> I say something about history of git, I know what I am talking about ;-)\n> \n> Reset has been about nuking local changes from the very beginning.  That\n> is why it removes MERGE_HEAD, rr-cache/MERGE_RR as well as removing\n> conflicted stages in the index and reverts local changes from the worktree.\n> \n> It is \"my worktree state is a mess, and I cannot even describe nor care\n> which paths are dirty --- just get rid of the local changes so that I can\n> start working cleanly from a checkout of HEAD\".\n\nOK Thanks, I see.\n\nI have made myself that git-move-head script that uses checkouts and\nrenames so I guess I'm happy. I used to use the --hard as a shortcut.\n\nBoaz\n"},{"id":"81105","messageId":"alpine.DEB.1.00.0806251109380.9925@racer","threadId":"14112","inReplyTo":"48620C1A.6000509@panasas.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-25T10:16:20Z","receivedAt":"2008-06-25T10:16:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\njust to add to Junio's comments:\n\nOn Wed, 25 Jun 2008, Boaz Harrosh wrote:\n\n> Junio C Hamano wrote:\n> > Steven Walter <stevenrwalter@gmail.com> writes:\n> > \n> >> @@ -225,6 +243,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n> >>  \tif (reset_type == HARD && is_bare_repository())\n> >>  \t\tdie(\"hard reset makes no sense in a bare repository\");\n> >>  \n> >> +        if (reset_type == HARD && !force && index_is_dirty()) {\n> >> +                die(\"Uncommitted changes; re-run with -f to trash them\");\n> >> +        }\n> >> +\n> > \n> > Please don't.  With your change, does the testsuite even pass?\n> > \n> > \"reset --hard\" has *ALWAYS* meant to be destructive --- discarding\n> > potential local cruft is the whole point of the operation.\n> > \n> \n> I was under the impression that --hard means working-directory-also\n> as opposed to tree-and-index-only. Nothing to do with \n> destructive-discarding.\n\nBut \"reset\" _means_ to discard something.\n\nFrankly, we could introduce \"git reset --hard --force --really \n--really-i-mean-it --do-reset-the-fscking-working-directory-NOW\", but I do \nnot think that it makes sense.\n\nIf you want to reset the working directory, you want to reset the working \ndirectory.  If you wanted to save the changes somewhere, you should have \ndone that.  We have enough ways to do that.\n\n> > Learn the lingo, and get over it.\n> \n> I did lern the lingo and got bitten.\n\nApparently not.  So again, \"reset --hard\" means to reset HEAD, index and \nworking directory to the revision you pass (defaulting to the HEAD).\n\nThe fact that you do not lose the information which used to be HEAD, is \njust a side-effect of Git storing all the revisions in one big graph.  It \nis _not_ implied by \"reset\", which, as I pointed out, means \"re-set\".\n\n> there is:\n> git-reset --clean - destructive-discarding any local changes\n\nWhat would be a \"nondestructive-discarding\", /me wonders.\n\n> git-reset --hard - move tree index and working directory to new head\n\nThat is not \"git reset --hard\".\n\n\"move\" to a new head is called \"switching branches\" in Git lingo (and BTW \nin many other SCM lingos, too, so you might just as well get used to it), \nand it is another command: \"git checkout <branch>\".\n\nIncidentally, a friend just told me that \"checkout\" is everything but \nintuitive, and he would have preferred \"git branch switch <branch>\", but \nthen settled for my proposed \"git branch --switch <branch>\", which I did \nnot have time to implement yet, unfortunately.\n\nCiao,\nDscho\n"},{"id":"81106","messageId":"1214389498.6634.10.camel@localhost","threadId":"14112","inReplyTo":"alpine.DEB.1.00.0806251109380.9925@racer","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Matthias Kestenholz","fromEmail":"mk@spinlock.ch","sentAt":"2008-06-25T10:24:58Z","receivedAt":"2008-06-25T10:24:58Z","isPatch":true,"sender":{"key":"matthias@spinlock.ch","avatar":"https://gravatar.com/avatar/bc18f396e70163d09ab458a341b1decb7e8b6ee3aa2c0c954ec20162e67c4d46?d=mp&s=160"},"body":"On Wed, 2008-06-25 at 11:16 +0100, Johannes Schindelin wrote:\n> Incidentally, a friend just told me that \"checkout\" is everything but \n> intuitive, and he would have preferred \"git branch switch <branch>\", but \n> then settled for my proposed \"git branch --switch <branch>\", which I did \n> not have time to implement yet, unfortunately.\n\nBut why? I don't want to 'branch', I want to 'checkout' another branch,\nwhich incidentally matches the git command I need to use to achieve\nthat.\n\nMatthias\n"},{"id":"81108","messageId":"486220CE.3070103@viscovery.net","threadId":"14112","inReplyTo":"alpine.DEB.1.00.0806251109380.9925@racer","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-06-25T10:41:18Z","receivedAt":"2008-06-25T10:41:18Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Schindelin schrieb:\n> Incidentally, a friend just told me that \"checkout\" is everything but \n> intuitive, and he would have preferred \"git branch switch <branch>\", but \n> then settled for my proposed \"git branch --switch <branch>\", which I did \n> not have time to implement yet, unfortunately.\n\n$ git config alias.switch checkout\n$ git switch topic\n\nHm? Notice that the command even reports back:\n\nSwitched to branch \"topic\"\n^^^^^^^^\n\n-- Hannes\n"},{"id":"81109","messageId":"20080625104605.GA10322@atn.sw.ru","threadId":"14112","inReplyTo":"1214389498.6634.10.camel@localhost","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Anton Gladkov","fromEmail":"agladkov@parallels.com","sentAt":"2008-06-25T10:46:06Z","receivedAt":"2008-06-25T10:46:06Z","isPatch":true,"sender":{"key":"agladkov@parallels.com","avatar":null},"body":"On Wed, Jun 25, 2008 at 02:24:58PM +0400, Matthias Kestenholz wrote:\n> On Wed, 2008-06-25 at 11:16 +0100, Johannes Schindelin wrote:\n> > Incidentally, a friend just told me that \"checkout\" is everything but\n> > intuitive, and he would have preferred \"git branch switch <branch>\", but\n> > then settled for my proposed \"git branch --switch <branch>\", which I did\n> > not have time to implement yet, unfortunately.\n> \n> But why? I don't want to 'branch', I want to 'checkout' another branch,\n> which incidentally matches the git command I need to use to achieve\n> that.\n\nBecause 'checkout' in other SCMs like CVS or SVN means 'get latest data from\nrepo', i.e. it acts like 'pull' or 'fetch' in git.\nAnd 'branch' means branch manipulation: creating, deleting, switching...\n\n-- \nBest regards,\n\t\tAnton\nmailto:agladkov@parallels.com\n"},{"id":"81111","messageId":"alpine.DEB.1.00.0806251332190.9925@racer","threadId":"14112","inReplyTo":"20080625104605.GA10322@atn.sw.ru","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-25T12:33:49Z","receivedAt":"2008-06-25T12:33:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 25 Jun 2008, Anton Gladkov wrote:\n\n> On Wed, Jun 25, 2008 at 02:24:58PM +0400, Matthias Kestenholz wrote:\n> > On Wed, 2008-06-25 at 11:16 +0100, Johannes Schindelin wrote:\n> > > Incidentally, a friend just told me that \"checkout\" is everything but\n> > > intuitive, and he would have preferred \"git branch switch <branch>\", but\n> > > then settled for my proposed \"git branch --switch <branch>\", which I did\n> > > not have time to implement yet, unfortunately.\n> > \n> > But why? I don't want to 'branch', I want to 'checkout' another branch,\n> > which incidentally matches the git command I need to use to achieve\n> > that.\n> \n> Because 'checkout' in other SCMs like CVS or SVN means 'get latest data \n> from repo', i.e. it acts like 'pull' or 'fetch' in git. And 'branch' \n> means branch manipulation: creating, deleting, switching...\n\nActually, I don't find this a good reason at all.  The fact that other \nSCMs bastardized a term to mean something it clearly does not mean, is \nirrelevant here.\n\nThe thing is: if we say \"let's switch branches\", what command would spring \nto mind to a (non-CVS-braindamaged) user?  Exactly: \"git branch\".  That is \nthe command that should do something with branches.\n\nCiao,\nDscho\n"},{"id":"81112","messageId":"alpine.DEB.1.00.0806251334060.9925@racer","threadId":"14112","inReplyTo":"486220CE.3070103@viscovery.net","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-25T12:38:30Z","receivedAt":"2008-06-25T12:38:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 25 Jun 2008, Johannes Sixt wrote:\n\n> Johannes Schindelin schrieb:\n> > Incidentally, a friend just told me that \"checkout\" is everything but \n> > intuitive, and he would have preferred \"git branch switch <branch>\", but \n> > then settled for my proposed \"git branch --switch <branch>\", which I did \n> > not have time to implement yet, unfortunately.\n> \n> $ git config alias.switch checkout\n> $ git switch topic\n> \n> Hm? Notice that the command even reports back:\n> \n> Switched to branch \"topic\"\n> ^^^^^^^^\n\nNice.  And now my friend says \"why does this braindamaged Git not have \nthat command by _default_?  Hmm?  It is _just as braindamaged_ as CVS!\"\n\nAnd I would not have anything reasonable for my defense.\n\nBecause Git _should_ have an intuitive command to switch branches by \ndefault.  \"git checkout\" just does not fly, especially given that it can \nbe used to revert single files (which \"git revert\" should know how to, but \ndoes not, see \nhttp://mid.gmane.org/7vlk8wshii.fsf@gitster.siamese.dyndns.org).\n\nI _do_ see a cause of confusion here, _even_ if I know Git pretty well.\n\nCiao,\nDscho\n"},{"id":"81115","messageId":"alpine.LFD.1.10.0806250907340.5393@sys-0.hiltweb.site","threadId":"14112","inReplyTo":"48620C1A.6000509@panasas.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Ian Hilt","fromEmail":"ian.hilt@gmx.com","sentAt":"2008-06-25T13:19:36Z","receivedAt":"2008-06-25T13:19:36Z","isPatch":true,"sender":{"key":"ian.hilt@gmx.com","avatar":null},"body":"On Wed, 25 Jun 2008 at 12:12pm +0300, Boaz Harrosh wrote:\n\n> Junio C Hamano wrote:\n> > Learn the lingo, and get over it.\n> > \n> \n> I did lern the lingo and got bitten. I wanted to do one thing\n> also got the other one.\n\nSomething that I think has not been emphasized enough for whatever\nreason is how _easy_ it is to test out git commands.  For example, if\nyou have a really_important_repo that you don't want to screw up, but\nyou need to do a potentially destructive thing to it, just do,\n\n$ cp -r /path/to/really_important_repo ~/test\n$ cd ~/test && git destructive\n\nand you find out whether your mental concept of what \"git destructive\"\ndoes is correct or not without possibly losing your work.\n\n\n-- \nIan Hilt\nIan.Hilt (at) gmx.com\nGnuPG key: 0x4AFC1EE3\n"},{"id":"81118","messageId":"20080625135100.GF20361@mit.edu","threadId":"14112","inReplyTo":"alpine.DEB.1.00.0806251334060.9925@racer","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2008-06-25T13:51:00Z","receivedAt":"2008-06-25T13:51:00Z","isPatch":true,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Wed, Jun 25, 2008 at 01:38:30PM +0100, Johannes Schindelin wrote:\n> > $ git config alias.switch checkout\n> > $ git switch topic\n> > \n> > Hm? Notice that the command even reports back:\n> > \n> > Switched to branch \"topic\"\n> > ^^^^^^^^\n> \n> Nice.  And now my friend says \"why does this braindamaged Git not have \n> that command by _default_?  Hmm?  It is _just as braindamaged_ as CVS!\"\n\nI agree that \"git switch\" would be a great alias to have for \"git\ncheckout\".  It is much more intuitive; traditionally, the issue has\nalways been that it's not so intuitive for existing git users, who\nhave gotten used to the existing quirks, and it people won't want to\nbreak things for the existing users.  (There are analogues to this is\nthe English language --- why is it that \"though\", \"through\", \"plough\",\n\"cough\", \"hough\", or \"tough\" don't rhyme[1]?)\n\n[1]  http://www.mipmip.org/tidbits/pronunciation.shtml\n\n> And I would not have anything reasonable for my defense.\n\nNeither does the English language; but just try changing it!\n\"Historical reasons\" is for better or for worse a very strong\nargument.\n\n> Because Git _should_ have an intuitive command to switch branches by \n> default.  \"git checkout\" just does not fly, especially given that it can \n> be used to revert single files (which \"git revert\" should know how to, but \n> does not, see \n> http://mid.gmane.org/7vlk8wshii.fsf@gitster.siamese.dyndns.org).\n\nI used to argue for this, but gave up, because no one seemed to agree\nwith me.  So now I just have the following in\n/home/tytso/bin/git-revert-file and I am very happy:\n\n#!/bin/sh\n#\nprefix=$(git rev-parse --show-prefix)\n\nfor i in $*\ndo\n        git show HEAD:$prefix$i > $i\ndone\n\nIt makes \"git revert-file <file1> <file2> <file3>\" do the right thing.\nYeah, it doesn't do enough error checking, and it doesn't handle\nfilenames with spaces, and there are probably other corner cases it\ndoesn't get right, but it's been enough to keep me happy.  :-)\n\nIf someone wants to take the above and turn it into git-rename.sh and\ntry to submit it to the git tree --- they are welcome to do it.  Or\nheck, if Junio is willing to commit that it that with the appropriate\ncleanups it would be accepted, I'd be willing to do the work.  I just\ngot tired of arguing that the concept of \"git revert-file\" was in fact\nuseful, and so its existence could be justified, which IIRC was\ndisputed the last time we went around this topic.  I know I wanted it,\nthough, so I implemented it for myself.\n\n> I _do_ see a cause of confusion here, _even_ if I know Git pretty well.\n\nAs do I....  I think the expert git users have just leared how to work\naround it, either by learning the non-linearities in the UI, or by our\nown private hacks or aliases.\n\n\t\t\t\t\t\t- Ted\n"},{"id":"81123","messageId":"63BEA5E623E09F4D92233FB12A9F794302389C2C@emailmn.mqsoftware.com","threadId":"14112","inReplyTo":"20080625104605.GA10322@atn.sw.ru","subject":"RE: [PATCH] cmd_reset: don't trash uncommitted changes unless toldto","fromName":"Craig L. Ching","fromEmail":"cching@mqsoftware.com","sentAt":"2008-06-25T14:49:16Z","receivedAt":"2008-06-25T14:49:16Z","isPatch":true,"sender":{"key":"cching@mqsoftware.com","avatar":null},"body":" \n\n> -----Original Message-----\n> From: git-owner@vger.kernel.org \n> [mailto:git-owner@vger.kernel.org] On Behalf Of Anton Gladkov\n> Sent: Wednesday, June 25, 2008 5:46 AM\n> To: Matthias Kestenholz\n> Cc: Johannes Schindelin; Boaz Harrosh; Junio C Hamano; Steven \n> Walter; git@vger.kernel.org; jeske@google.com\n> Subject: Re: [PATCH] cmd_reset: don't trash uncommitted \n> changes unless toldto\n> \n> Because 'checkout' in other SCMs like CVS or SVN means 'get \n> latest data from repo', i.e. it acts like 'pull' or 'fetch' in git.\n> And 'branch' means branch manipulation: creating, deleting, \n> switching...\n> \nCheckout, for me and a lot of people I work with, never meant \"get\nlatest data from repo\", it always meant \"get me a workspace\".  Anyway,\njust sharing a dissenting opinion, I don't agree that the checkout verb\nis used incorrectly in git.\n\n\n> --\n> Best regards,\n> \t\tAnton\n> mailto:agladkov@parallels.com\n> --\n\nCheers,\nCraig\n"},{"id":"81127","messageId":"20080625151835.GA14343@atn.sw.ru","threadId":"14112","inReplyTo":"63BEA5E623E09F4D92233FB12A9F794302389C2C@emailmn.mqsoftware.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless toldto","fromName":"Anton Gladkov","fromEmail":"agladkov@parallels.com","sentAt":"2008-06-25T15:18:35Z","receivedAt":"2008-06-25T15:18:35Z","isPatch":true,"sender":{"key":"agladkov@parallels.com","avatar":null},"body":"On Wed, Jun 25, 2008 at 06:49:16PM +0400, Craig L. Ching wrote:\n> > Because 'checkout' in other SCMs like CVS or SVN means 'get\n> > latest data from repo', i.e. it acts like 'pull' or 'fetch' in git.\n> > And 'branch' means branch manipulation: creating, deleting,\n> > switching...\n> >\n> Checkout, for me and a lot of people I work with, never meant \"get\n> latest data from repo\", it always meant \"get me a workspace\".  Anyway,\n> just sharing a dissenting opinion, I don't agree that the checkout verb\n> is used incorrectly in git.\n\nCraig,\nI'm not trying to say that git incorrectly uses 'checkout' word :)\n\n-- \nBest regards,\n\t\tAnton\nmailto:agladkov@parallels.com\n"},{"id":"81144","messageId":"7v63rx2zwf.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"20080625135100.GF20361@mit.edu","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T17:22:08Z","receivedAt":"2008-06-25T17:22:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> I used to argue for this, but gave up, because no one seemed to agree\n> with me.  So now I just have the following in\n> /home/tytso/bin/git-revert-file and I am very happy:\n>\n> #!/bin/sh\n> #\n> prefix=$(git rev-parse --show-prefix)\n>\n> for i in $*\n> do\n>         git show HEAD:$prefix$i > $i\n> done\n\nIsn't that this?\n\n        #!/bin/sh\n        exec git checkout HEAD -- \"$@\"\n"},{"id":"81170","messageId":"20080625195003.GB15077@mit.edu","threadId":"14112","inReplyTo":"7v63rx2zwf.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2008-06-25T19:50:03Z","receivedAt":"2008-06-25T19:50:03Z","isPatch":true,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Wed, Jun 25, 2008 at 10:22:08AM -0700, Junio C Hamano wrote:\n> Isn't that this?\n> \n>         #!/bin/sh\n>         exec git checkout HEAD -- \"$@\"\n\nWell, I think you really want this to handle filenames with spaces:\n\nfor i in $*\ndo\n    git checkout HEAD -- \"$i\"\ndone\n\nI still think it would be nice this as a built-in for \"git\nrevert-file\" since this is much easier to type than \"git checkout HEAD\n-- \" (all those characters and capital letters).  But if it ends up\nbeing a private shell script for people who do this a lot, that's also fine.\n\nI will say that it was not at all obvious that \"git checkout\" can also\nbe used to revert files, so it wasn't one of the man pages that looked\nfor when trying to figure out how to implement revert files.  That's\nwhy I ended up using:\n\n    git show HEAD:$prefix$i > $i\n\n      \t\t      \t     \t \t    - Ted\n"},{"id":"81172","messageId":"32541b130806251304u39c8ffdenc52904391aebd089@mail.gmail.com","threadId":"14112","inReplyTo":"20080625195003.GB15077@mit.edu","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2008-06-25T20:04:47Z","receivedAt":"2008-06-25T20:04:47Z","isPatch":true,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On 6/25/08, Theodore Tso <tytso@mit.edu> wrote:\n> On Wed, Jun 25, 2008 at 10:22:08AM -0700, Junio C Hamano wrote:\n>  >         exec git checkout HEAD -- \"$@\"\n>\n> Well, I think you really want this to handle filenames with spaces:\n>\n>  for i in $*\n>  do\n>     git checkout HEAD -- \"$i\"\n>  done\n\n\"$@\" notation actually handles spaces just fine.  It's magic that way.\n On the other hand, \"for i in $*\" does not, because all the spaces get\nsplit as part of the unquoted $* in \"for\".  Beware!\n\n>  I still think it would be nice this as a built-in for \"git\n>  revert-file\" since this is much easier to type than \"git checkout HEAD\n>  -- \" (all those characters and capital letters).  But if it ends up\n>  being a private shell script for people who do this a lot, that's also fine.\n\nHow about making \"git checkout\" default to HEAD if no revision is\nsupplied?  There's precedent for this in, say, git-diff (and I think a\nfew others).\n\nIncidentally, \"checkout <filename>\" was also the way to do a revert\noperation in CVS.  And the way to switch branches, too, iirc.  So git\nisn't being too unusual here.  That said, the commands were\ndeliberately renamed in svn because CVS was considered largely insane.\n\nHave fun,\n\nAvery\n"},{"id":"81174","messageId":"7vprq5z383.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"20080625195003.GB15077@mit.edu","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T20:09:16Z","receivedAt":"2008-06-25T20:09:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> On Wed, Jun 25, 2008 at 10:22:08AM -0700, Junio C Hamano wrote:\n>> Isn't that this?\n>> \n>>         #!/bin/sh\n>>         exec git checkout HEAD -- \"$@\"\n>\n> Well, I think you really want this to handle filenames with spaces:\n\nSorry, I do not understand that remark.  Does \"$@\" corrupt embedded spaces\nin its parameters?\n"},{"id":"81175","messageId":"7vlk0tz33n.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"32541b130806251304u39c8ffdenc52904391aebd089@mail.gmail.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T20:11:56Z","receivedAt":"2008-06-25T20:11:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Avery Pennarun\" <apenwarr@gmail.com> writes:\n\n> How about making \"git checkout\" default to HEAD if no revision is\n> supplied?  There's precedent for this in, say, git-diff (and I think a\n> few others).\n\nWon't fly.  'git checkout -- \"$@\"' is to revert to the last staged\nversion.\n\n * You say \"git checkout branch\" when you want to \"check out that branch\";\n\n * You say \"git checkout -- file\" when you want to \"check out the file\n   from the index\";\n\n * You say \"git checkout v1.5 -- file\" when you want to \"check out the\n   file out of that revision\".\n\nIt's not that hard.\n"},{"id":"81178","messageId":"32541b130806251322l478faa87gc9f2016254689022@mail.gmail.com","threadId":"14112","inReplyTo":"7vlk0tz33n.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2008-06-25T20:22:29Z","receivedAt":"2008-06-25T20:22:29Z","isPatch":true,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On 6/25/08, Junio C Hamano <gitster@pobox.com> wrote:\n> \"Avery Pennarun\" <apenwarr@gmail.com> writes:\n>\n>  > How about making \"git checkout\" default to HEAD if no revision is\n>  > supplied?  There's precedent for this in, say, git-diff (and I think a\n>  > few others).\n>\n> Won't fly.  'git checkout -- \"$@\"' is to revert to the last staged\n>  version.\n\nAh, I didn't catch the difference between HEAD and index there.\n\n>   * You say \"git checkout -- file\" when you want to \"check out the file\n>    from the index\";\n\nThe real question here is the --.  Is it strictly needed?  It's\noptional in things like git-diff, which just do their best to guess\nwhat you mean if you don't use the --.\n\nIf reset and checkout made the -- optional, then you could do:\n\ngit reset filename         # undo an accidental \"add\"\ngit checkout filename  # undo accidental modifications that haven't been added\n\n...and save git reset --hard for people willing to take that risk.\n(The fact that git-gui includes git reset --hard as a really\neasy-to-click GUI command scared me the first time I saw it, too.)\n\nI think simplifying the syntax might help to make the role of the\nindex less mysterious in the whole \"revert\" operation.  It's not\nobvious to me at all whether a revert-file ought to get the one from\nHEAD or the one from the index.  But I can easily understand and\nexplain checkout (copy index to working copy) and reset (undo an add).\n\nThanks,\n\nAvery\n"},{"id":"81180","messageId":"e06498070806251337v53260405t537e8363f797e91@mail.gmail.com","threadId":"14112","inReplyTo":"7vlk0tz33n.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Steven Walter","fromEmail":"stevenrwalter@gmail.com","sentAt":"2008-06-25T20:37:39Z","receivedAt":"2008-06-25T20:37:39Z","isPatch":true,"sender":{"key":"stevenrwalter@gmail.com","avatar":"https://avatars.githubusercontent.com/u/79127?v=4"},"body":"On Wed, Jun 25, 2008 at 4:11 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>  * You say \"git checkout branch\" when you want to \"check out that branch\";\n>\n>  * You say \"git checkout -- file\" when you want to \"check out the file\n>   from the index\";\n>\n>  * You say \"git checkout v1.5 -- file\" when you want to \"check out the\n>   file out of that revision\".\n>\n> It's not that hard.\n\nNo, it's not \"that hard.\"  But are you really claiming that it's\nbeyond improvement?\n-- \n-Steven Walter <stevenrwalter@gmail.com>\n"},{"id":"81181","messageId":"20080625203822.GA7827@mit.edu","threadId":"14112","inReplyTo":"32541b130806251304u39c8ffdenc52904391aebd089@mail.gmail.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2008-06-25T20:38:22Z","receivedAt":"2008-06-25T20:38:22Z","isPatch":true,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Wed, Jun 25, 2008 at 04:04:47PM -0400, Avery Pennarun wrote:\n> How about making \"git checkout\" default to HEAD if no revision is\n> supplied?  There's precedent for this in, say, git-diff (and I think a\n> few others).\n> \n> Incidentally, \"checkout <filename>\" was also the way to do a revert\n> operation in CVS.  And the way to switch branches, too, iirc.  So git\n> isn't being too unusual here.  That said, the commands were\n> deliberately renamed in svn because CVS was considered largely insane.\n\nThe one thing I would worry about is the potential ambiguity if you do\nsomething like \"git checkout FOOBAR\", and FOOBAR was both a branch\nname as well as a file name.  How should it be interpreted?  I'd argue\nthe real problem was we conflated two distinct operations: \"switching\nto a new branch\", and \"reverting a file\" to the same name, checkout.\n\nHence the suggestion to add a new command, \"git revert-file\", where\nthere would be no ambiguity.\n\n\t\t\t\t\t\t\t- Ted\n"},{"id":"81183","messageId":"7vd4m5z1f8.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"32541b130806251322l478faa87gc9f2016254689022@mail.gmail.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T20:48:11Z","receivedAt":"2008-06-25T20:48:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Avery Pennarun\" <apenwarr@gmail.com> writes:\n\n>>   * You say \"git checkout -- file\" when you want to \"check out the file\n>>    from the index\";\n>\n> The real question here is the --.  Is it strictly needed?  It's\n> optional in things like git-diff, which just do their best to guess\n> what you mean if you don't use the --.\n\nNo, I wrote -- only for clarity, because you can happen to have a branch\nwhose name is the same as the file.  Otherwise you can safely omit it,\njust like git-diff and any other commands that follow the -- convention.\n\nI have a work tree that has an untracked file HEAD and master just to\ncatch script breakages that forgets to place -- in appropriate places when\nthey deal with user supplied pathnames.\n"},{"id":"81185","messageId":"7v8wwtz1c1.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"20080625203822.GA7827@mit.edu","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T20:50:06Z","receivedAt":"2008-06-25T20:50:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> The one thing I would worry about is the potential ambiguity if you do\n> something like \"git checkout FOOBAR\", and FOOBAR was both a branch\n> name as well as a file name.  How should it be interpreted?  I'd argue\n> the real problem was we conflated two distinct operations: \"switching\n> to a new branch\", and \"reverting a file\" to the same name, checkout.\n\nI just replied to Avery about that.  -- is always the way to disambiguate\nbetween refs (that come before --) and paths (that come after --), not\nlimited to \"git checkout\" but with other commands such as \"git log\", \"git\ndiff\", etc.\n"},{"id":"81189","messageId":"32541b130806251358n3ab6cfc8y7a90d898b9308e12@mail.gmail.com","threadId":"14112","inReplyTo":"7vd4m5z1f8.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2008-06-25T20:58:09Z","receivedAt":"2008-06-25T20:58:09Z","isPatch":true,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On 6/25/08, Junio C Hamano <gitster@pobox.com> wrote:\n> \"Avery Pennarun\" <apenwarr@gmail.com> writes:\n> >>   * You say \"git checkout -- file\" when you want to \"check out the file\n>  >>    from the index\";\n>  >\n>  > The real question here is the --.  Is it strictly needed?  It's\n>  > optional in things like git-diff, which just do their best to guess\n>  > what you mean if you don't use the --.\n>\n> No, I wrote -- only for clarity, because you can happen to have a branch\n>  whose name is the same as the file.  Otherwise you can safely omit it,\n>  just like git-diff and any other commands that follow the -- convention.\n\nOops, I got mixed up.  Only git-reset requires the --.  Would it make\nsense to bring git-reset into line with everything else, then?\n\nThanks,\n\nAvery\n"},{"id":"81190","messageId":"20080625210535.GA8610@mit.edu","threadId":"14112","inReplyTo":"7v8wwtz1c1.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2008-06-25T21:05:35Z","receivedAt":"2008-06-25T21:05:35Z","isPatch":true,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Wed, Jun 25, 2008 at 01:50:06PM -0700, Junio C Hamano wrote:\n> I just replied to Avery about that.  -- is always the way to disambiguate\n> between refs (that come before --) and paths (that come after --), not\n> limited to \"git checkout\" but with other commands such as \"git log\", \"git\n> diff\", etc.\n\nStupid quesiton --- where is this documented?  I don't see this\ndocumented either in the man page for git or git-checkout.\n\nRegards,\n\n\t\t\t\t\t\t- Ted\n"},{"id":"81191","messageId":"7vwskdxl6z.fsf_-_@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"32541b130806251358n3ab6cfc8y7a90d898b9308e12@mail.gmail.com","subject":"Re* [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T21:24:04Z","receivedAt":"2008-06-25T21:24:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Avery Pennarun\" <apenwarr@gmail.com> writes:\n\n> On 6/25/08, Junio C Hamano <gitster@pobox.com> wrote:\n>> \"Avery Pennarun\" <apenwarr@gmail.com> writes:\n>> >>   * You say \"git checkout -- file\" when you want to \"check out the file\n>>  >>    from the index\";\n>>  >\n>>  > The real question here is the --.  Is it strictly needed?  It's\n>>  > optional in things like git-diff, which just do their best to guess\n>>  > what you mean if you don't use the --.\n>>\n>> No, I wrote -- only for clarity, because you can happen to have a branch\n>>  whose name is the same as the file.  Otherwise you can safely omit it,\n>>  just like git-diff and any other commands that follow the -- convention.\n>\n> Oops, I got mixed up.  Only git-reset requires the --.  Would it make\n> sense to bring git-reset into line with everything else, then?\n\nAh, interesting.  It appears that the current \"reset in C\" inherited that\nbug from the scripted version.  It works most of the time without --\nexcept for one place.\n\n\t# prove that the work tree is clean...\n\t$ git reset --hard\n\tHEAD is now at 7b7f39e Fix use after free() in builtin-fetch\n\t$ git diff\n        $ git diff --cached\n\n\t# what's different since HEAD^?\n        $ git diff --name-only HEAD^\n        builtin-fetch.c\n\n        # reset the path\n        $ git reset HEAD^ builtin-fetch.c\n\tbuiltin-fetch.c: needs update\n\n\t# prove that HEAD did not move\n\t$ git rev-parse HEAD\n\t7b7f39eae6ab0bbcc68d3c42a5b23595880e528f\n\t# prove that work tree did not change\n        $ git diff HEAD\n        # prove that index has old version\n\t$ git diff --cached HEAD^\n\nReset is about resetting the index and --hard option tells it to propagate\nthe change down to the work tree as well.\n\nThere is no \"reset to the index\", so \"reset -- path\" would be a redundant\nway to spell \"reset HEAD path\" or \"reset HEAD -- path\" which is even more\nredundant.\n\nAs long as builti-fetch.c is not a valid ref, you should be able to get\nout of the above mess by any one of:\n\n\t$ git reset builtin-fetch.c\n        $ git reset -- builtin-fetch.c\n        $ git reset HEAD builtin-fetch.c\n\nbut the first one complains, saying builtin-fetch.c is not a valid ref.\n\nThis may help.\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex f34acb1..c7d60f5 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -194,9 +194,21 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \treflog_action = args_to_str(argv);\n \tsetenv(\"GIT_REFLOG_ACTION\", reflog_action, 0);\n \n-\tif (i < argc && strcmp(argv[i], \"--\"))\n-\t\trev = argv[i++];\n-\n+\t/*\n+\t * Possible arguments are:\n+\t *\n+\t * git reset <rev> <paths>...\n+\t * git reset <rev> -- <paths>...\n+\t * git reset -- <paths>...\n+\t * git reset <paths>...\n+\t */\n+\tif (i < argc && strcmp(argv[i], \"--\")) {\n+\t\t/* could be \"git reset <path>\" */\n+\t\tif (get_sha1(argv[i+1], sha1))\n+\t\t\t;\n+\t\telse\n+\t\t\trev = argv[i++];\n+\t}\n \tif (get_sha1(rev, sha1))\n \t\tdie(\"Failed to resolve '%s' as a valid ref.\", rev);\n \n"},{"id":"81192","messageId":"7vskv1xkq9.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"7vwskdxl6z.fsf_-_@gitster.siamese.dyndns.org","subject":"Re: Re* [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T21:34:06Z","receivedAt":"2008-06-25T21:34:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> \"Avery Pennarun\" <apenwarr@gmail.com> writes:\n>\n>> On 6/25/08, Junio C Hamano <gitster@pobox.com> wrote:\n>>> \"Avery Pennarun\" <apenwarr@gmail.com> writes:\n>>> >>   * You say \"git checkout -- file\" when you want to \"check out the file\n>>>  >>    from the index\";\n>>>  >\n>>>  > The real question here is the --.  Is it strictly needed?  It's\n>>>  > optional in things like git-diff, which just do their best to guess\n>>>  > what you mean if you don't use the --.\n>>>\n>>> No, I wrote -- only for clarity, because you can happen to have a branch\n>>>  whose name is the same as the file.  Otherwise you can safely omit it,\n>>>  just like git-diff and any other commands that follow the -- convention.\n>>\n>> Oops, I got mixed up.  Only git-reset requires the --.  Would it make\n>> sense to bring git-reset into line with everything else, then?\n>\n> Ah, interesting.  It appears that the current \"reset in C\" inherited that\n> bug from the scripted version.  It works most of the time without --\n> except for one place.\n>\n> \t# prove that the work tree is clean...\n> \t$ git reset --hard\n> \tHEAD is now at 7b7f39e Fix use after free() in builtin-fetch\n> \t$ git diff\n>         $ git diff --cached\n>\n> \t# what's different since HEAD^?\n>         $ git diff --name-only HEAD^\n>         builtin-fetch.c\n>\n>         # reset the path\n>         $ git reset HEAD^ builtin-fetch.c\n> \tbuiltin-fetch.c: needs update\n>\n> \t# prove that HEAD did not move\n> \t$ git rev-parse HEAD\n> \t7b7f39eae6ab0bbcc68d3c42a5b23595880e528f\n> \t# prove that work tree did not change\n>         $ git diff HEAD\n>         # prove that index has old version\n> \t$ git diff --cached HEAD^\n>\n> Reset is about resetting the index and --hard option tells it to propagate\n> the change down to the work tree as well.\n>\n> There is no \"reset to the index\", so \"reset -- path\" would be a redundant\n> way to spell \"reset HEAD path\" or \"reset HEAD -- path\" which is even more\n> redundant.\n>\n> As long as builti-fetch.c is not a valid ref, you should be able to get\n> out of the above mess by any one of:\n>\n> \t$ git reset builtin-fetch.c\n>         $ git reset -- builtin-fetch.c\n>         $ git reset HEAD builtin-fetch.c\n>\n> but the first one complains, saying builtin-fetch.c is not a valid ref.\n>\n> This may help.\n>\n> diff --git a/builtin-reset.c b/builtin-reset.c\n> index f34acb1..c7d60f5 100644\n> --- a/builtin-reset.c\n> +++ b/builtin-reset.c\n> @@ -194,9 +194,21 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>  \treflog_action = args_to_str(argv);\n>  \tsetenv(\"GIT_REFLOG_ACTION\", reflog_action, 0);\n>  \n> -\tif (i < argc && strcmp(argv[i], \"--\"))\n> -\t\trev = argv[i++];\n> -\n> +\t/*\n> +\t * Possible arguments are:\n> +\t *\n> +\t * git reset <rev> <paths>...\n> +\t * git reset <rev> -- <paths>...\n> +\t * git reset -- <paths>...\n> +\t * git reset <paths>...\n> +\t */\n> +\tif (i < argc && strcmp(argv[i], \"--\")) {\n> +\t\t/* could be \"git reset <path>\" */\n> +\t\tif (get_sha1(argv[i+1], sha1))\n\ntypofix: s/i+1/i/;\n\n> +\t\t\t;\n> +\t\telse\n> +\t\t\trev = argv[i++];\n> +\t}\n>  \tif (get_sha1(rev, sha1))\n>  \t\tdie(\"Failed to resolve '%s' as a valid ref.\", rev);\n>  \n"},{"id":"81194","messageId":"7vod5pxknh.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"20080625210535.GA8610@mit.edu","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-25T21:35:46Z","receivedAt":"2008-06-25T21:35:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> On Wed, Jun 25, 2008 at 01:50:06PM -0700, Junio C Hamano wrote:\n>> I just replied to Avery about that.  -- is always the way to disambiguate\n>> between refs (that come before --) and paths (that come after --), not\n>> limited to \"git checkout\" but with other commands such as \"git log\", \"git\n>> diff\", etc.\n>\n> Stupid quesiton --- where is this documented?  I don't see this\n> documented either in the man page for git or git-checkout.\n\nYou are asking a wrong person.  My git knowledge mostly comes from\nyearlong reading of the mailing list articles, and doing a bit myself also\nhelps ;-).\n"},{"id":"81198","messageId":"20080625224428.GB12567@machine.or.cz","threadId":"14112","inReplyTo":"20080625203822.GA7827@mit.edu","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2008-06-25T22:44:28Z","receivedAt":"2008-06-25T22:44:28Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Wed, Jun 25, 2008 at 04:38:22PM -0400, Theodore Tso wrote:\n> On Wed, Jun 25, 2008 at 04:04:47PM -0400, Avery Pennarun wrote:\n> > How about making \"git checkout\" default to HEAD if no revision is\n> > supplied?  There's precedent for this in, say, git-diff (and I think a\n> > few others).\n> > \n> > Incidentally, \"checkout <filename>\" was also the way to do a revert\n> > operation in CVS.  And the way to switch branches, too, iirc.  So git\n> > isn't being too unusual here.  That said, the commands were\n> > deliberately renamed in svn because CVS was considered largely insane.\n> \n> The one thing I would worry about is the potential ambiguity if you do\n> something like \"git checkout FOOBAR\", and FOOBAR was both a branch\n> name as well as a file name.  How should it be interpreted?  I'd argue\n> the real problem was we conflated two distinct operations: \"switching\n> to a new branch\", and \"reverting a file\" to the same name, checkout.\n> \n> Hence the suggestion to add a new command, \"git revert-file\", where\n> there would be no ambiguity.\n\nJust to chime in, this reminds me of Cogito - it had cg-switch for\nswitching branches (like git checkout) and cg-restore for restoring\nfiles in working copy (like git checkout, too; but you would pass -f if\nyou wanted to overwrite existing copy).\n\n(Though, Cogito didn't quite get it right either since it tried to\noverload cg-switch with the git branch functionality of creating new\nbranches. I still didn't quite come in terms with any UI model of the\nbranches I know about.)\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nThe last good thing written in C++ was the Pachelbel Canon. -- J. Olson\n"},{"id":"81221","messageId":"7vk5gduguq.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"7vwskdxl6z.fsf_-_@gitster.siamese.dyndns.org","subject":"Re: Re* [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T01:26:05Z","receivedAt":"2008-06-26T01:26:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Reset is about resetting the index and --hard option tells it to propagate\n> the change down to the work tree as well.\n>\n> There is no \"reset to the index\", so \"reset -- path\" would be a redundant\n> way to spell \"reset HEAD path\" or \"reset HEAD -- path\" which is even more\n> redundant.\n>\n> As long as builti-fetch.c is not a valid ref, you should be able to get\n> out of the above mess by any one of:\n>\n>         $ git reset builtin-fetch.c\n>         $ git reset -- builtin-fetch.c\n>         $ git reset HEAD builtin-fetch.c\n>\n> but the first one complains, saying builtin-fetch.c is not a valid ref.\n>\n> This may help.\n\nAnd this is a cleaned-up patch that is more through.\n\n-- >8 --\nAllow \"git-reset path\" when unambiguous\n\nResetting a selected set of index entries is done with\n\"git reset -- paths\" syntax, but we did not allow -- to be omitted\neven when the command is unambiguous.\n\nThis updates the command to follow the general rule:\n\n * When -- appears, revs come before it, and paths come after it;\n\n * When there is no --, earlier ones are revs and the rest are paths, and\n   we need to guess.  When lack of -- marker forces us to guess, we\n   protect from user errors and typoes by making sure what we treat as\n   revs do not appear as filenames in the work tree, and what we treat as\n   paths do appear as filenames in the work tree, and by erroring out if\n   that is not the case.  We tell the user to disambiguate by using -- in\n   such a case.\n\nwhich is employed elsewhere in the system.\n\nWhen this rule is applied to \"reset\", because we can have only zero or one\nrev to the command, the check can be slightly simpler than other programs.\nWe have to check only the first one or two tokens after the command name\nand options, and when they are:\n\n    -- A:\n    \tno explicit rev given; \"A\" and whatever follows it are paths.\n\n    A --:\n        explicit rev \"A\" given and whatever follows the \"--\" are paths.\n\n    A B:\n       \"A\" could be rev or path and we need to guess.  \"B\" could\n       be missing but if exists that (and everything that follows) would\n       be paths.\n\nSo we apply the guess only in the last case and only to \"A\" (not \"B\" and\nwhat comes after it).\n\n * As long as \"A\" is unambiguously a path, index entries for \"A\", \"B\" (and\n   everything that follows) are reset to the HEAD revision.\n\n * If \"A\" is unambiguously a rev, on the other hand, the index entries for\n   \"B\" (and everything that follows) are reset to the \"A\" revision.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n\n---\n\n builtin-reset.c  |   39 ++++++++++++++++++++++++++++++++++-----\n t/t7102-reset.sh |   47 +++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 81 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex f34acb1..a032169 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -194,8 +194,40 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \treflog_action = args_to_str(argv);\n \tsetenv(\"GIT_REFLOG_ACTION\", reflog_action, 0);\n \n-\tif (i < argc && strcmp(argv[i], \"--\"))\n-\t\trev = argv[i++];\n+\t/*\n+\t * Possible arguments are:\n+\t *\n+\t * git reset [-opts] <rev> <paths>...\n+\t * git reset [-opts] <rev> -- <paths>...\n+\t * git reset [-opts] -- <paths>...\n+\t * git reset [-opts] <paths>...\n+\t *\n+\t * At this point, argv[i] points immediately after [-opts].\n+\t */\n+\n+\tif (i < argc) {\n+\t\tif (!strcmp(argv[i], \"--\")) {\n+\t\t\ti++; /* reset to HEAD, possibly with paths */\n+\t\t} else if (i + 1 < argc && !strcmp(argv[i+1], \"--\")) {\n+\t\t\trev = argv[i];\n+\t\t\ti += 2;\n+\t\t}\n+\t\t/*\n+\t\t * Otherwise, argv[i] could be either <rev> or <paths> and\n+\t\t * has to be unambigous.\n+\t\t */\n+\t\telse if (!get_sha1(argv[i], sha1)) {\n+\t\t\t/*\n+\t\t\t * Ok, argv[i] looks like a rev; it should not\n+\t\t\t * be a filename.\n+\t\t\t */\n+\t\t\tverify_non_filename(prefix, argv[i]);\n+\t\t\trev = argv[i++];\n+\t\t} else {\n+\t\t\t/* Otherwise we treat this as a filename */\n+\t\t\tverify_filename(prefix, argv[i]);\n+\t\t}\n+\t}\n \n \tif (get_sha1(rev, sha1))\n \t\tdie(\"Failed to resolve '%s' as a valid ref.\", rev);\n@@ -205,9 +237,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tdie(\"Could not parse object '%s'.\", rev);\n \thashcpy(sha1, commit->object.sha1);\n \n-\tif (i < argc && !strcmp(argv[i], \"--\"))\n-\t\ti++;\n-\n \t/* git reset tree [--] paths... can be used to\n \t * load chosen paths from the tree into the index without\n \t * affecting the working tree nor HEAD. */\ndiff --git a/t/t7102-reset.sh b/t/t7102-reset.sh\nindex 39ba141..96d1508 100755\n--- a/t/t7102-reset.sh\n+++ b/t/t7102-reset.sh\n@@ -428,4 +428,51 @@ test_expect_success '--mixed refreshes the index' '\n \ttest_cmp expect output\n '\n \n+test_expect_success 'disambiguation (1)' '\n+\n+\tgit reset --hard &&\n+\t>secondfile &&\n+\tgit add secondfile &&\n+\ttest_must_fail git reset secondfile &&\n+\ttest -z \"$(git diff --cached --name-only)\" &&\n+\ttest -f secondfile &&\n+\ttest ! -s secondfile\n+\n+'\n+\n+test_expect_success 'disambiguation (2)' '\n+\n+\tgit reset --hard &&\n+\t>secondfile &&\n+\tgit add secondfile &&\n+\trm -f secondfile &&\n+\ttest_must_fail git reset secondfile &&\n+\ttest -n \"$(git diff --cached --name-only -- secondfile)\" &&\n+\ttest ! -f secondfile\n+\n+'\n+\n+test_expect_success 'disambiguation (3)' '\n+\n+\tgit reset --hard &&\n+\t>secondfile &&\n+\tgit add secondfile &&\n+\trm -f secondfile &&\n+\ttest_must_fail git reset HEAD secondfile &&\n+\ttest -z \"$(git diff --cached --name-only)\" &&\n+\ttest ! -f secondfile\n+\n+'\n+\n+test_expect_success 'disambiguation (4)' '\n+\n+\tgit reset --hard &&\n+\t>secondfile &&\n+\tgit add secondfile &&\n+\trm -f secondfile &&\n+\ttest_must_fail git reset -- secondfile &&\n+\ttest -z \"$(git diff --cached --name-only)\" &&\n+\ttest ! -f secondfile\n+'\n+\n test_done\n"},{"id":"81223","messageId":"alpine.DEB.1.00.0806260121000.4503@eeepc-johanness","threadId":"14112","inReplyTo":"20080625224428.GB12567@machine.or.cz","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-26T01:59:25Z","receivedAt":"2008-06-26T01:59:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 26 Jun 2008, Petr Baudis wrote:\n\n> On Wed, Jun 25, 2008 at 04:38:22PM -0400, Theodore Tso wrote:\n> > On Wed, Jun 25, 2008 at 04:04:47PM -0400, Avery Pennarun wrote:\n> > > How about making \"git checkout\" default to HEAD if no revision is \n> > > supplied?  There's precedent for this in, say, git-diff (and I think \n> > > a few others).\n> > > \n> > > Incidentally, \"checkout <filename>\" was also the way to do a revert \n> > > operation in CVS.  And the way to switch branches, too, iirc.  So \n> > > git isn't being too unusual here.  That said, the commands were \n> > > deliberately renamed in svn because CVS was considered largely \n> > > insane.\n> > \n> > The one thing I would worry about is the potential ambiguity if you do \n> > something like \"git checkout FOOBAR\", and FOOBAR was both a branch \n> > name as well as a file name.  How should it be interpreted?  I'd argue \n> > the real problem was we conflated two distinct operations: \"switching \n> > to a new branch\", and \"reverting a file\" to the same name, checkout.\n> > \n> > Hence the suggestion to add a new command, \"git revert-file\", where \n> > there would be no ambiguity.\n> \n> Just to chime in, this reminds me of Cogito - it had cg-switch for\n> switching branches (like git checkout) and cg-restore for restoring\n> files in working copy (like git checkout, too; but you would pass -f if\n> you wanted to overwrite existing copy).\n\nYeah, I was kinda disappointed that this part of Cogito never was picked \nup by Git \"core\".\n\nI really liked the fact that Cogito was a test-bed for UI enhancements, \nand miss it a bit.  It was nice how it drove the UI enhancements of Git, \nand I am a little sad that Cogito was discontinued.  (And no, I do not see \nany contender picking up the task of driving Git's UI in the right \ndirection.)\n \n> (Though, Cogito didn't quite get it right either since it tried to \n> overload cg-switch with the git branch functionality of creating new \n> branches. I still didn't quite come in terms with any UI model of the \n> branches I know about.)\n\nTo the contrary, I think that \"git branch --create <branch>\" _should_ \nswitch to the newly created branch.  That is what users expect, and Cogito \ngot that right.\n\nCiao,\nDscho\n"},{"id":"81230","messageId":"7vprq4u66i.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"7vod5pxknh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-26T05:16:37Z","receivedAt":"2008-06-26T05:16:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Theodore Tso <tytso@mit.edu> writes:\n>\n>> On Wed, Jun 25, 2008 at 01:50:06PM -0700, Junio C Hamano wrote:\n>>> I just replied to Avery about that.  -- is always the way to disambiguate\n>>> between refs (that come before --) and paths (that come after --), not\n>>> limited to \"git checkout\" but with other commands such as \"git log\", \"git\n>>> diff\", etc.\n>>\n>> Stupid quesiton --- where is this documented?  I don't see this\n>> documented either in the man page for git or git-checkout.\n>\n> You are asking a wrong person.  My git knowledge mostly comes from\n> yearlong reading of the mailing list articles, and doing a bit myself also\n> helps ;-).\n\nI couldn't find a good central place to place this as this is more or less\nused consistently throughout the UI (log, diff, grep, and then I just\nfixed reset as well).\n\nWhereever the description should end up to be in, here is what I think we\nshould talk about.\n\n\n Documentation/gitcli.txt |   37 +++++++++++++++++++++++++++++++++----\n 1 files changed, 33 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt\nindex 8fb5d88..2316049 100644\n--- a/Documentation/gitcli.txt\n+++ b/Documentation/gitcli.txt\n@@ -13,8 +13,37 @@ gitcli\n DESCRIPTION\n -----------\n \n-This manual describes best practice in how to use git CLI.  Here are\n-the rules that you should follow when you are scripting git:\n+This manual describes the convention used throughout git CLI.\n+\n+Many commands take revisions (most often \"commits\", but sometimes\n+\"tree-ish\", depending on the context and command) and paths as their\n+arguments.  Here are the rules:\n+\n+ * Revisions come first and then paths.\n+   E.g. in `git diff v1.0 v2.0 arch/x86 include/asm-x86`,\n+   `v1.0` and `v2.0` are revisions and `arch/x86` and `include/asm-x86`\n+   are paths.\n+\n+ * When an argument can be misunderstood as either a revision or a path,\n+   they can be disambiguated by placing `\\--` between them.\n+   E.g. `git diff \\-- HEAD` is, \"I have a file called HEAD in my work\n+   tree.  Please show changes between the version I staged in the index\n+   and what I have in the work tree for that file\". not \"show difference\n+   between the HEAD commit and the work tree as a whole\".  You can say\n+   `git diff HEAD \\--` to ask for the latter.\n+\n+ * Without disambiguating `\\--`, git makes a reasonable guess, but errors\n+   out and asking you to disambiguate when ambiguous.  E.g. if you have a\n+   file called HEAD in your work tree, `git diff HEAD` is ambiguous, and\n+   you have to say either `git diff HEAD \\--` or `git diff \\-- HEAD` to\n+   disambiguate.\n+\n+When writing a script that is expected to handle random user-input, it is\n+a good practice to make it explicit which arguments are which by placing\n+disambiguating `\\--` at appropriate places.\n+\n+Here are the rules regarding the \"flags\" that you should follow when you are\n+scripting git:\n \n  * it's preferred to use the non dashed form of git commands, which means that\n    you should prefer `\"git foo\"` to `\"git-foo\"`.\n@@ -34,8 +63,8 @@ the rules that you should follow when you are scripting git:\n    if you happen to have a file called `HEAD` in the work tree.\n \n \n-ENHANCED CLI\n-------------\n+ENHANCED OPTION PARSER\n+----------------------\n From the git 1.5.4 series and further, many git commands (not all of them at the\n time of the writing though) come with an enhanced option parser.\n \n"},{"id":"81233","messageId":"486329C9.8020801@op5.se","threadId":"14112","inReplyTo":"48620C1A.6000509@panasas.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2008-06-26T05:31:53Z","receivedAt":"2008-06-26T05:31:53Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Boaz Harrosh wrote:\n> Junio C Hamano wrote:\n>> Steven Walter <stevenrwalter@gmail.com> writes:\n>>\n>>> @@ -225,6 +243,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>>>  \tif (reset_type == HARD && is_bare_repository())\n>>>  \t\tdie(\"hard reset makes no sense in a bare repository\");\n>>>  \n>>> +        if (reset_type == HARD && !force && index_is_dirty()) {\n>>> +                die(\"Uncommitted changes; re-run with -f to trash them\");\n>>> +        }\n>>> +\n>> Please don't.  With your change, does the testsuite even pass?\n>>\n>> \"reset --hard\" has *ALWAYS* meant to be destructive --- discarding\n>> potential local cruft is the whole point of the operation.\n>>\n> \n> I was under the impression that --hard means working-directory-also\n> as opposed to tree-and-index-only. Nothing to do with \n> destructive-discarding. If it is then something is missing.\n> I need 2 distinct functions. You combine to functions under\n> one command.\n> \n>> Learn the lingo, and get over it.\n>>\n> \n> I did lern the lingo and got bitten. I wanted to do one thing\n> also got the other one.\n> \n> there is:\n> git-reset --clean - destructive-discarding any local changes\n> git-reset --hard - move tree index and working directory to new head\n> \n> How can I separate between them, Please\n> \n\nThere is a \"--hard\" after one of them. It reads like this:\n\ngit reset --hard  ;# move current branch to random point in history\n                   # discarding working tree and index state\n\ngit reset --mixed ;# move current branch to random point in history\n                   # discard the index but keep the working tree\n\ngit reset --soft  ;# move current branch to random point in history,\n                   # leaving index and working tree intact\n\nIt's under OPTIONS in the man-page. --mixed is default.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"81277","messageId":"20080626115550.GA23058@atjola.homenet","threadId":"14112","inReplyTo":"7v63rx2zwf.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2008-06-26T11:55:50Z","receivedAt":"2008-06-26T11:55:50Z","isPatch":true,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2008.06.25 10:22:08 -0700, Junio C Hamano wrote:\n> Theodore Tso <tytso@mit.edu> writes:\n> \n> > I used to argue for this, but gave up, because no one seemed to agree\n> > with me.  So now I just have the following in\n> > /home/tytso/bin/git-revert-file and I am very happy:\n> >\n> > #!/bin/sh\n> > #\n> > prefix=$(git rev-parse --show-prefix)\n> >\n> > for i in $*\n> > do\n> >         git show HEAD:$prefix$i > $i\n> > done\n> \n> Isn't that this?\n> \n>         #!/bin/sh\n>         exec git checkout HEAD -- \"$@\"\n\nI thought so at first, too, but there's one difference. Ted's version\ndoesn't affect the index, while yours does. Of course I cannot tell if\nTed actually intended not to touch the index ;-)\n\nBjörn\n"},{"id":"81279","messageId":"vpqy74scsln.fsf@bauges.imag.fr","threadId":"14112","inReplyTo":"20080625135100.GF20361@mit.edu","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2008-06-26T12:01:56Z","receivedAt":"2008-06-26T12:01:56Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> for i in $*\n\nDetail: you meant \"$@\", your version isn't whitespace-robust.\n\n-- \nMatthieu\n"},{"id":"81280","messageId":"alpine.DEB.1.00.0806261306060.9925@racer","threadId":"14112","inReplyTo":"20080626115550.GA23058@atjola.homenet","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-26T12:07:40Z","receivedAt":"2008-06-26T12:07:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 26 Jun 2008, Björn Steinbrink wrote:\n\n> On 2008.06.25 10:22:08 -0700, Junio C Hamano wrote:\n> > Theodore Tso <tytso@mit.edu> writes:\n> > \n> > > I used to argue for this, but gave up, because no one seemed to agree\n> > > with me.  So now I just have the following in\n> > > /home/tytso/bin/git-revert-file and I am very happy:\n> > >\n> > > #!/bin/sh\n> > > #\n> > > prefix=$(git rev-parse --show-prefix)\n> > >\n> > > for i in $*\n> > > do\n> > >         git show HEAD:$prefix$i > $i\n> > > done\n> > \n> > Isn't that this?\n> > \n> >         #!/bin/sh\n> >         exec git checkout HEAD -- \"$@\"\n> \n> I thought so at first, too, but there's one difference. Ted's version\n> doesn't affect the index, while yours does. Of course I cannot tell if\n> Ted actually intended not to touch the index ;-)\n\nWhile we are nit-picking: Ted's version does not respect autocrlf, while \nJunio's does.\n\nOh, and Junio's version works with spaces and other funny stuff in file \nnames, while Ted's does not.\n\nOh, and error checking is correct in Junio's version.\n\nI am sure there are more differences.\n\nCiao,\nDscho\n"},{"id":"81281","messageId":"alpine.DEB.1.00.0806261308420.9925@racer","threadId":"14112","inReplyTo":"vpqy74scsln.fsf@bauges.imag.fr","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-26T12:09:10Z","receivedAt":"2008-06-26T12:09:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 26 Jun 2008, Matthieu Moy wrote:\n\n> Theodore Tso <tytso@mit.edu> writes:\n> \n> > for i in $*\n> \n> Detail: you meant \"$@\", your version isn't whitespace-robust.\n\nIn that case, you'd have to quote the variables in \"$prefix$i\" and \"> $i\", \ntoo.\n\nCiao,\nDscho\n"},{"id":"81284","messageId":"86k5gcs7u7.fsf@lola.quinscape.zz","threadId":"14112","inReplyTo":"alpine.DEB.1.00.0806261308420.9925@racer","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2008-06-26T12:23:44Z","receivedAt":"2008-06-26T12:23:44Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi,\n>\n> On Thu, 26 Jun 2008, Matthieu Moy wrote:\n>\n>> Theodore Tso <tytso@mit.edu> writes:\n>> \n>> > for i in $*\n>> \n>> Detail: you meant \"$@\", your version isn't whitespace-robust.\n>\n> In that case, you'd have to quote the variables in \"$prefix$i\" and \"> $i\", \n> too.\n\nYes for the first, no for the second I think.  But it would do no harm\nin the second case, either.  Certainly makes it less shell-dependent.\n\nIn fact, just tried it with bash and dash:\n\ndak@lisa:/tmp$ zup=\"a b  c\"\ndak@lisa:/tmp$ echo x > $zup\nbash: $zup: ambiguous redirect\ndak@lisa:/tmp$ echo x > \"$zup\"\ndak@lisa:/tmp$ rm \"$zup\"\ndak@lisa:/tmp$ dash\n$ zup=\"a b  c\"\n$ echo x > $zup\n$ ls -l \"$zup\"\n-rw-r--r-- 1 dak dak 2 2008-06-26 14:18 a b  c\n$ \n\nDash gets it right.  Bash just talks nonsense.  \"ambiguous redirect\" is\nnot a useful message at all.  There is nothing ambiguous here.\n\nAnyway, bash is prevalent enough to warrant the quoting.\n\n-- \nDavid Kastrup\n"},{"id":"81285","messageId":"20080626123539.GA22219@atjola.homenet","threadId":"14112","inReplyTo":"alpine.DEB.1.00.0806261306060.9925@racer","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2008-06-26T12:35:39Z","receivedAt":"2008-06-26T12:35:39Z","isPatch":true,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2008.06.26 13:07:40 +0100, Johannes Schindelin wrote:\n> On Thu, 26 Jun 2008, Björn Steinbrink wrote:\n> \n> > On 2008.06.25 10:22:08 -0700, Junio C Hamano wrote:\n> > > Theodore Tso <tytso@mit.edu> writes:\n> > > \n> > > > I used to argue for this, but gave up, because no one seemed to agree\n> > > > with me.  So now I just have the following in\n> > > > /home/tytso/bin/git-revert-file and I am very happy:\n> > > >\n> > > > #!/bin/sh\n> > > > #\n> > > > prefix=$(git rev-parse --show-prefix)\n> > > >\n> > > > for i in $*\n> > > > do\n> > > >         git show HEAD:$prefix$i > $i\n> > > > done\n> > > \n> > > Isn't that this?\n> > > \n> > >         #!/bin/sh\n> > >         exec git checkout HEAD -- \"$@\"\n> > \n> > I thought so at first, too, but there's one difference. Ted's version\n> > doesn't affect the index, while yours does. Of course I cannot tell if\n> > Ted actually intended not to touch the index ;-)\n> \n> While we are nit-picking: Ted's version does not respect autocrlf, while \n> Junio's does.\n> \n> Oh, and Junio's version works with spaces and other funny stuff in file \n> names, while Ted's does not.\n> \n> Oh, and error checking is correct in Junio's version.\n> \n> I am sure there are more differences.\n\nI didn't intend to nit-pick, sorry if it looked like that. Not touching\nthe index might have been a conscious decision, but obviously I must\nhave missed some email that made it clear that it was intended to also\nrevert the index entry. Very sorry...\n\nThanks for the information on autocrlf though, didn't know that show\ndoesn't care about that.\n\nBjörn\n"},{"id":"81294","messageId":"K8mYvOxbzHDUUveNqGY1qxKxQCRRn4fCJly5l1F_bU9bM2LdvpAD1g@cipher.nrlssc.navy.mil","threadId":"14112","inReplyTo":"20080625022610.GB20361@mit.edu","subject":"Re: why is git destructive by default? (i suggest it not be!)","fromName":"Brandon Casey","fromEmail":"casey@nrlssc.navy.mil","sentAt":"2008-06-26T15:13:27Z","receivedAt":"2008-06-26T15:13:27Z","isPatch":false,"sender":{"key":"drafnel@gmail.com","avatar":"https://avatars.githubusercontent.com/u/921167?v=4"},"body":"Theodore Tso wrote:\n> On Tue, Jun 24, 2008 at 04:07:57PM -0700, Junio C Hamano wrote:\n>>> Instead, I've just learned to be careful and my use of git reset\n>>> --hard is mainly for historical reasons.\n>> This makes it sound as if avoiding \"reset --hard\" is a good thing, but I\n>> do not understand why.\n> \n> Well, it was Brandon Casey who was asserting that git reset --hard was\n> evil, which I generally don't agree with.\n\nI definitely don't think 'reset --hard' is evil. I _do_ think it is somewhat\nof an advanced command. It should be used where it is appropriate. I think\nit is a misuse of the command if it is used in place of checkout, which I got\nthe impression might be the case.\n\nYou described resetting an integration branch, Junio does a similar thing\nwith pu and these are both valid uses. This is what I was talking about\nwhen I said that usually when I use reset I don't care about the state of\nthe branch I am resetting. I also agree there are many other valid uses for\n'git reset --hard'.\n\n-brandon\n"},{"id":"81296","messageId":"32541b130806260855o691d444bpc0843e5f51639430@mail.gmail.com","threadId":"14112","inReplyTo":"alpine.DEB.1.00.0806261306060.9925@racer","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Avery Pennarun","fromEmail":"apenwarr@gmail.com","sentAt":"2008-06-26T15:55:46Z","receivedAt":"2008-06-26T15:55:46Z","isPatch":true,"sender":{"key":"apenwarr@gmail.com","avatar":"https://avatars.githubusercontent.com/u/20592?v=4"},"body":"On 6/26/08, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> While we are nit-picking: Ted's version does not respect autocrlf, while\n>  Junio's does.\n\nIs it intentional that git-show doesn't respect autocrlf, or just an oversight?\n\nAvery\n"},{"id":"81298","messageId":"4863C087.1070304@freescale.com","threadId":"14112","inReplyTo":"486329C9.8020801@op5.se","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Jon Loeliger","fromEmail":"jdl@freescale.com","sentAt":"2008-06-26T16:15:03Z","receivedAt":"2008-06-26T16:15:03Z","isPatch":true,"sender":{"key":"jdl@jdl.com","avatar":"https://gravatar.com/avatar/75ce9a10b151acd2c28ec4ab2136dba7b2ff1634530bd04b155981a749d08a64?d=mp&s=160"},"body":"Andreas Ericsson wrote:\n\n> There is a \"--hard\" after one of them. It reads like this:\n> \n> git reset --hard  ;# move current branch to random point in history\n>                   # discarding working tree and index state\n> \n> git reset --mixed ;# move current branch to random point in history\n>                   # discard the index but keep the working tree\n> \n> git reset --soft  ;# move current branch to random point in history,\n>                   # leaving index and working tree intact\n\nI always thought that these would be best presented in\na linear ordering so that the effects were clearly\nshown in an \"increasing\" way:\n\n--soft\n    - touches one thing\n\n--mixed\n    - touches one thing and a second\n    - this is the default\n\n--hard\n    - touches one thing, a second and a third\n\nWant a patch down that line?\n\njdl\n"},{"id":"81303","messageId":"alpine.DEB.1.00.0806261848230.9925@racer","threadId":"14112","inReplyTo":"32541b130806260855o691d444bpc0843e5f51639430@mail.gmail.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-06-26T17:49:33Z","receivedAt":"2008-06-26T17:49:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 26 Jun 2008, Avery Pennarun wrote:\n\n> On 6/26/08, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > While we are nit-picking: Ted's version does not respect autocrlf, \n> > while Junio's does.\n> \n> Is it intentional that git-show doesn't respect autocrlf, or just an \n> oversight?\n\nFunny.  I seem to have answered exactly the same question a few days ago.\n\n\"git show\" is meant to show the contents of an object.  It does not \noperate on a working directory.  It does not even _need_ a working \ndirectory.\n\nSo, no, it is _not_ an oversight.\n\nHth,\nDscho\n"},{"id":"81503","messageId":"7vabh6plyh.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"20080627193325.6117@nanako3.lavabit.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-27T22:11:34Z","receivedAt":"2008-06-27T22:11:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":" しらいしななこ <nanako3@lavabit.com> writes:\n\n> Quoting Junio C Hamano <gitster@pobox.com>:\n>\n>> > Theodore Tso <tytso@mit.edu> writes:\n>> > ...\n>> >> Stupid quesiton --- where is this documented?  I don't see this\n>> >> documented either in the man page for git or git-checkout.\n>> >\n>> > You are asking a wrong person.  My git knowledge mostly comes from\n>> > yearlong reading of the mailing list articles, and doing a bit myself also\n>> > helps ;-).\n>> \n>> I couldn't find a good central place to place this as this is more or less\n>> used consistently throughout the UI (log, diff, grep, and then I just\n>> fixed reset as well).\n>> \n>> Whereever the description should end up to be in, here is what I think we\n>> should talk about.\n>\n> Because it is where the convention that is used in all of the UI is\n> described, I think gitcli documentation is an appropriate place.\n\nI am still not convinced it is the best place but I guess it would be\nbetter than not documenting it anywhere.\n\n> Don't you also want to talk about distinction between --cached and\n> --index that new people are often confused about?  These options are\n> defined consistently across commands but people who do not know it bring\n> up discussions to rename --cached to some commands to --index to make it\n> inconsistent and waste your time every once in a while.\n"},{"id":"81522","messageId":"20080628090642.6117@nanako3.lavabit.com","threadId":"14112","inReplyTo":"7vabh6plyh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"しらいしななこ","fromEmail":"nanako3@lavabit.com","sentAt":"2008-06-28T00:06:42Z","receivedAt":"2008-06-28T00:06:42Z","isPatch":true,"sender":{"key":"nanako3@lavabit.com","avatar":"https://gravatar.com/avatar/3777b9e201c5883a62b1a6fdf7c53f2d712d1d80989146063ea861e33aad72a8?d=mp&s=160"},"body":"Quoting Junio C Hamano <gitster@pobox.com>:\n\n>> Because it is where the convention that is used in all of the UI is\n>> described, I think gitcli documentation is an appropriate place.\n>\n> I am still not convinced it is the best place but I guess it would be\n> better than not documenting it anywhere.\n>\n>> Don't you also want to talk about distinction between --cached and\n>> --index that new people are often confused about?  These options are\n>> defined consistently across commands but people who do not know it bring\n>> up discussions to rename --cached to some commands to --index to make it\n>> inconsistent and waste your time every once in a while.\n\nDo you have any comment on the --index/--cached issue?\n\n-- \nNanako Shiraishi\nhttp://ivory.ap.teacup.com/nanako3/\n"},{"id":"81585","messageId":"20080629073212.6117@nanako3.lavabit.com","threadId":"14112","inReplyTo":"20080628090642.6117@nanako3.lavabit.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"しらいしななこ","fromEmail":"nanako3@lavabit.com","sentAt":"2008-06-28T22:32:12Z","receivedAt":"2008-06-28T22:32:12Z","isPatch":true,"sender":{"key":"nanako3@lavabit.com","avatar":"https://gravatar.com/avatar/3777b9e201c5883a62b1a6fdf7c53f2d712d1d80989146063ea861e33aad72a8?d=mp&s=160"},"body":"Quoting myself:\n\n>>> Don't you also want to talk about distinction between --cached and\n>>> --index that new people are often confused about?  These options are\n>>> defined consistently across commands but people who do not know it bring\n>>> up discussions to rename --cached to some commands to --index to make it\n>>> inconsistent and waste your time every once in a while.\n>\n> Do you have any comment on the --index/--cached issue?\n\nJunio, I haven't heard back from you yet and I take it you mean you are not interested in a vague suggestion but in a concrete patch, so here it is.\n\n-- cut here -- 8< -- cut here --\n\nSubject: [PATCH] gitcli: Document meaning of --cached and --index\n\nWe saw this explanation repeated on the git mailing list a\nfew times. Even though the description of individual options\nto particular commands are explained in their manual pages,\nthe reason behind choosing which is which has been clearly\nexplained in none of the documentation.\n\nSigned-off-by: Nanako Shiraishi <nanako3@lavabit.com>\n---\n Documentation/gitcli.txt |   38 +++++++++++++++++++++++++++++++++++++-\n 1 files changed, 37 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt\nindex 2316049..281a987 100644\n--- a/Documentation/gitcli.txt\n+++ b/Documentation/gitcli.txt\n@@ -133,9 +133,45 @@ $ git describe --abbrev 10 HEAD  # NOT WHAT YOU MEANT\n ----------------------------\n \n \n+NOTES ON FREQUENTLY CONFUSED OPTIONS\n+------------------------------------\n+\n+Many commands that can work on files in the working tree\n+and/or in the index can take `--cached` and/or `--index`\n+options.  Sometimes people incorrectly think that, because\n+the index was originally called cache, these two are\n+synonyms.  They are _not_ --- these two options mean very\n+different things.\n+\n+ * The `--cached` option is used to ask a command that\n+   usually works on files in the working tree to _only_ work\n+   with the index.  For example, `git grep`, when used\n+   without a commit to specify from which commit to look for\n+   strings in, usually works on files in the working tree,\n+   but with the `--cached` option, it looks for strings in\n+   the index.\n+\n+ * The `--index` option is used to ask a command that\n+   usually works on files in the working tree to _also_\n+   affect the index.  For example, `git stash apply` usually\n+   merges changes recorded in a stash to the working tree,\n+   but with the `--index` option, it also merges changes to\n+   the index as well.\n+\n+`git apply` command can be used with `--cached` and\n+`--index` (but not at the same time).  Usually the command\n+only affects the files in the working tree, but with\n+`--index`, it patches both the files and their index\n+entries, and with `--cached`, it modifies only the index\n+entries.\n+\n+See also http://marc.info/?l=git&m=116563135620359 and\n+http://marc.info/?l=git&m=119150393620273 for further\n+information.\n+\n Documentation\n -------------\n-Documentation by Pierre Habouzit.\n+Documentation by Pierre Habouzit and others.\n \n GIT\n ---\n\n-- \n1.5.6\n\n-- \nNanako Shiraishi\nhttp://ivory.ap.teacup.com/nanako3/\n"},{"id":"81627","messageId":"7vhcbcd3g9.fsf@gitster.siamese.dyndns.org","threadId":"14112","inReplyTo":"20080629073212.6117@nanako3.lavabit.com","subject":"Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-06-29T08:56:38Z","receivedAt":"2008-06-29T08:56:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"しらいしななこ <nanako3@lavabit.com> writes:\n\n> Quoting myself:\n>\n>>>> Don't you also want to talk about distinction between --cached and\n>>>> --index that new people are often confused about?  These options are\n>>>> defined consistently across commands but people who do not know it bring\n>>>> up discussions to rename --cached to some commands to --index to make it\n>>>> inconsistent and waste your time every once in a while.\n>...\n> Junio, I haven't heard back from you yet and I take it you mean you are not interested in a vague suggestion but in a concrete patch, so here it is.\n\nWell, I pretended that I did not notice the original question because I\nwanted to avoid addressing this issue ;-<.\n\nWhile I think --index/--cached are not particularly good pair of words, as\none of the old article you pointed at in your documentation update states,\nto describe the distinction, the commands do use them consistently to\ndifferentiate what are operands to them clearly and consistently.  In that\nsense, your documentation update would probably be a good idea.  At least\nit makes it easier for new people to learn it just once, and once you know\nthe distinction and remember which is which, you can reuse the knowledge\nto all the commands.\n\n\nEven though I myself freely admit that these are not particularly a good\npair of words, it is not realistic to expect --index and --cached to ever\nbe deprecated.  But every time this comes up on the list, people end up\nwasting time trying to repaint this old bikeshed.  That is the primary\nreason I did not want to talk about it.  It still is possible to introduce\na pair of synonyms that new people might find more descriptive, perhaps:\n\n\t--index-only = --cached\n        --index-also = --index\n\nbut I personally do not think it would add much value to the system..\n\n> +NOTES ON FREQUENTLY CONFUSED OPTIONS\n> +------------------------------------\n\nHmmm.  Is this in anticipation for more \"confusing\" options described in\nthis section?\n\n> +Many commands that can work on files in the working tree\n> +and/or in the index can take `--cached` and/or `--index`\n> +options.  Sometimes people incorrectly think that, because\n> +the index was originally called cache, these two are\n> +synonyms.  They are _not_ --- these two options mean very\n\nIn e-mails we use _underscore_ but I do not think it works in AsciiDoc.\nI'll munge this (you have others below) to \"*not*\".  Also unlike LaTeX,\nlong dash is two dashes (--), not three (---).\n"},{"id":"299224","messageId":"willow-jeske-01l5kwGPFEDjCc7b","threadId":"14112","inReplyTo":"m3mylbl0xb.fsf@localhost.localdomain","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:02Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"To re-ask the same question I asked in my last post, using your ascii\npictures...\n\n\nLet's assume we're here..\n\n.<---.<---.<---A<---X<---Y    <--- master\n\\\n\\--B<---C    <--- customer_A_branch <=== HEAD\n\n\nAnd this person and everyone else moves their head pointers back to master\nwithout merging:\n\n\n.<---.<---.<---A<---X<---Y    <--- master              <=== HEAD\n\\\n\\--B<---C    <--- customer_A_branch\n\n\nNow, five years down the road, our tree looks like:\n\n\n.<---A<---X<---Y<---.<--.<--.(3 years of changes)<---ZZZ<--- master  <=== HEAD\n\\\n\\--B<---C   <--- customer_A_branch\n\nAnd someone does:\n\ngit-branch -f customer_A_branch ZZZ\n\nTo bring us to:\n\n.<---A<---X<---Y<---.<--.(3 years of changes)<---ZZZ<--- master  <=== HEAD\n\\                                           \\\n\\--B<---C                                   \\-- customer_A_branch\n\n\n..at this point, will a GC keep \"B<--C\", or garbage collect the commits and\nthrow them away?\n"},{"id":"299225","messageId":"willow-jeske-01l5lTEoFEDjCVta","threadId":"14112","inReplyTo":"20080624081601.GA2692@sigill.intra.peff.net","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:03Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"This is mostly moot since I've understood that it's easy to set git to never\nGC. I guess I'm curious about why those GC fields would ever be set to anything\nother than never?\n\n-- Jeff King wrote:\n> No. Git keeps the reachable DAG. So if the DAG is part of development\n> that is merged into one of your long running branches, or if you keep\n> around the branch that points to it, it will never go away.\n\nRight, that's what I thought.\n\nI'm not primarily concerned with what developers can do to their local git\nrepositories. I'm concerned with what the default sync operations can let them\ndo to the crown-jewels in the 'central organization repositories' which\neveryone is periodically pushing to.\n\nI like that deleting a branch in your repo does not cause it to be deleted in\nother repos. Presumably in an  organization we could prevent the central repo\nfrom ever accepting branch deletes from developers. (without some kind of\nauthorization)\n\nDoes it have the same protection for all operations that can cause DAGs to be\ndangling? For example, if they branch -f\" and push the branch?\n\n---\n\nAgain it's simple enough for me to just set the GC times to \"never\" on the\nserver, and I find git pretty pleasing because I'm a\nshort-attention-span-comitter. On a perforce or cvs repository, I frequently\ntar up subtrees between commits, so i don't lose my work -- git is light-years\nahead of this.\n\nQuite a bit of my fear of losing data came from some issues in the git-gui. I'm\ntrying out git on a windows project, and windows-shells just don't work right,\nso I'm using the \"Git Gui\". It turns out right-clicking on a history entry in\nthe gui has no checkout option, and the only option it does have which will let\nyou move the tree to that place is \"reset --hard\".. since this was the easiest\nthing to find in the GUI, I assumed it was the right way to do it, and then all\nmy more recent changes disappeared. It doesn't seem to have reflog\nfunctionality, so I couldn't find any way to get back all my changes. I ended\nup having an old history window that I did another reset --head in back to the\nlatest change, but I got scared about what git was doing underneath. The docs\nclearly explained that it will garbage collect dangling refs, and frankly the\ninformation about how often this happens is buried so deep I had no idea what\nthe frequency was.\n"},{"id":"299227","messageId":"willow-jeske-01l5pWdEFEDjCjLX","threadId":"14112","inReplyTo":"200806241322.14224.jnareb@gmail.com","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:05Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Jakub Narebski wrote:\n> If they are using '-f', i.e. force, they should know and be sure what\n> they are doing; it is not much different from 'rm -f *'.\n\nSure, no problem. I don't want the ability to \"rm -f *\". I'm raising my hand\nand saying \"I don't want the power to do these things, so just turn off all the\ngit commands that could be destructive and give me an alternate way to do the\nworkflows I need to do\". Just like a normal user on a unix machine doesn't run\naround with the power to rm -f /etc all the time, even though they may be able\nto su to root.\n\nLet me guess, you're always running euid==0. :)\n"},{"id":"299229","messageId":"willow-jeske-01l61=64jMFEDjCiBE","threadId":"14112","inReplyTo":"m31w2mlki4.fsf@localhost.localdomain","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:07Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"> -- David Jeske wrote:\n>> - improve the man page description of \"reset --hard\"\n>> - standardize all the potentially destructive operations\n>> (after gc) on \"-f/--force\" to override\n>\n> The thing is 'force' is not always the most descriptive word\n> for the behavior that you propose enabling with --force.\nI'm not talking about switching \"git reset --hard\" to \"git reset -f\". I'm\ntalking about requiring a \"-f\" option to \"git reset --hard\" when it would\ndestroy or dangle information.\n\n(a) If you have a clean working directory which is fully checked in and has\nanother branch tag other than the current branch tag, then \"git reset --hard\n<commitish>\" is non-destructive, and would complete happily.\n\n(b) If you have local modifications to working files it would complain \"hey,\nyour working files are dirty, 'reset --hard' will blow them away, either revert\nthem or use -f\". This is what Boaz asked for, and I doubt it would change along\nwould alter workflow much for people who are using \"git reset --hard\" to toss\nattempted patches (since they were fully committed anyhow), or even undo a\nclone or pull operation. If people use it as a combo \"revert and reset\", they\nwould notice.\n\n(c) If the current location is only pointed to by the current branch (which you\nare going to move with 'reset --hard') tell the user that those changes will be\ndangling and will be eligible for garbage collection if they move the branch.\nWhat to do in this case seems more controversial. I would prefer for this to\nerror with \"either label these changes with 'branch', or use 'reset --hard -f'\nto force us to leave these in the reflog unnamed\".  --- Some here say that\nbeing in the reflog is enough, and the -f is overkill here. If we define\ndestructive as dropping code-commits, then that's true. If we define\ndestructive as leaving code-commits unreferenced, then -f is warranted.\nPersonally, I'd rather git help me avoid dropping the NAMES to tips, because\neven with GC-never, I don't really want to find myself crawling through SHA1\nhashes and visualization trees to find them later, when git could have reminded\nme to name a branch that would conveniently show up in 'git branch'. It's easy\nenough to avoid dropping the names, or force git to not care with '-f'. I\npersonally would like to avoid dealing with reflog or SHA1 hashes 99% of the\ntime.\n\n> 'gc' is another command that has been mentioned along\n> with its '--aggressive' option.\n\nThis was an accident. When I made my \"mv --aggressive\" joke I was NOT intending\nto reference \"gc --aggressive\", that is just a coincidence. I was trying to\nmake up another 'semi-dangerous sounding name that might or not might be\ndestructive\". It's comical that it's in use for gc. I don't see any\nrelationship between \"gc --aggressive\" and destructive behavior.\n\nHowever, there IS a situation to require a \"-f\" on a, because again, \"-f\" would\nbe required for operations which destroy commits. If we think commits being in\nthe reflog is good enough to hold onto them, and users are thinking that items\nbeing in the reflog are 'safe', then a GC where reflog entry expiration is\ngoing to cause DAG entries to be removed could print an error like:\n\nerror: the following entries are beyond the expiration time,\n...<base branchname>/<commit-ish>: 17 commits, 78 lines, 3 authors\n...use diff <commit-ish> , to see the changes\n...use gc -f, to cause them to be deleted\n\nThis wouldn't happen very often, and would make \"gc\" a safe operation even on\ntrees with shorter expiration time. In fact, if this were the way it worked, I\nmight set my GC back from never to \"30 days\", because this would not only allow\nme to safely cleanup junk, but it would also allow me to catch unnamed and\ndangling references before they became so old I didn't remember what to name\nthem.\n\nThis would make a \"non forced gc\" safe from throwing away commits, but still\nmake it really easy to do so for people who want to. Likewise, we could make\nany \"auto-gc\" that happens not forced by default.\n"},{"id":"299230","messageId":"willow-jeske-01l64jJSFEDjCc0Q","threadId":"14112","inReplyTo":"FmVFerrNVumRho9GZZwRiHrXV_hb12J_P_hSYUBnFhcCFiMGdtdCrg@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:08Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Brandon Casey wrote:\n> I only have the same advice I gave to Boaz. I think you should try to adjust\n> your workflow so that 'git reset' is not necessary. It seems that for the\n> functions you're trying to perform, 'checkout' and 'branch' should be used\n> rather than 'reset'.\n\nEven when I change my workflow to avoid 'reset', I believe that the\nuser-interface of git will be stronger if it is a simpler expression of the\nsame functionality. One way to simplify it is to use convention that is\nstandardized across a set of tools so we don't have to learn every little\nnuance of every little feature independently.\n\nTwo things I'd like to make it easy for users to never do are:\n- delete data\n- cause refs to be dangling\n\nTherefore, I'd like a simple convention I can apply across all commands, so\nthat if users never do them, they'll never do either of the above things. I'm\nnot alone.\n\nI think some of the impedance mismatch between my suggestions, and current\nusage, has to do with where I'd like to be next. This is a meaty topic, I'll\nstart another thread on \"policy and mechanism for less-connected clients\".\n\n> I'm not sure why you want to use reset so often. If there is something in the\n> documentation that led you to want to use reset maybe it can be changed so\nthat\n> other users are not led in the same way.\n\nYes, it's a problem in the git-gui and the \"reset --hard\" documentation. I'm\nworking on a patch.\n"},{"id":"299249","messageId":"willow-jeske-01l5cKsCFEDjC=91MX","threadId":"14112","inReplyTo":"jeske@willow=01l5V7waFEDjChmh","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:45:54Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"As a new user, I'm finding git difficult to trust, because there are operations\nwhich are destructive by default and capable of inadvertently throwing hours or\ndays of work into the bit bucket.\n\nMore problematic, those commands have no discernible pattern that shows their\ndanger, and they need to be used to do typical everyday things. I'm starting to\nfeel like I need to use another source control system on top of the git\nrepository in case I make a mistake.  My philosophy is simple, I never never\nnever want to throw away changes, you shouldn't either. Disks are cheaper than\nprogrammer hours. I can understand wanting to keep things tidy, so I can\nunderstand ways to correct the 'easily visible changes', and also avoid pushing\nthem to other trees, but I don't understand why git needs to delete things.\n\nFor example, the following commands seem capable of totally destroying hours or\ndays of work. Some of them need to be used regularly to do everyday things, and\nthere is no pattern among them spelling out danger.\n\ngit reset --hard          : if another branch name hasn't been created\ngit rebase\ngit branch -D <branch>    : if branch hasn't been merged\ngit branch -f <new>       : if new exists and hasn't been merged\ngit branch -m <old> <new> : if new exists and hasn't been merged\n\nI've heard from a couple users that the solution to these problems is to \"go\ndig what you need out of the log, it's still in there\". However, it's only in\nthere until the log is garbage collected. This either means they are\ndestructive operations, or we expect \"running without ever collecting the log\"\nto be a valid mode of operation... which I doubt is the case.\n\nQuestion: How about assuring ALL operations can be done non-destructivly by\ndefault? Then make destructive things require an explicit action that follows a\ncommon pattern.\n\nSuggestion Illustration\n-----------------------\n\nBelow is one illustration of how these commands could be changed to be entirely\nnon-destructive, while retaining the current functionality. It also allows you\nto destroy stuff if you have lawyers breathing down your neck, or really really\ncan't afford the hard drive space for a couple lines of text (though I'll\npersonally make a donation to anyone in this state!) :)\n\n1) Require the \"--destroy\" flag for ANY git operation which is capable of\ndestroying data such that it is unrecoverable. A narrow view of this is to only\nconsider checked-in repository data, and not metadata, such as the location of\na branchname. However, the broad view would be to include all/most metadata.\n\n2) Make a pattern for branch names which are kept in the local tree, not\nincluded in push/pull, not modifiable without first renaming, and not shown by\ndefault when viewing all branch history. For example, \"local-<date>-*\"\n\n3) make 'git reset --hard <commit>' safe\n\nAutomatically commit working set and make a branch name (if necessary) to avoid\nchanges being thrown away. The branch name could be of the form\n\"local-<date>-reset-<user>-<date>\". If the user really wants to destroy it,\nthey could use the dangerous version \"git reset --hard --destroy\", or they\ncould just \"git branch -d --destroy <branchname>\" afterwords. Most users would\ndo neither.\n\n4) make 'git rebase' safe\n\n'rebase' would make a branch name before performing its operation, assuring it\nwas easy to get back to the previous state. Currently, \"git rebase\" turns this:\n\nA---B---C topic\n/\nD---E---F---G master\n\nInto this:\n\nA'--B'--C' topic\n/\nD---E---F---G master\n\n.. and in turn destroys the original changes. It would instead create this:\n\nA--B--C (x)    A'--B'--C' (y)\n/              /\nD---E------F-------G master\n\n(x) - local-<date>-rebase-topic-<commit for G>\n(y) - topic\n\n5) make 'git branch' follow rule 1 above (safe without --destroy)\n\nUsing any of the following commands without --destroy would cause them to\ncreate a branch \"local-<date>-rename-<old branch name>\", to prevet the\ndestruction of the old branch location:\n\ngit branch -d <branchname>\ngit branch -M <old> <new>\ngit branch -f <branchname>\n"},{"id":"299250","messageId":"willow-jeske-01l5e9cgFEDjCh3F","threadId":"14112","inReplyTo":"alpine.LFD.1.10.0806232213360.2979@xanadu.home","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:45:56Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Nicolas Pitre wrote:\n>> or we expect \"running without ever collecting the log\"\n>> to be a valid mode of operation... which I doubt is the case.\n>\n> Why not?\n\nIs see the hole I left in my logic, so let me restate.\n\n... or we expect \"human parsing of the the log\" is a valid common\nuser-interface for non-git developers.\n"},{"id":"299251","messageId":"willow-jeske-01l5g9o4FEDjCXMB","threadId":"14112","inReplyTo":"alpine.LFD.1.10.0806232356340.2979@xanadu.home","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:45:58Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Nicolas Pitre wrote:\n> I hope you'll feel much safer then.\n\nI moved a branch around and then deleted it, and I don't see any record in the\nreflog of where it was, or that it ever was.\n\nAm I missing something about how branches are used? I see some language in \"git\ntag\" about how attempts are made to assure that others can't move around\nsemi-immutable tags during push, but I don't see any such language about\nbranches. What prevents someone from accidentally deleting an old branch that\nnobody is watching, but is important to the history and then not noticing as gc\nsilently deletes the old deltas?\n\nI've had need to pull out versions several years old multiple times in my\ncareer, so this is the kind of thing I'm thinking about.\n\ngit config --global gc.reflogexpire            \"10 years\"'\ngit config --global gc.reflogexpireunreachable \"10 years\"\n\nMakes me feel safer that the data will be in there, but even with the reflog\nand access to the repository, I doubt I could FIND the place an old branch was\nsupposed to be if it was inadvertently deleted in a 2-million line source tree.\nAm I just looking in the wrong places?\n"},{"id":"299252","messageId":"willow-jeske-01l5izRzFEDjCdyL","threadId":"14112","inReplyTo":"32541b130806232220r292d691cn5bf5f9976126aa29@mail.gmail.com","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:45:59Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"Thanks for all the helpful responses...\n\n-- Avery Pennarun wrote:\n> git's philosophy is different. Branches are really just \"temporary\n> tags\". A merge operation doesn't just copy data from one branch to\n> another: it actually joins the two histories together, so you can then\n> trace back through the exact history of the merged branches, commit by\n> commit. \"git log\" will show each checkin to *either* branch\n> individually, instead of just one big \"merge\" checkin.\n\nIf branches are \"temporary tags\" how do I see the actual code they had working\nin their branch before they merged it?\n\nI'm reading about rebase, and it sounds like something I would want to forever\ndisallow on my git repository, because it looks like it rewrites history and\nmakes it impossible to get to the state of the tree they actually had working\nbefore the merge. However, something you say below both clarifies and confuses\nthis.\n\nAm I understanding this wrong?\n\n> The end result is that even if you delete the source branch after\n> doing a merge, nothing is actually lost.\n\n..and what if you never merge? That branch-pointer points to useful information\nabout a development attempt, but it was never merged. (imagine a different\ndevelopment path was taken) They never created a tag because it's not clear\nwhen that work was \"done\" (unlike a release, which is much more well\nunderstood). What prevents someone from deleting the branch-pointer or moving\nit to a different part of the tree, causing that set of changes to be a\ndangling ref lost in a sea of refs. Later when someone goes back looking for\nit, how would they ever find it in a sea of tens of thousands of checkins?\n\n> Thus, there's no reason for git to try to make branches impossible\n> to lose, as they are in svn.\n\nBefore I set the GC times to \"100 years\", there was a HUGE reason for git to\nmake those branch-pointers impossible to lose, because by default if you lose\nthem git actually garbage collects them and throws the diffs away after 90\ndays!\n\n> Another way to think of it is that svn's concept of a \"branch\" is\n> actually the \"reflog\" in git. (svn records which data a particular\n> branch name points to over time, just like git's reflog does.) git\n> branches are something else entirely; a git branch always points at\n> only a single commit, and has no history of its own.\n\nThat's sort of helpful, and sort of confusing. I think of git's branches as\n\"branch pointers to the head of a linked-list of states of the tree\".\n\nAs long as you keep those refs without deleting them, and you keep that branch\npointer to the head, you can walk back through the history of that branch. If\nmultiple developers are working in the branch (and not using rebase, and not\ngarbage collecting), can't you even go track down the working state of their\nlocal clients while they were working before they merged?\n\nIf I'm understanding all that right, it's exactly the kind of functionality I\nwant -- the ability to reproduce the state of all working history, exactly as\nit was when the code was actually working in someone's client a long time ago,\nbefore they merged it to the mainline. Except the standard model seems to be to\nlet the system \"garbage collect\" all that history, and toss it away as\nunimportant -- and in some cases it seems to even provide developers with ways\nto more aggressively assure garbage collection makes it disappear.\n\nAm I expecting too much out of git? It doesn't really feel like a source\ncontrol system for an organization that wants to save everything, forever, even\nwhen those people and trees and home directories disappear. It feels like a\ndistributed patch manager that is much more automatic than sending around\ndiffs, but isn't overly concerned with providing access to old history. (which,\nduh, is no surprise given that's what I expect it's doing for linux kernel)\n"},{"id":"299253","messageId":"willow-jeske-01l5kbGzFEDjCX3J","threadId":"14112","inReplyTo":"20080624072455.GF19224@sigill.intra.peff.net","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:46:00Z","isPatch":false,"sender":{"key":"jeske@google.com","avatar":null},"body":"-- Jeff King wrote:\n> I think you are confusing two aspects of history.\n>\n> There is the commit DAG, which says \"at some time T, the files were at\n> some state S, and the commit message by author A was M\". And those\n> commits form a chain so you can see how the state of the files\n> progressed. And anything that is reachable through that history will\n\nokay.\n\n> always be kept by git, and you can always go back to any point.\n\n..are you saying that if I reset --hard, or delete a branch ref, or do a\nrebase, and then do a GC beyond the GC timeout, that git will NEVER throw away\nany of those DAGs? (the actual source diffs committed)\n\n> And the ref history is what gets garbage collected. Most people are fine\n> with that, because they care about the actual commit history, and the\n> reflog is just a convenient way of saying \"oops, what was happening\n> yesterday?\" But if you really care, then by all means, set the reflog\n> expiration much higher.\n\nMy (possibly flawed) understanding was that it drops any DAG sections that are\nnot referenced by valid refs which are older than the GC timeout.\n\nIt came from wording like this in the docs:\n\n\"The optional configuration variable gc.reflogExpireUnreachable\ncan be set to indicate how long historical reflog entries which\nare not part of the current branch should remain available in\nthis repository. These types of entries are generally created\nas a result of using git commit --amend or git rebase and are the\ncommits prior to the amend or rebase occurring. Since\nthese changes are not part of the current project most users\n^^^^^^^^^^^^^\nwill want to expire them sooner. This option defaults to 30 days.\"\n\nIn the above, I resolve \"these changes\" to \"commits prior to the amend\" in the\nprevious sentence.\n\n\"git-gc tries very hard to be safe about the garbage it collects.\nIn particular, it will keep not only objects referenced by your\ncurrent set of branches and tags, but also objects referenced by\nthe index, remote tracking branches, refs saved by\ngit-filter-branch(1) in refs/original/, or reflogs (which may\nreferences commits in branches that were later amended or rewound).\"\n\nIn the above, I resolve \"keep .. only objects referenced by your current set of\nbranches and tags [and some other stuff]\" to \"commmits in the DAG pointed to by\nrefs [and other stuff]\".\nAre you saying this GC process will never collect source diffs in the DAG?\n"}]}