{"thread":{"id":"43110","subject":"Re: [RFC] Introduce \"git stage\" (along with some heresy)","startedAt":"2006-12-01T17:36:00Z","lastAt":"2006-12-02T22:33:34Z","messageCount":5,"participants":["Sam Vilain","Carl Worth","Wink Saville","Marko Macek"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"297242","messageId":"87slfzfri7.wl%cworth@cworth.org","threadId":"43110","inReplyTo":null,"subject":"[RFC] Introduce \"git stage\" (along with some heresy)","fromName":"Carl Worth","fromEmail":"cworth@cworth.org","sentAt":"2006-12-01T17:36:00Z","receivedAt":"2006-12-01T17:36:00Z","isPatch":false,"sender":{"key":"cworth@cworth.org","avatar":"https://gravatar.com/avatar/3746dc28cde609bdbd7f939058356e7e2bbd16d21e32274df0725eb3d998bc5b?d=mp&s=160"},"body":"[This message, (yes,another long one from me), proposes 3 changes. The\nfirst should be uncontroversial I think, while the second and third\nare clear heresy, (and the second would require some amount of\nre-training or re-configuration by existing git user). Pick and choose\nas you see fit. I don't think they actually depend on each other,\nthough I'll present them here as parts of a whole.]\n\nChange #1: Add \"git stage\" command, use \"--staged\" instead of \"--index\"\n=======================================================================\nIf we're going to start describing the index as a \"staging area\" let's\nmake the command set reflect that as well. I propose a new \"git stage\"\ncommand that is intended for human use when wanting to do a staged\ncommit.\n\nThen, a few other commands that currently have --index or --cached\narguments could switch to --staged as well.\n\nWith this change here is a summary of some of the primary git commands\n(that are relevant to the current discussion):\n\nadd\t\tShove a file's contents into git's staging area\n\nstage\t\tShove a file's contents into git's staging area\n\nrm\t\tRemove a file from git's staging area\n\ndiff\t\tShow what's changed in working tree compared to\n\t\tstaging area\n\ndiff --staged\tShow what's changed in staging area compared to latest\n\t\tcommit\n\ncommit\t\tCreate a new commit from the contents of the staging area\n\ncommit -a\tUpdate the contents of all files in the staging area,\n\t\tand create a new commit from the new staging area\n\ncommit files...\tCreate a new commit that differs from the latest\n\t\tcommit only in files... (which get new content from\n\t\tthe current working tree). Staged content of other\n\t\tfiles (if any) will not be committed.\n\nI hope that so far (in this email) I haven't said anything very\ncontentious. This is basically just a summary of the existing behavior\nwith things like \"update-index\" and \"--cached\" changed to \"stage\" and\n\"--staged\".\n\nThe introduction of this new \"stage\" command would be a very minor\nchange. If you're not particularly picky about names, it might be seen\nas having no impact at all, (or even slightly negative since \"add\" and\n\"stage\" could be considered equivalent). If you are picky about names\nyou might consider it slightly better to \"add\" when adding a new file\nand to \"stage\" when you want to put some content into the staging area.\n\nOK, so now let me start in with my heresy[*].\n\nTo start with I'd like to group the above command into two groups such\nthat one can be understood without a need to understand the purpose of\nthe staging area. Note: the goal here is not to lie about the staging\narea. It will still be mentioned in the documentation for any command\nthat needs to mention it, but in a way that a user can easily ignore\nthose portions at first. So the grouping is:\n\nWithout staging\n---------------\nadd\nrm\ndiff\ncommit -a\ncommit files...\n\nWith staging\n------------\nstage\ndiff --staged\ncommit\n\nSo far, that's just a re-grouping. No names or semantics have been\nchanged.\n\nChange #2: Make a staged commit an explicit act\n===============================================\nThe \"-a\" stands out to me here as the only command-line option needed\nin the first list, and the only command in the second list that\nperforms a staged operation by default. So change number to is to\nredefine \"commit\" to mean what \"commit -a\" meant before and to require\na new command-line option for staged committing, (the best naming I\nhave so far is \"commit --staged\" with a shortcut of \"commit -i\"---the\nmismatch of \"'i' as short for --staged\" is a bit unlovely I admit).\n\nHere's what we have after change #2:\n\nWithout staging\n---------------\nadd\nrm\ndiff\ncommit\ncommit files...\n\nWith staging\n------------\nstage\ndiff --staged\ncommit --staged (or \"commit -i\")\n\nChange #3: Change \"add\" to not stage any content\n================================================\nTo finish off, I'd like to propose descriptions of the commands to\nallow the user to use the \"without staging\" commands as a complete set\nwhile being able to easily ignore any of the staging capabilities.\nThis does trigger a need for a semantic change in the \"add\"\ncommand. Here are the proposed descriptions:\n\nWithout staging\n---------------\nadd\t\tAdd a file to be managed by git\n\nrm\t\tRemove a file to no longer be managed by git\n\ndiff\t\tShow the changes in the working tree compared to the\n\t\tlatest commit, (or compared to staged content, if any)\n\ncommit\t\tCommit the current state of all git-managed files\n\ncommit files...\tCommit the current state of the specified files\n\nWith staging\n------------\nstage\t\tShove the current contents of the specified files into\n\t\tgit's staging area\n\ndiff --staged\tShow the changes in the staging area compared to the\n\t\tlatest commit\n\ncommit --staged\tCommit the state of the current staging area\ncommit -i\n\nTo make the above work, I think Daniel's suggestion of making \"add\"\nput 0{40} into the staging area should work just fine. I know that\nLinus has religious objections to these proposed new semantics of \"git\nadd\". One response there is to just consider \"add\" to be a mud-pit\ncommand for people to wallow in that really want it, (like Linus'\nproposed \"ci\" command). If you don't want to be in that mud-pit, then\njust use my \"stage\" command along with \"commit -i\", (or with \"commit\"\nand some configuration option, or with \"commit\" and a rejection to my\nchange #2).\n\nAnother response is that these new semantics for \"add\" really aren't\nany worse than other existing things in git, (for example, \"git rm\"\nisn't just updating file content into the index---because it even\nleaves the file around by default). [Actually, the fact that \"git rm\"\ndoesn't delete the file by default is a bug (and it's my bug). I think\nthe right thing is that \"git rm\" should be defined as always deleting\nthe file from the working tree, and that it should be fixed to fail if\nthe file if the file is dirty, (unless -f is passed)].\n\nOther examples of the current semantics of git commands being just as\n\"evil\", (I would argue \"usable\" instead), are below.\n\nI think that here, finally, I've made my proposal as clearly and\nconsistently as I can. I think the above would only improve git, (by\nmaking it easier to use by new people, while still providing a\nconsistent model and a way to easily learn everything git has to\noffer). Change #2 would be the hardest pill to swallow since it would\nmean some change in the habits of existing users, (the other changes\ncould largely be blissfully ignored by trained git users I\nthink). This difficulty could be softened with a configuration option\nsomething like core.commitStagedByDefault, or this one change could be\nrejected.\n\n-Carl\n\n[*] I say heresy, but I think all the talk about \"inconsistency\" and\n\"dishonesty\" in the proposals I've been making are really\nmisplaced. The easiest way to see that is to apply the same arguments\nto existing commands in git and see that they are already inconsistent\nand dishonest.\n\nInconsistency\n-------------\nIf the consistent model is \"'commit' commits the contents of the\nstaging area\" then what in the world is happening in the case of\n\"commit files...\"? There's really no way to describe that operation in\nterms of the staging area, because it simply ignores it. The closest\nyou could get is to describe the internal implementation in detail:\n\ncommit files... Creates a temporary staging area from the latest\n\t\tcommit, shoves the content of the named files into\n\t\tthat temporary staging area, creates a new commit from\n\t\tthat and then does [something] to the original staging\n\t\tarea.\n\nI (obviously) botched that. Somebody could write an actual, correct\ntechnical description. But you know what? It would be totally\nuseless. It's really hard to describe what the current command does in\nterms of the staging area and nobody would care anyway. It wouldn't\nhelp anybody use the thing. The fact that all commit operations _do_\ninvolve a staging area at some deep point in the implementation is\ntotally irrelevant to the fact that what \"commit files...\" does do\n_is_ desirable, and is not hard to explain at a conceptual level. What\nthe current documentation has is:\n\n\t\"Commit only the files specified on the command line.\"\n\nThis documentation doesn't say _anything_ about the content coming\nfrom the working tree rather than the index. But that's _obviously_\nthe correct place for the content to come from, and that's what's\nimplemented.\n\nDishonesty\n----------\nThe argument here is that some \"easier to use\" commands lie to the\nuser, giving them an incorrect idea of what's really happening, and\nthat this will create barriers to later understanding. I think the\nsame argument could be applied to say that there's no reason to have\n\"add\", \"rm\", \"resolve\", and \"update-index\" (or \"stage\"). These\ncommands are all doing the same thing at a technical level, so why lie\nto the user and let the user think they are doing something different?\nMy reply is that this isn't a lie, but it's providing names for the\nuser that match the operations that the user is conceptually\ndoing. That's called \"providing a usable interface\". If the user goes\non to learn the internals and discovers that these are all wrappers\naround some shared core command, then the user can appreciate that\nelegance of implementation. But forcing everyone to _use_ one command\nfor these conceptually separate arguments would be a mistake from the\npoint-of-view of usability.\n"},{"id":"293985","messageId":"87y7pr2xkg.wl%cworth@cworth.org","threadId":"43110","inReplyTo":"87slfzfri7.wl%cworth@cworth.org","subject":"Some thoughts on resolving conflicts","fromName":"Carl Worth","fromEmail":"cworth@cworth.org","sentAt":"2006-12-01T20:03:27Z","receivedAt":"2006-12-01T20:03:27Z","isPatch":false,"sender":{"key":"cworth@cworth.org","avatar":"https://gravatar.com/avatar/3746dc28cde609bdbd7f939058356e7e2bbd16d21e32274df0725eb3d998bc5b?d=mp&s=160"},"body":"On Fri, 01 Dec 2006 09:36:00 -0800, Carl Worth wrote:\n> To finish off, I'd like to propose descriptions of the commands to\n> allow the user to use the \"without staging\" commands as a complete set\n> while being able to easily ignore any of the staging capabilities.\n> This does trigger a need for a semantic change in the \"add\"\n> command. Here are the proposed descriptions:\n\nBy the way, back when we used to call it the \"index\" one of the things\nthat was often mentioned as a reason not to \"hide the index\" is that\nthe index ends up being so important during the process of resolving a\nmerge.\n\nThis is extremely true, and this is where git really starts to\nshine. I've seen people get really put off by the index when they\nfirst encounter \"commit -a\" or a messages instructing them to\n\"update-index\" something. But, if people are properly presented with\nwhat git offers for helping with conflict resolution then I think they\nwill fall in love with it.\n\nBut I think \"hide the index\" vs. \"celebrate the index\" frames the\ndebate entirely wrong. It's not a matter of \"working tree\" vs. \"index\"\nbeing the king. The king is what the user wants to accomplish and what\ndoes git offer to help with that.\n\nSo, for example, in the case of conflict resolution, what git offers\nin an iterative process involving:\n\n\tgit diff\tShows what still needs to be resolved\n\n\tgit resolve\tIndicate to git that conflicts are resolved in\n\t\t\tthe specified files\n\n(Yes, I'm assuming a future \"resolve\" synonym for update-index here)\nAnd finally, \"git commit\" when complete. This is a fantastic sequence\nsince it fits what the user wants to do and helps the user do it, (and\nthe incremental nature of it is helpful for large conflicts).\n\nNote that I don't think it's important whether the final \"git commit\"\nexecutes a \"commit -a\" or a mode traditional commit-the-index. It\nwould be exceedingly rare for someone to want to make a partial,\nstaged commit during conflict resolution. So I think that special case\ncan be entirely ignored when considering the user-interface.\n\nSo git provides tools well suited to the job here. One thing it\ndoesn't do well is to advertise them to the user. It would probably be\nhelpful to print some small section of advice and guidance when the\nconflict happens. Right now, git spews a lot of scary internal state\nthat definitely gives the impression of things going wrong, and\ndoesn't tell the user much about what to do. It would be nice to say\nsomething more along the lines of \"A conflict occurred during the\nmerge attempt. That's nothing to worry about---it happens\nsometimes. And here are some tools that git offers to help you fix\nthings up:...\"\n\nAnd there are other lovely things that git provides, such as:\n\n\tgit log -p --merge\tShows commits that contributed to this conflict\n\n\tgit diff --ours\t\tShow changes in working tree compared\n\t\t\t\tto our latest commit for unresolved files\n\n\tgit diff --theirs\tShow changes in working tree compared\n\t\t\t\tto the commit being merged in for\n\t\t\t\tunresolved files\n\nTo tell the truth, I hadn't really played with \"diff --ours\" and \"diff\n--theirs\" much before. They're right handy! I can't find any\ndocumentation for them, (it might exist somewhere deep in the plumbing\ndocumentation but I can't find it). It would be great to have\nexamples in the \"git diff\" page showing these off, and maybe some\nhints in the message that comes from the conflicted merge.\n\nSo the above commands are wildly useful. But there not useful because\n\"the index is an essential part of git\", they're useful because they\nhelp the user get information related to what the user is doing.\n\nOne command that I didn't find in my experimentation was how to see\nthe multi-parent diff after resolving the conflict. I found that I can\ndo a single-parent thing with:\n\n\tgit diff --cached\tShow changes in staging area compared\n\t\t\t\tto our latest commit.\n\nBut I didn't figure out how to get the multi-parent thing there\nyet. After I make the commit object I _can_ see the result I want with\n\"git show\", but it would be nice to be able to see that before the\ncommit.\n\nSurely there's a command-line option somewhere that does this, with a\nname like -cc or -C or something, but it's something that I would\nargue should acquire a different name---that is, if I were doing\nconflict resolution often. As it stands now, I rarely have any\nconflicts to resolve, so any user-interface warts that git has here\nhaven't rubbed me the wrong way yet. Other than the conflict spew\nwhich gives the impression of \"Git tried (multiple ways) and failed to\nmerge this mess. You're on your own now.\"\n\n-Carl\n\nPS. Here's the example I just used to experiment with conflict\nresolution. It's something like this that would be nice to have in\nsomething like \"git tutorial conflict-resolution\" which would run the\nfollowing sequence of commands for the user and then invite the user\nto play with things like \"git diff --ours\" and \"git diff --theirs\".\n\nThe commands below look really ugly, so we definitely don't want the\ntutorial reader to ever have to go through all this\nstate-creation. But the end result---what the user sees in \"git diff\"\nis so intuitive that it would be wonderful to have this kind of thing\nreadily available at the command-line.\n\nA more ambitious example might setup conflict in multiple files to\nteach the incremental nature of using \"git diff\" and \"git resolve\"\ntogether.\n\nmkdir git-tutorial-conflict-resolution\ncd git-tutorial-conflict-resolution\ngit init-db\necho 'vvv Context paragraph 1 vvv\nThis is a paragraph that exists for context.\nIt will be unmodified in both branches.\n^^^ Context paragraph 1 ^^^\n\nThis is a paragraph that I will modify in master\nand delete in other.\n\nvvv Context paragraph 2 vvv\nThis is a second paragraph that exists for context.\nIt too, will be unmodified in both branches.\n^^^ Context paragraph 2 ^^^\n\nThis is a paragraph that I will delete in master\nand modify in other.\n\nvvv Context paragraph 3 vvv\nThis is the third paragraph that exists for context.\nAgain, it will be unmodified in both branches.\n^^^ Context paragraph 3 ^^^\n\nThis is a paragraph that I will modify in two\ndifferent ways in master and other.\n' > file\ngit add file\ngit commit -m \"add file\"\ngit branch other\necho 'vvv Context paragraph 1 vvv\nThis is a paragraph that exists for context.\nIt will be unmodified in both branches.\n^^^ Context paragraph 1 ^^^\n\nThis is a paragraph that I have modified\nin master.\n\nvvv Context paragraph 2 vvv\nThis is a second paragraph that exists for context.\nIt too, will be unmodified in both branches.\n^^^ Context paragraph 2 ^^^\n\nvvv Context paragraph 3 vvv\nThis is the third paragraph that exists for context.\nAgain, it will be unmodified in both branches.\n^^^ Context paragraph 3 ^^^\n\nThis is a paragraph that I have modified\nin master.\n' > file\ngit commit -a -m \"master modifications\"\ngit checkout other\necho 'vvv Context paragraph 1 vvv\nThis is a paragraph that exists for context.\nIt will be unmodified in both branches.\n^^^ Context paragraph 1 ^^^\n\nvvv Context paragraph 2 vvv\nThis is a second paragraph that exists for context.\nIt too, will be unmodified in both branches.\n^^^ Context paragraph 2 ^^^\n\nThis is a paragraph that I have modified\nin other.\n\nvvv Context paragraph 3 vvv\nThis is the third paragraph that exists for context.\nAgain, it will be unmodified in both branches.\n^^^ Context paragraph 3 ^^^\n\nThis is a paragraph that I have modified\nin other\n' > file\ngit commit -a -m \"other modifications\"\ngit checkout master\ngit pull . other\n"},{"id":"295814","messageId":"4570942C.406@gmx.net","threadId":"43110","inReplyTo":"87slfzfri7.wl%cworth@cworth.org","subject":"Re: [RFC] Introduce \"git stage\" (along with some heresy)","fromName":"Marko Macek","fromEmail":"marko.macek@gmx.net","sentAt":"2006-12-01T20:44:28Z","receivedAt":"2006-12-01T20:44:28Z","isPatch":false,"sender":{"key":"marko.macek@gmx.net","avatar":null},"body":"Carl Worth wrote:\n> [This message, (yes,another long one from me), proposes 3 changes. The\n> first should be uncontroversial I think, while the second and third\n> are clear heresy, (and the second would require some amount of\n> re-training or re-configuration by existing git user). Pick and choose\n> as you see fit. I don't think they actually depend on each other,\n> though I'll present them here as parts of a whole.]\n\n/me likes (both emails).\n\nQ: should git-commit require either -a or --staged when there is a\nstaged commit?\n\nMark\n"},{"id":"293857","messageId":"4571EA24.4080907@vilain.net","threadId":"43110","inReplyTo":"87slfzfri7.wl%cworth@cworth.org","subject":"Re: [RFC] Introduce \"git stage\" (along with some heresy)","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2006-12-02T21:03:32Z","receivedAt":"2006-12-02T21:03:32Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Carl Worth wrote:\n> Change #2: Make a staged commit an explicit act\n> ===============================================\n> The \"-a\" stands out to me here as the only command-line option needed\n> in the first list, and the only command in the second list that\n> performs a staged operation by default. So change number to is to\n> redefine \"commit\" to mean what \"commit -a\" meant before and to require\n> a new command-line option for staged committing, (the best naming I\n> have so far is \"commit --staged\" with a shortcut of \"commit -i\"---the\n> mismatch of \"'i' as short for --staged\" is a bit unlovely I admit).\n\nI wonder about backwards compatibility, but then another part of me says\nthat porcelain are probably using \"git-commit-tree\" anyway.\n\nHow about considering alternative words?  Like \"git save\" for this\nhigher level and more user friendly interface.\n\nAs another idea (brainstorming here), what about an \"autocommit\" approach?\n\n  git rm       # removes files and asks for commit message\n  git add      # ditto\n  git commit   # updates and commits everything\n\n  git stage    # starts a staged commit\n  git add      # modifies staging area\n  git rm       # ditto\n  git stage filename # adds contents to staging area\n  git commit   # saves staging area as commit\n\nThen you could have \"core.autocommit\" as a repo-config option,\ndefaulting to off for \"backwards compatibility\".\n\n> Change #3: Change \"add\" to not stage any content\n> ================================================\n> To finish off, I'd like to propose descriptions of the commands to\n> allow the user to use the \"without staging\" commands as a complete set\n> while being able to easily ignore any of the staging capabilities.\n> This does trigger a need for a semantic change in the \"add\"\n> command. Here are the proposed descriptions:\n\nThe \"autocommit\" concept may make this less of an issue.\n\n"},{"id":"295626","messageId":"4571FF3E.4090209@saville.com","threadId":"43110","inReplyTo":"87slfzfri7.wl%cworth@cworth.org","subject":"Re: [RFC] Introduce \"git stage\" (along with some heresy)","fromName":"Wink Saville","fromEmail":"wink@saville.com","sentAt":"2006-12-02T22:33:34Z","receivedAt":"2006-12-02T22:33:34Z","isPatch":false,"sender":{"key":"wink@saville.com","avatar":"https://avatars.githubusercontent.com/u/1024284?v=4"},"body":"Carl Worth wrote:\n> \n> Without staging\n> ---------------\n> add\t\tAdd a file to be managed by git\n> \n> rm\t\tRemove a file to no longer be managed by git\n> \n> diff\t\tShow the changes in the working tree compared to the\n> \t\tlatest commit, (or compared to staged content, if any)\n> \n> commit\t\tCommit the current state of all git-managed files\n> \n> commit files...\tCommit the current state of the specified files\n> \n\nAs a newbie like this entire proposal and especially the above.\n\nWink Saville\n"}]}