{"thread":{"id":"4138","subject":"The git newbie experience","startedAt":"2006-05-14T18:36:40Z","lastAt":"2006-05-15T21:10:24Z","messageCount":12,"participants":["Tommi Virtanen","Junio C Hamano","Shawn Pearce","Carl Baldwin","Carl Worth"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"19924","messageId":"446778B8.7080201@inoi.fi","threadId":"4138","inReplyTo":null,"subject":"The git newbie experience","fromName":"Tommi Virtanen","fromEmail":"tv@inoi.fi","sentAt":"2006-05-14T18:36:40Z","receivedAt":"2006-05-14T18:36:40Z","isPatch":false,"sender":{"key":"tv@debian.org","avatar":null},"body":"Here's my thoughts from teaching half a dozen people git recently:\n\nMinimal newbie command set\n--------------------------\n\nThe complete set of \"newbie commands\" for useful development work should\nbe as small as possible, for fast learning.\n\nPeople can always look up new things when they want to, but if they\ndon't get the simple things going quickly they will forever see git\nas \"that overcomplex thing I tried to use once\".\n\nConcretely: explain the indexless \"git commit -a\" case first,\nso people don't need update-index right away. Most new docs are\npretty good at this, already.\n\nFix the cases where \"git commit -a\" is not enough. Here's a case I\nran into:\n\n- Jack is a beginning user of git and does not (want to) understand\n  the index (right now).\n- Jack works on branch X, say his HEAD points to X1. He has an edited,\n  uncommitted files with the names A, B and C.\n- Jack wants to pull new changes made by others to his branch.\n  There are merge conflicts in files D, E, ..., Z.\n- Jack resolves the merge conflicts and is ready to commit the resulting\n  merge. Note files A, B and C should not be committed.\n\n  1. if Jack says \"git commit -a\", then A, B and C will be committed\n     also.\n\n  2. if Jack says \"git commit\", then the current state of the index will\n     be committed. That is, the commit will not contain the proper\n     merged state of files D, E, ..., Z.\n\n  3. if Jack says \"git commit D E ... Z\", things work correctly. But\n     Jack does not want to type or copy-paste that much, and that's\n     horribly error-prone anyway. If the leaves one file out, or\n     accidentally adds B there too, the merge goes wrong.\n\n  4. if Jack says \"git update-index --refresh\" and then \"git commit\",\n     things work correctly. But Jack doesn't (want to) know about the\n     index.\n\nMy best idea so far is to add a \"git commit -A\" option, that\nessentially does the \"update-index --refresh\". Whenever index\nhas a file state != HEAD, update-index it. The modified unrelated\nfiles will have index state == HEAD. Or altering \"git commit -a\"\nto do that.\n\nExcept, trying to solve usability problems by _adding_ options\nis just insane.\n\nI'd really like to see a way to use git without caring about the\nindex, and just having things work. I can appreciate the index\nis useful, and possibly even necessary to work on projects the size\nof the Linux kernel, but I really wish it would default to being\n_only_ an optimization, not the central bit of user interface to\nprepare commits.\n\nBasic git use _should_ be as easy as basic svn/bzr/hg use. Anything\nelse will just mean git is not used outside of what codebases Linus\nhas dictatorship over. (At least not after bzr is more done or hg\nmore well known; right now git has a very nice feature set, but the\nothers are catching up fast.)\n\nThis is a part that Subversion got right. Basic use needs to be simple.\n(If you catch me in agitated mood, I'd claim it's the _only_ part\nSubversion got right;-)\n\n\nAnd to reply to a comment on IRC I missed at the time:\n\n(21:05:35) gitster: as gittus said much earlier, refusing index is like\nrefusing git.  We might be able to implement \"index-less\" mode in which\nthings like merge and am refuse to operate when you have any change from\nHEAD in the working tree. Then new users can always do \"commit -a\".\n(21:06:04) gitster: \"git-repo-config core.newuser yes\" perhaps?\n\nIf you do it that way, you only make git unnecessarily hard to use for\nnewbies. For example, we had a case where we absolutely _had_ to keep\nan ugly workaround in the tree, in a file not otherwise edited, but\nwe definitely did not want to commit the kludge, at least not to the\nbranch that was really being worked on. So such restricted mode would\njust have meant either people could not merge, or they had to use index\nanyway. That's a point where people who have a choice make on, and stop\ntrying to use git.\n\n(21:08:34) ***gitster personally considers getting more users a very\nhigh priority but agrees that from usability point of view, having a\nmode to expose \"stripped down\" set of features for simple needs would be\nbeneficial.\n\nThat I can 100% agree with.\n\n\nBranch management\n-----------------\n\n\"master\" and \"origin\" are good enough for the really simple use, but\nthat starts to fail fast when you add in more branches.\n\nThe remotes/* branch support is really nice, but should be used better.\nHere's a bunch of wild ideas:\n\n- When cloning a repository, just clone all the non-remote heads to\nlocal remotes/* heads. See what name the remote HEAD points to, store\nthat locally also as a refs/heads/master, set local HEAD to it. Note,\norigin is gone, and is now called remotes/master.\n\n- Alternatively (and I think I like this more): When cloning a\nrepository, just clone all the non-remote heads to local remotes/*\nheads. See what the remote HEAD points to, store that locally\nalso as a refs/heads/* head, set local HEAD to it. Note, origin and\nmaster are both gone, and accessible via remotes/X and refs/heads/X\n(where X is the name remote HEAD pointed to).\n\n- Currently, when people start tracking a new remote branch, they end\nup editing .git/remotes/origin and adding new Pull: lines. If they\nintend to work on the branch, they also clone the branch locally, and\nadd a Push: line. Make this simpler. Here's a rough sketch:\n\n  \"git track [--read-only] REMOTE [BRANCH | --all]\"\n\n  Without --all, git track would:\n  - abort if refs/remotes/foo exists\n  - add \"Pull: foo:remotes/foo\" to .git/remotes/origin (or the\n    equivalent config file)\n  - if --read-only is not given:\n    - add \"Push: foo:foo\" to .git/remotes/origin\n  - fetch foo from origin to remotes/foo\n  - if --read-only is not given:\n    - run \"git branch foo remotes/foo\"\n\n  With --all, it would do the same, but for everything the REMOTE has\n  in refs/remotes/. Exactly when to abort is a bit harder to define,\n  but still..\n\n- Or, if that's too much, at least make peek-remote understand\n.git/remotes/* shortcuts, so finding out what branches exist is a bit\nsimpler.\n"},{"id":"19930","messageId":"7vmzdk2t8i.fsf@assigned-by-dhcp.cox.net","threadId":"4138","inReplyTo":"446778B8.7080201@inoi.fi","subject":"Re: The git newbie experience","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-14T21:26:21Z","receivedAt":"2006-05-14T21:26:21Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Tommi Virtanen <tv@inoi.fi> writes:\n\n> (21:08:34) ***gitster personally considers getting more users a very\n> high priority but agrees that from usability point of view, having a\n> mode to expose \"stripped down\" set of features for simple needs would be\n> beneficial.\n>\n> That I can 100% agree with.\n\nSorry, I personally consider it is not a very high priority; the\nabove is a typo (otherwise \"but agrees\" does not make _any_\nsense).\n\nThe rest of the message I'll find a time to comment on\nseparately, but I am in the middle of migrating the development\nenvironment, so it might take some time.\n\nOh, and please send patches cc'ed to the list at least for a few\ndays, because I am fighting with fetchmail/getmail configuration\nright now and might lose a few mails while doing so.\n"},{"id":"19932","messageId":"7vfyjcntro.fsf@assigned-by-dhcp.cox.net","threadId":"4138","inReplyTo":"446778B8.7080201@inoi.fi","subject":"Re: The git newbie experience","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-14T22:09:15Z","receivedAt":"2006-05-14T22:09:15Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Tommi Virtanen <tv@inoi.fi> writes:\n\n> My best idea so far is to add a \"git commit -A\" option, that\n> essentially does the \"update-index --refresh\". Whenever index\n> has a file state != HEAD, update-index it. The modified unrelated\n> files will have index state == HEAD. Or altering \"git commit -a\"\n> to do that.\n\nI am not sure what you are trying to achieve by --refresh.  It\ndoes not update the object names in the index.  Maybe you are\nthinking about --again, but that is when you did something to\nthe index yourself, so it would not buy you much in the \"novice\nfaced with merge\" case.\n\nAnyway, I think the time to commit is too late to save somebody\nwho does not understand the index.  How would you explain why\nyou sometimes need to use -A and sometimes -a?  That is why I\nsuggested to make \"git pull\" and \"git merge\" refuse to work if\nthere are local changes for novice users, where the definition\nof novice is \"git commit -a\" is the only way to make a commit.\nWe can have [core] novice = yes in .git/config for that.\n\nIf somebody does not understand the index, if the merge is\nprevented because the local change does conflict with it, how\nwould you explain why sometimes you can merge and sometimes you\ncannot?\n\nBut if you insist going that route, I would say we could make\n\"git commit -a\" on a merge commit to do a bit more magic.\n\nFor example, we could make -a do something special for a merge\nby looking at the presense of .git/MERGE_HEAD.\n\n\t- if \"commit -a\", and without .git/MERGE_HEAD, just grab\n          all the local modifications that are not in index yet,\n          and commit it.\n\n\t- upon \"commit -a\", and when .git/MERGE_HEAD exists,\n          grab the paths that ls-files -u reports, update-index\n          them.  Other automerged paths are already registered\n          in the index.\n\n> Except, trying to solve usability problems by _adding_ options\n> is just insane.\n\nI am not sure if it is \"usability\" but additional option to\nsimplify things does not sound right, I'd agree.\n\n> For example, we had a case where we absolutely _had_ to keep\n> an ugly workaround in the tree, in a file not otherwise\n> edited, but we definitely did not want to commit the kludge,\n> at least not to the branch that was really being worked on. So\n> such restricted mode would just have meant either people could\n> not merge, or they had to use index anyway.\n\nYour example is a very ill-thought out one.\n\nIf you are leaving the uncommitable kludge around, you cannot be\nusing \"commit -a\" with the normal non-merge workflow.  Why\nwould you worry about not being able to do \"commit -a\" on a\nmerge then?\n\nFor the beginning user without index, I would rewrite your\nscenario like this.\n\n- Jack is a beginning user of git and does not (want to) understand\n  the index (right now).\n\n- Jack works on branch X, say his HEAD points to X1. He has an edited,\n  uncommitted files with the names A, B and C.\n\n- Jack wants to pull new changes made by others to his branch.\n  But \"git merge\" invoked from \"git pull\" says he needs to stash\n  away the local changes to do the merge.\n\n- Jack stashes away what he has been working on and cleans up\n  his mess.\n\n  git diff >P.diff\n  git checkout HEAD A B C\n\n- Jack then pulls.  There are merge conflicts in files D, E, ..., Z.\n\n- Jack resolves the merge conflicts and is ready to commit the resulting\n  merge. Note files A, B and C do not have his unfinished work.\n\n  There is no \"if Jack does this or that\" problem; he says \"git\n  commit -a\" because that is the only \"commit\" command he knows\n  about.\n\n- Jack then reapplies what he stashed away with \"git apply P.diff\"\n  and keeps working.\n\nMaybe \"git stash\" command that does \"git diff --full-index\" with\nsome frills, and \"git unstash\" command which does an equivalent\nof \"git am -3\" would help this workflow (bare \"git apply\" does\nnot do the three-way merge like am does).\n"},{"id":"19961","messageId":"44680C54.8040206@inoi.fi","threadId":"4138","inReplyTo":"7vfyjcntro.fsf@assigned-by-dhcp.cox.net","subject":"Re: The git newbie experience","fromName":"Tommi Virtanen","fromEmail":"tv@inoi.fi","sentAt":"2006-05-15T05:06:28Z","receivedAt":"2006-05-15T05:06:28Z","isPatch":false,"sender":{"key":"tv@debian.org","avatar":null},"body":"Junio C Hamano wrote:\n> Anyway, I think the time to commit is too late to save somebody\n> who does not understand the index.  How would you explain why\n> you sometimes need to use -A and sometimes -a? \n\nI guess what I really want is \"a smarter -a\".\n\n> That is why I\n> suggested to make \"git pull\" and \"git merge\" refuse to work if\n> there are local changes for novice users, where the definition\n> of novice is \"git commit -a\" is the only way to make a commit.\n> We can have [core] novice = yes in .git/config for that.\n> \n> If somebody does not understand the index, if the merge is\n> prevented because the local change does conflict with it, how\n> would you explain why sometimes you can merge and sometimes you\n> cannot?\n\nBy the same logic that is already implemented. \"pull refuses to pull\nchanges to files that are modified but not committed\".\n\n>> For example, we had a case where we absolutely _had_ to keep\n>> an ugly workaround in the tree, in a file not otherwise\n>> edited, but we definitely did not want to commit the kludge,\n> Your example is a very ill-thought out one.\n>\n> If you are leaving the uncommitable kludge around, you cannot be\n> using \"commit -a\" with the normal non-merge workflow.  Why\n> would you worry about not being able to do \"commit -a\" on a\n> merge then?\n\nThe indexless working mode means you know two kinds of commits.\n\"git commit -a\" or \"git commit FILE..\". The uncommitted kludge hanging\naround means people listed file names. The case where the merge differs\nis that it's not just a few files, and they didn't even really\nknow what files to list. And \"git status\" showed them something\nthey were not used to seeing.\n\n> For the beginning user without index, I would rewrite your\n> scenario like this.\n> \n...\n> - Jack stashes away what he has been working on and cleans up\n>   his mess.\n> \n>   git diff >P.diff\n>   git checkout HEAD A B C\n...\n> - Jack then reapplies what he stashed away with \"git apply P.diff\"\n>   and keeps working.\n> \n> Maybe \"git stash\" command that does \"git diff --full-index\" with\n> some frills, and \"git unstash\" command which does an equivalent\n> of \"git am -3\" would help this workflow (bare \"git apply\" does\n> not do the three-way merge like am does).\n\nOh, I'd love to have a quick stash, that's what we actually ended up\ndoing a lot. Although I'd rather see a real implementation use a branch\nand not just a diff file, but.. yes please.\n\nAlthough, \"git stash\" and \"git unstash\" are yet another command to add\nto the newbie set, and I just complained about the size of the set ;)\n\n-- \nInoi Oy, Tykistökatu 4 D (4. krs), FI-20520 Turku, Finland\nhttp://www.inoi.fi/\nMobile +358 40 762 5656\n"},{"id":"19962","messageId":"7vy7x3x3ux.fsf@assigned-by-dhcp.cox.net","threadId":"4138","inReplyTo":"44680C54.8040206@inoi.fi","subject":"Re: The git newbie experience","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-15T05:18:46Z","receivedAt":"2006-05-15T05:18:46Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Tommi Virtanen <tv@inoi.fi> writes:\n\n> Oh, I'd love to have a quick stash, that's what we actually ended up\n> doing a lot. Although I'd rather see a real implementation use a branch\n> and not just a diff file, but.. yes please.\n\nI'd rather do that with a diff file that can be used to do a\n3-way (see how rebase does it with --full-index diff with am -3).\nNo point creating and forgetting to remove a throw away branch\nand getting more complaints.\n"},{"id":"19963","messageId":"20060515052728.GA28068@spearce.org","threadId":"4138","inReplyTo":"44680C54.8040206@inoi.fi","subject":"Re: The git newbie experience","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-05-15T05:27:28Z","receivedAt":"2006-05-15T05:27:28Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Tommi Virtanen <tv@inoi.fi> wrote:\n> Junio C Hamano wrote:\n[snip]\n> > - Jack stashes away what he has been working on and cleans up\n> >   his mess.\n> > \n> >   git diff >P.diff\n> >   git checkout HEAD A B C\n> ...\n> > - Jack then reapplies what he stashed away with \"git apply P.diff\"\n> >   and keeps working.\n> > \n> > Maybe \"git stash\" command that does \"git diff --full-index\" with\n> > some frills, and \"git unstash\" command which does an equivalent\n> > of \"git am -3\" would help this workflow (bare \"git apply\" does\n> > not do the three-way merge like am does).\n> \n> Oh, I'd love to have a quick stash, that's what we actually ended up\n> doing a lot. Although I'd rather see a real implementation use a branch\n> and not just a diff file, but.. yes please.\n> \n> Although, \"git stash\" and \"git unstash\" are yet another command to add\n> to the newbie set, and I just complained about the size of the set ;)\n\nThis is perhaps one area where SVN's user interface is actually nice.\nSVN's equiv. of stash is making a copy of your working directory into\nthe repository; something that is rather simple to do for the user.\n\nWhat about \"git commit -b foo -a\" to commit the current working\ndirectory to branch 'foo'?\n\nThen restoring is a pull of foo (\"git pull . foo\"), but that\nintermediate commit is now part of the repository history.  And \"git\ncommit -a\" doesn't automatically add extra/other files to the\nrepository and it probably should in the case of a \"stash\".\n\n-- \nShawn.\n"},{"id":"19965","messageId":"20060515053133.GB28068@spearce.org","threadId":"4138","inReplyTo":"7vy7x3x3ux.fsf@assigned-by-dhcp.cox.net","subject":"Re: The git newbie experience","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-05-15T05:31:33Z","receivedAt":"2006-05-15T05:31:33Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Tommi Virtanen <tv@inoi.fi> writes:\n> \n> > Oh, I'd love to have a quick stash, that's what we actually ended up\n> > doing a lot. Although I'd rather see a real implementation use a branch\n> > and not just a diff file, but.. yes please.\n> \n> I'd rather do that with a diff file that can be used to do a\n> 3-way (see how rebase does it with --full-index diff with am -3).\n> No point creating and forgetting to remove a throw away branch\n> and getting more complaints.\n\nHow is a quick stash different from a topic branch?  I don't see\nany difference between the two.  Your working directory was a topic\nbranch, just an unnamed topic branch.  Why don't you name it and\ndeal with it once it is named?\n\nI can see new users getting confused about what changes are in\ntheir quick stash or accidentially losing their quick stash by\nrunning it twice in a row.\n\nTeaching new users to always work on a topic branch and committing\nbefore pulling/merging should be the favored workflow.\n\n-- \nShawn.\n"},{"id":"19978","messageId":"7v1wuvvg0j.fsf@assigned-by-dhcp.cox.net","threadId":"4138","inReplyTo":"20060515053133.GB28068@spearce.org","subject":"Re: The git newbie experience","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-15T08:39:08Z","receivedAt":"2006-05-15T08:39:08Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Shawn Pearce <spearce@spearce.org> writes:\n\n>> I'd rather do that with a diff file that can be used to do a\n>> 3-way (see how rebase does it with --full-index diff with am -3).\n>> No point creating and forgetting to remove a throw away branch\n>> and getting more complaints.\n>\n> How is a quick stash different from a topic branch?\n\nThe original version of my message in response to TV looked like\nthis.\n\n - Jack is a beginning user of git and does not (want to) understand\n   the index (right now).\n\n - Jack works on branch X, say his HEAD points to X1. He has an edited,\n   uncommitted files with the names A, B and C.\n\n - Jack wants to pull new changes made by others to his branch.\n   But \"git merge\" invoked from \"git pull\" says he needs to stash\n   away the local changes to do the merge.\n\n - Jack stashes away what he has been working on and cleans up\n   his mess.\n\n   git checkout -b stash ;# risks error when \"stash\" exists\n   git commit -a -m 'Stashing WIP'\n   git checkout master ;# assuming that was where he was\n\n - Jack then pulls.  There are merge conflicts in files D, E, ..., Z.\n\n - Jack resolves the merge conflicts and is ready to commit the resulting\n   merge. Note files A, B and C do not have his unfinished work.\n\n   There is no \"if Jack does this or that\" problem; he says \"git\n   commit -a\" because that is the only \"commit\" command he knows\n   about.\n\n - Jack then reapplies what he stashed away, and keeps working.\n\n   git pull . --no-commit stash\n   git branch -D stash\n\nYou have to teach the new user to (1) name something, only to\nimmediately discard it when he returns to what he was in the\nmiddle of, (2) remember to clean up the temporary thing once he\nis done lest he forgets to clean it up (and common names like\n\"stash\", \"tmp\" will be reused by accident causing grief next\ntime he needs to do another stash), and (3) use of --no-commit\npull.\n\nOn the other hand, \"git stash/unstash\" workflow would be quite\nsimple:\n\n\t$ git stash >my.precious.state\n        ... do whatever you want to deviate to\n        $ git unstash <my.precious.state\n\nMerge resolve might be needed while unstashing, but \nwe are talking about pulling somebody else's work in \"do\nwhatever\" part, so that is something the user knows how to\nperform anyway.\n\nA quick and dirty stash implementation would go like this:\n\nStash is easy.\n\n        #!/bin/sh\n        # git stash\n        git diff --binary HEAD\n        git reset --hard\n\nUnstash is a bit involved.\n\n        #!/bin/sh\n        # git unstash\n        . git-sh-setup\n        O_OBJECT=`cd \"$GIT_OBJECT_DIRECTORY\" && pwd`\n        O_DIR=`cd \"$GIT_DIR\" && pwd`\n        stash=\"$O_DIR/.stash$$\"\n        rm -fr \"$stash.*\"\n        trap 'rm -rf $stash.*' 0\n        cat >\"$stash.patch\"\n        git-apply -z --index-info <\"$stash.patch\" >\"$stash.list\"\n        GIT_INDEX_FILE=\"$stash.index\"  \\\n        GIT_OBJECT_DIRECTORY=\"$O_OBJECT\" \\\n        (\n                mkdir -p \"$stash.tmp\" &&\n                git-update-index -z --index-info <\"$stash.list\" &&\n                git-write-tree >\"$stash.base\" &&\n                cd \"$stash.tmp\" &&\n                git-apply --binary --index <\"$stash.patch\" &&\n                git-write-tree >\"$stash.his\"\n        )\n        his_tree=$(cat \"$stash.his\")\n        orig_tree=$(cat \"$stash.base\")\n        rm -fr \"$stash.*\"\n        git-merge-resolve $orig_tree -- HEAD $his_tree\n\nThis is essentially the core of \"am -3\" logic; if you are going\nto use this for real, you would probably want to see if the\npatch applies cleanly before falling back on the three-way\nmerge, though.\n"},{"id":"20011","messageId":"20060515164610.GA24295@hpsvcnb.fc.hp.com","threadId":"4138","inReplyTo":"7v1wuvvg0j.fsf@assigned-by-dhcp.cox.net","subject":"Re: The git newbie experience","fromName":"Carl Baldwin","fromEmail":"cnb@fc.hp.com","sentAt":"2006-05-15T16:46:10Z","receivedAt":"2006-05-15T16:46:10Z","isPatch":false,"sender":{"key":"cnb@fc.hp.com","avatar":null},"body":"Junio,\n\nThis seems a lot like what I tried to do with git-undo/git-redo quite a\nwhile back.\n\nMy implementation actually wrote the working file state into the object\nstore as a tree and stored a reference to the tree under something like\n.git/refs/undo (or .git/refs/stash).  Redo was a simple merge of this\ntree back onto the current working files.\n\nI think I would like something like this better than the 'generate\nbinary patch and reapply the patch later.\n\nIf these commands were added to git I think they would be better if the\ncommands chose a temporary branch name, committed the current state to\nthat branch and did everything else that someone more experienced would\ndo using branches having chosen a temporary branch name.\n\nThe redo or unstash operation could just pick the most recent tempory\nbranch name (top of stack) and merge changes into the working copy.\n\nCarl\n\nOn Mon, May 15, 2006 at 01:39:08AM -0700, Junio C Hamano wrote:\n> Shawn Pearce <spearce@spearce.org> writes:\n> \n> >> I'd rather do that with a diff file that can be used to do a\n> >> 3-way (see how rebase does it with --full-index diff with am -3).\n> >> No point creating and forgetting to remove a throw away branch\n> >> and getting more complaints.\n> >\n> > How is a quick stash different from a topic branch?\n> \n> The original version of my message in response to TV looked like\n> this.\n> \n>  - Jack is a beginning user of git and does not (want to) understand\n>    the index (right now).\n> \n>  - Jack works on branch X, say his HEAD points to X1. He has an edited,\n>    uncommitted files with the names A, B and C.\n> \n>  - Jack wants to pull new changes made by others to his branch.\n>    But \"git merge\" invoked from \"git pull\" says he needs to stash\n>    away the local changes to do the merge.\n> \n>  - Jack stashes away what he has been working on and cleans up\n>    his mess.\n> \n>    git checkout -b stash ;# risks error when \"stash\" exists\n>    git commit -a -m 'Stashing WIP'\n>    git checkout master ;# assuming that was where he was\n> \n>  - Jack then pulls.  There are merge conflicts in files D, E, ..., Z.\n> \n>  - Jack resolves the merge conflicts and is ready to commit the resulting\n>    merge. Note files A, B and C do not have his unfinished work.\n> \n>    There is no \"if Jack does this or that\" problem; he says \"git\n>    commit -a\" because that is the only \"commit\" command he knows\n>    about.\n> \n>  - Jack then reapplies what he stashed away, and keeps working.\n> \n>    git pull . --no-commit stash\n>    git branch -D stash\n> \n> You have to teach the new user to (1) name something, only to\n> immediately discard it when he returns to what he was in the\n> middle of, (2) remember to clean up the temporary thing once he\n> is done lest he forgets to clean it up (and common names like\n> \"stash\", \"tmp\" will be reused by accident causing grief next\n> time he needs to do another stash), and (3) use of --no-commit\n> pull.\n> \n> On the other hand, \"git stash/unstash\" workflow would be quite\n> simple:\n> \n> \t$ git stash >my.precious.state\n>         ... do whatever you want to deviate to\n>         $ git unstash <my.precious.state\n> \n> Merge resolve might be needed while unstashing, but \n> we are talking about pulling somebody else's work in \"do\n> whatever\" part, so that is something the user knows how to\n> perform anyway.\n> \n> A quick and dirty stash implementation would go like this:\n> \n> Stash is easy.\n> \n>         #!/bin/sh\n>         # git stash\n>         git diff --binary HEAD\n>         git reset --hard\n> \n> Unstash is a bit involved.\n> \n>         #!/bin/sh\n>         # git unstash\n>         . git-sh-setup\n>         O_OBJECT=`cd \"$GIT_OBJECT_DIRECTORY\" && pwd`\n>         O_DIR=`cd \"$GIT_DIR\" && pwd`\n>         stash=\"$O_DIR/.stash$$\"\n>         rm -fr \"$stash.*\"\n>         trap 'rm -rf $stash.*' 0\n>         cat >\"$stash.patch\"\n>         git-apply -z --index-info <\"$stash.patch\" >\"$stash.list\"\n>         GIT_INDEX_FILE=\"$stash.index\"  \\\n>         GIT_OBJECT_DIRECTORY=\"$O_OBJECT\" \\\n>         (\n>                 mkdir -p \"$stash.tmp\" &&\n>                 git-update-index -z --index-info <\"$stash.list\" &&\n>                 git-write-tree >\"$stash.base\" &&\n>                 cd \"$stash.tmp\" &&\n>                 git-apply --binary --index <\"$stash.patch\" &&\n>                 git-write-tree >\"$stash.his\"\n>         )\n>         his_tree=$(cat \"$stash.his\")\n>         orig_tree=$(cat \"$stash.base\")\n>         rm -fr \"$stash.*\"\n>         git-merge-resolve $orig_tree -- HEAD $his_tree\n> \n> This is essentially the core of \"am -3\" logic; if you are going\n> to use this for real, you would probably want to see if the\n> patch applies cleanly before falling back on the three-way\n> merge, though.\n> \n> \n> -\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n\n-- \n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n Carl Baldwin                        RADCAD (R&D CAD)\n Hewlett Packard Company\n MS 88                               work: 970 898-1523\n 3404 E. Harmony Rd.                 work: Carl.N.Baldwin@hp.com\n Fort Collins, CO 80525              home: Carl@ecBaldwin.net\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"},{"id":"20025","messageId":"877j4nvx2w.wl%cworth@cworth.org","threadId":"4138","inReplyTo":"7v1wuvvg0j.fsf@assigned-by-dhcp.cox.net","subject":"Re: The git newbie experience","fromName":"Carl Worth","fromEmail":"cworth@cworth.org","sentAt":"2006-05-15T20:42:47Z","receivedAt":"2006-05-15T20:42:47Z","isPatch":false,"sender":{"key":"cworth@cworth.org","avatar":"https://gravatar.com/avatar/3746dc28cde609bdbd7f939058356e7e2bbd16d21e32274df0725eb3d998bc5b?d=mp&s=160"},"body":"On Mon, 15 May 2006 01:39:08 -0700, Junio C Hamano wrote:\n>  - Jack stashes away what he has been working on and cleans up\n>    his mess.\n> \n>    git checkout -b stash ;# risks error when \"stash\" exists\n>    git commit -a -m 'Stashing WIP'\n>    git checkout master ;# assuming that was where he was\n\nI really like the proposal made elsewhere to implement a new:\n\n\tcommit -b <newbranch>\n\nwhich would then allow for a single command to achieve at least the\nfirst two commands above:\n\n\tgit commit -a -b stash -m 'Stashing WIP'\n\nIt might even make sense for this command to effectively perform all\nthree of the above commands. That is, should \"commit -b\" also checkout\nthe newly created branch or should it leave HEAD unchanged. I'm not\nsure.\n\n> You have to teach the new user to (1) name something, only to\n> immediately discard it when he returns to what he was in the\n> middle of, (2) remember to clean up the temporary thing once he\n> is done lest he forgets to clean it up (and common names like\n> \"stash\", \"tmp\" will be reused by accident causing grief next\n> time he needs to do another stash), and (3) use of --no-commit\n> pull.\n\nI threw out a simple git-stash earlier, (which stashed to a branch\nrather than to a file). I've spent some time using it, and am now\nquite sure it's the wrong thing, and the above problems outline the\ndefect quite well:\n\n1) Naming.\n\n   Here, git-stash is doing too much. I prefer the idea of a stash\n   command using a branch rather than a patch file, (and allowing one\n   stash per branch rather than one stash per repository). But the\n   namespace of branches is something the user owns, and we should\n   avoid adding commands that steal from it unnecessarily. So my\n   git-stash fails on this point, while \"commit -b <newbranch>\" is\n   much better.\n\n2) Cleanup and --no-commit pull\n\n   Here, git-stash is doing too little. It's really only performing\n   one piece of what needs to be done in order to switch back and\n   forth between different topics of work.\n\nSo here are my thoughts on what I'd like instead:\n\nIn git, a branch is what we use to name a topic of work.\n\nHistorically, a branch has been extremely lightweight, (a name and\nreference to a parent for subsequent commits). But there's been a\nrecent trend (in proposals at least) to add other, useful things to a\nbranch, (as in the discussions of branch-specific configuration).\n\nIn my work, I've found that the uncommitted state of my working tree\nis something that I associate very strongly with my \"current topic\"\nand expect the branch-changing commands respected that.\n\nIn particular, when using checkout to change branches, unless I've\nspecifically stated with \"-m\" that I want to carry my changes along, I\nwould like git to stash my working tree \"into\" the branch I'm\nswitching away from.\n\nSimilarly, when switching to a branch, I'd like to have the working\ntree restored to what it was the last time I switched away from that\nbranch.\n\nDoes that seem unreasonable to anyone?\n\nThe only snag I've imagined is that when using \"checkout -m\" to switch\nto a branch that also had a stashed working tree, then there's a merge\nto be performed and that could obviously conflict. I've intentionally\nnot mentioned how the stashing/restoring should be implemented, since\nthe user shouldn't care. But a merge conflict is one case where the\nimplementation might leak out to the user. The wimpy thing to do would\nbe to refuse to allow \"checkout -m\" to a branch with stashed changes.\n\n-Carl\n"},{"id":"20026","messageId":"7vhd3rhv6t.fsf@assigned-by-dhcp.cox.net","threadId":"4138","inReplyTo":"20060515164610.GA24295@hpsvcnb.fc.hp.com","subject":"Re: The git newbie experience","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-15T20:47:22Z","receivedAt":"2006-05-15T20:47:22Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carl Baldwin <cnb@fc.hp.com> writes:\n\n> My implementation actually wrote the working file state into the object\n> store as a tree and stored a reference to the tree under something like\n> .git/refs/undo (or .git/refs/stash).  Redo was a simple merge of this\n> tree back onto the current working files.\n>\n> I think I would like something like this better than the 'generate\n> binary patch and reapply the patch later.\n\nWhen you think of the \"binary patch\" as a human readable\nrepresentation of your (hierarchical set of) tree objects, you\nwould realize that these two approaches aren't that much\ndifferent at the tree merge level, and it's just a matter of\nwhich representation is more convenient and human readable.\n\nPros and cons I see are:\n\n * Branch approach needs to teach users only one thing -- create\n   a branch, merge with it, throw it away.  Which is something\n   the user needs to know anyway, so it is a plus.\n\n * Branch approach needs to store a full postimage tree and the\n   base commit (so you can use it as a merge base); the\n   postimage tree includes paths that are not involved in the\n   change being stashed.\n\n * Patch records only the object names of paths that are relevant\n   to the stash.  Instead of keeping the full postimage tree, it\n   creates one on the fly when you actually do the unstashing.\n\n * Patch is human readable and can be used for purposes other\n   than falling back to a three-way merge.  When cleanly applies\n   apply + write-tree is faster than a tree merge.\n\n * Patch could be verbose if the change being stashed is large;\n   after all the primary information used are the object names\n   recorded on the \"index\" lines and the patch text itself is a\n   waste from storage point of view.  This is a disadvantage of\n   the \"patch\" approach, but its readability might offset it.\n   If a change being stashed is large, the user had better be\n   doing it on a separate topic branch anyway, so this might not\n   be a big issue.\n"},{"id":"20029","messageId":"7vlkt3gfjz.fsf@assigned-by-dhcp.cox.net","threadId":"4138","inReplyTo":"877j4nvx2w.wl%cworth@cworth.org","subject":"Re: The git newbie experience","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-15T21:10:24Z","receivedAt":"2006-05-15T21:10:24Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carl Worth <cworth@cworth.org> writes:\n\n> In particular, when using checkout to change branches, unless I've\n> specifically stated with \"-m\" that I want to carry my changes along, I\n> would like git to stash my working tree \"into\" the branch I'm\n> switching away from.\n>\n> Similarly, when switching to a branch, I'd like to have the working\n> tree restored to what it was the last time I switched away from that\n> branch.\n>\n> Does that seem unreasonable to anyone?\n\nI would not call it unreasonable to want to have an easy access\nto that mode of operation _as_ _well_, as an option.\n\nIf you were suggesting to make it the only way for future git to\nwork (I think you are not), then it sounds very unreasonable to\nme.\n\nThe implementation behind the scene does not matter, but I think \nset of \"stashes\" that can be attached to each branch would work\nwell for what you would want.  OTOH, isn't it called stgit?\n\nThe reason why I want it to stay as an option is because I often\ndo a throw-away patch on top of whatever branch is checked out\nin my working tree while reading the list traffic to compose a\nresponse with an alternative patch.  Usually I follow that by a\n\"git reset\" once the message is sent out, but when I like the\nidea well enough, I do \"checkout -b jc/that-topic master\" to\nswitch to a new branch with the dirty state carried along, to\nwork on it further.  I do not want that workflow to require -m\nflag, which means something different (-m means \"I accept the\npossibility of the three-way merge failing while doing this\nswitch that needs a merge\").  Instead, I want \"checkout -b\" to\ntry carrying state forward and stop if it cannot without\nfile-level merging (i.e. the current behaviour).  Then I can\nthink if I want to do a stash with \"git diff\", or if I want to\ndo the temporary branch not based on \"master\" but the current\nbranch (which is guaranteed to work without -m) and deal with\nthe mess later.\n"}]}