{"thread":{"id":"22449","subject":"My use case","startedAt":"2010-01-30T08:26:19Z","lastAt":"2010-01-30T19:19:45Z","messageCount":7,"participants":["Ron Garret","Edward Z. Yang","tytso@mit.edu","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"133103","messageId":"ron1-09825C.00261930012010@news.gmane.org","threadId":"22449","inReplyTo":null,"subject":"My use case","fromName":"Ron Garret","fromEmail":"ron1@flownet.com","sentAt":"2010-01-30T08:26:19Z","receivedAt":"2010-01-30T08:26:19Z","isPatch":false,"sender":{"key":"ron1@flownet.com","avatar":null},"body":"My recent question about checking out an upstream commit (and ending up \nas a result on a detached head) has generated a lot of discussion and \nuseful information.  I thought I'd describe what I'm actually up to \nbecause someone might have some ideas on how to do it better.\n\nI'm trying to integrate git into a Lisp IDE (Clozure Common Lisp).  \nBecause it's Lisp, code is often developed incrementally and \nexperimentally.  This has two important consequences.  First, the files \nin your working directory can and often do, as part of the normal course \nof events, get into an incoherent state.  Everything in your running \nLisp image is working just fine, but if you try to recompile your entire \nsystem something will break, and you can go for a very long time without \ndiscovering that this has happened.  Second, development can often lead \nto dead-ends where you want to throw everything you've just done away, \ngo back to some earlier version of *some but not all* of your code, and \nstart over.\n\nIn other words, it is not uncommon to want to roll back an individual \nfile or set of files to an earlier version and leave the rest of the \ntree alone.  git can do this, but it's not straightforward.  Simply \nrolling back through the history of the current branch doesn't work \nbecause you might want to roll back file A, but the last dozen revisions \nor so have been changes to file B.  You might also want to roll both A \nand B back to states which never co-existed in the original history.\n\nOne approach is to use git rev-list to find those commits where \nparticular files changed, but this is sub-optimal for several reasons.  \nFirst, a naive approach calls rev-list for every rollback, and rev-list \nhas to traverse the entire history, so it's very inefficient.  Second, \nif you roll back a single file, git doesn't keep track of that file's \nprovenance, so you have to manually track which files and have been \nrolled back and which revisions they have been rolled back to.  (There \nwas a third problem but I can't think what it was right now.)\n\nI have this intuition that git can be made to really do this right by \nkeeping a separate history of every individual file in addition to a \nhistory of the entire source tree.  Git can't do this directly as far as \nI know.  I'd be writing additional code to generate extra tree and \ncommit objects every time a file was saved from the IDE.  But turning \nthis intuition into reality is turning out to be quite challenging.  So \nI'm going with the rev-list approach for the first version despite its \nshortcomings.\n\nIf anyone has ideas or suggestions, feedback would be much appreciated.  \nBut this is mostly just FYI.\n\nrg\n"},{"id":"133104","messageId":"1264840729-sup-5264@ezyang","threadId":"22449","inReplyTo":"ron1-09825C.00261930012010@news.gmane.org","subject":"Re: My use case","fromName":"Edward Z. Yang","fromEmail":"ezyang@mit.edu","sentAt":"2010-01-30T08:47:43Z","receivedAt":"2010-01-30T08:47:43Z","isPatch":false,"sender":{"key":"ezyang@mit.edu","avatar":"https://gravatar.com/avatar/6aaa9d10a82c2cf3d676f1f9397c2ae05ee2534182eda446128c0fe7c04494ba?d=mp&s=160"},"body":"Excerpts from Ron Garret's message of Sat Jan 30 03:26:19 -0500 2010:\n> In other words, it is not uncommon to want to roll back an individual \n> file or set of files to an earlier version and leave the rest of the \n> tree alone.  git can do this, but it's not straightforward.  Simply \n> rolling back through the history of the current branch doesn't work \n> because you might want to roll back file A, but the last dozen revisions \n> or so have been changes to file B.  You might also want to roll both A \n> and B back to states which never co-existed in the original history.\n> \n> One approach is to use git rev-list to find those commits where \n> particular files changed, but this is sub-optimal for several reasons.  \n> First, a naive approach calls rev-list for every rollback, and rev-list \n> has to traverse the entire history, so it's very inefficient.  Second, \n> if you roll back a single file, git doesn't keep track of that file's \n> provenance, so you have to manually track which files and have been \n> rolled back and which revisions they have been rolled back to.  (There \n> was a third problem but I can't think what it was right now.)\n\nMy approach, in this case, would be to use git log, possibly git log -p,\nin order to view the changes in each file you were interested in rolling\nback.  If the rollback falls on a commit boundary, great; you can use\n`git checkout rev -- path`.  If not, you can perform that, and then\nuse git checkout -p to selectively revert hunks in the patch (fundamentally,\nyou can't really get better than that).\n\n> I have this intuition that git can be made to really do this right by \n> keeping a separate history of every individual file in addition to a \n> history of the entire source tree.  Git can't do this directly as far as \n> I know.  I'd be writing additional code to generate extra tree and \n> commit objects every time a file was saved from the IDE.  But turning \n> this intuition into reality is turning out to be quite challenging.  So \n> I'm going with the rev-list approach for the first version despite its \n> shortcomings.\n\nWhile Git's ability to look at individual file's history is \"slower\", it's still\nquite excellent, and you are encouraged to use it as necessary.\n\nSlightly relatedly, I'd recommend flushing to disk and committing more\noften.  It's great that the LISP REPL allows for more daring changes,\nbut having a history either way is very helpful!\n\nCheers,\nEdward\n"},{"id":"133105","messageId":"ron1-CC0A6E.00541330012010@news.gmane.org","threadId":"22449","inReplyTo":"1264840729-sup-5264@ezyang","subject":"Re: My use case","fromName":"Ron Garret","fromEmail":"ron1@flownet.com","sentAt":"2010-01-30T08:54:13Z","receivedAt":"2010-01-30T08:54:13Z","isPatch":false,"sender":{"key":"ron1@flownet.com","avatar":null},"body":"In article <1264840729-sup-5264@ezyang>,\n \"Edward Z. Yang\" <ezyang@MIT.EDU> wrote:\n\n> Excerpts from Ron Garret's message of Sat Jan 30 03:26:19 -0500 2010:\n> > In other words, it is not uncommon to want to roll back an individual \n> > file or set of files to an earlier version and leave the rest of the \n> > tree alone.  git can do this, but it's not straightforward.  Simply \n> > rolling back through the history of the current branch doesn't work \n> > because you might want to roll back file A, but the last dozen revisions \n> > or so have been changes to file B.  You might also want to roll both A \n> > and B back to states which never co-existed in the original history.\n> > \n> > One approach is to use git rev-list to find those commits where \n> > particular files changed, but this is sub-optimal for several reasons.  \n> > First, a naive approach calls rev-list for every rollback, and rev-list \n> > has to traverse the entire history, so it's very inefficient.  Second, \n> > if you roll back a single file, git doesn't keep track of that file's \n> > provenance, so you have to manually track which files and have been \n> > rolled back and which revisions they have been rolled back to.  (There \n> > was a third problem but I can't think what it was right now.)\n> \n> My approach, in this case, would be to use git log, possibly git log -p,\n> in order to view the changes in each file you were interested in rolling\n> back.  If the rollback falls on a commit boundary, great; you can use\n> `git checkout rev -- path`.  If not, you can perform that, and then\n> use git checkout -p to selectively revert hunks in the patch (fundamentally,\n> you can't really get better than that).\n\nDon't forget, I'm integrating this *into* the IDE, not just using it \n*for* the IDE.  So I want to just have a context menu on each code \nwindow with \"SNAPSHOT\" and \"ROLLBACK\" items that Just Work.  The casual \nuser won't even know that there's git behind the scenes.\n\n> > I have this intuition that git can be made to really do this right by \n> > keeping a separate history of every individual file in addition to a \n> > history of the entire source tree.  Git can't do this directly as far as \n> > I know.  I'd be writing additional code to generate extra tree and \n> > commit objects every time a file was saved from the IDE.  But turning \n> > this intuition into reality is turning out to be quite challenging.  So \n> > I'm going with the rev-list approach for the first version despite its \n> > shortcomings.\n> \n> While Git's ability to look at individual file's history is \"slower\", it's \n> still\n> quite excellent, and you are encouraged to use it as necessary.\n\nGood to know.\n\n> Slightly relatedly, I'd recommend flushing to disk and committing more\n> often.  It's great that the LISP REPL allows for more daring changes,\n> but having a history either way is very helpful!\n\nYep!  Save early, save often.  I'm actually considering an auto-save \noption where it takes a snapshot every time you evaluate a form after \nmaking a change.\n\nrg\n"},{"id":"133128","messageId":"20100130174844.GD788@thunk.org","threadId":"22449","inReplyTo":"ron1-CC0A6E.00541330012010@news.gmane.org","subject":"Re: My use case","fromName":"","fromEmail":"tytso@mit.edu","sentAt":"2010-01-30T17:48:44Z","receivedAt":"2010-01-30T17:48:44Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sat, Jan 30, 2010 at 12:54:13AM -0800, Ron Garret wrote:\n> Don't forget, I'm integrating this *into* the IDE, not just using it \n> *for* the IDE.  So I want to just have a context menu on each code \n> window with \"SNAPSHOT\" and \"ROLLBACK\" items that Just Work.  The casual \n> user won't even know that there's git behind the scenes.\n\nThis is a workflow question, I suppose, but I find things work much\nbetter if you can get the user to give you explicit commit boundaries\nso that (a) bisect works, and (b) they can describe what each commit\ndoes, and (c) so they can more easily move specific bug fixes or\nfeatures between different release branches.  The free-form hacking\nmore may be nice, and very \"LISP-like\", but there are some real\nadvantages to having explicitly describable and documented commits.\n\nBest regards,\n\n\t\t\t\t\t- Ted\n"},{"id":"133130","messageId":"ron1-A58BC7.10295430012010@news.gmane.org","threadId":"22449","inReplyTo":"20100130174844.GD788@thunk.org","subject":"Re: My use case","fromName":"Ron Garret","fromEmail":"ron1@flownet.com","sentAt":"2010-01-30T18:29:54Z","receivedAt":"2010-01-30T18:29:54Z","isPatch":false,"sender":{"key":"ron1@flownet.com","avatar":null},"body":"In article <20100130174844.GD788@thunk.org>, tytso@mit.edu wrote:\n\n> On Sat, Jan 30, 2010 at 12:54:13AM -0800, Ron Garret wrote:\n> > Don't forget, I'm integrating this *into* the IDE, not just using it \n> > *for* the IDE.  So I want to just have a context menu on each code \n> > window with \"SNAPSHOT\" and \"ROLLBACK\" items that Just Work.  The casual \n> > user won't even know that there's git behind the scenes.\n> \n> This is a workflow question, I suppose, but I find things work much\n> better if you can get the user to give you explicit commit boundaries\n> so that (a) bisect works, and (b) they can describe what each commit\n> does, and (c) so they can more easily move specific bug fixes or\n> features between different release branches.  The free-form hacking\n> more may be nice, and very \"LISP-like\", but there are some real\n> advantages to having explicitly describable and documented commits.\n\nYou are absolutely right.  That is another reason why having the \nindividual files tracked separately from the main project would be a \ngood thing if I can get it to work.  (It would be kind of like having a \ngit-stash on a per-file basis.)\n\nrg\n"},{"id":"133133","messageId":"7vtyu3o1hq.fsf@alter.siamese.dyndns.org","threadId":"22449","inReplyTo":"ron1-A58BC7.10295430012010@news.gmane.org","subject":"Re: My use case","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-30T19:07:29Z","receivedAt":"2010-01-30T19:07:29Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ron Garret <ron1@flownet.com> writes:\n\n> You are absolutely right.  That is another reason why having the \n> individual files tracked separately from the main project would be a \n> good thing if I can get it to work.  (It would be kind of like having a \n> git-stash on a per-file basis.)\n\nWhen you have more than one functions defined in a file, and the\ninteractive Lisp development cycle works primarily on s-exp basis, not\nnecessarily constrained by file boundaries, don't you want even finer\ngrained control than \"stash per-file\"?\n\nI don't think of a good solution myself, but I find your \"finer than whole\ntree\" an interesting topic.\n"},{"id":"133134","messageId":"ron1-EF6DDC.11194530012010@news.gmane.org","threadId":"22449","inReplyTo":"7vtyu3o1hq.fsf@alter.siamese.dyndns.org","subject":"Re: My use case","fromName":"Ron Garret","fromEmail":"ron1@flownet.com","sentAt":"2010-01-30T19:19:45Z","receivedAt":"2010-01-30T19:19:45Z","isPatch":false,"sender":{"key":"ron1@flownet.com","avatar":null},"body":"In article <7vtyu3o1hq.fsf@alter.siamese.dyndns.org>,\n Junio C Hamano <gitster@pobox.com> wrote:\n\n> Ron Garret <ron1@flownet.com> writes:\n> \n> > You are absolutely right.  That is another reason why having the \n> > individual files tracked separately from the main project would be a \n> > good thing if I can get it to work.  (It would be kind of like having a \n> > git-stash on a per-file basis.)\n> \n> When you have more than one functions defined in a file, and the\n> interactive Lisp development cycle works primarily on s-exp basis, not\n> necessarily constrained by file boundaries, don't you want even finer\n> grained control than \"stash per-file\"?\n> \n> I don't think of a good solution myself, but I find your \"finer than whole\n> tree\" an interesting topic.\n\nYou're reading my mind.  My long-term vision for this thing is indeed a \nrevision control system based on S-expressions, not files.  (I \npersonally think the whole concept of files is fundamentally broken, but \nthat's a whole 'nuther kettle of lobster.)  Unfortunately, that opens up \na Pandora's box of ancillary issues, which would be seriously off-topic \nhere.  If you're interested we can talk about it off-line (or we can do \nit here if you think it's not too much of a tangent).\n\nrg\n"}]}