{"thread":{"id":"43093","subject":"[PATCH 1/2] Move in_merge_bases() to commit.c","startedAt":"2006-12-16T23:10:53Z","lastAt":"2006-12-20T00:58:25Z","messageCount":28,"participants":["Junio C Hamano","Linus Torvalds","Shawn Pearce","Andy Parkins","Brian Gernhardt","Jakub Narebski","Yann Dirson","Josef Weidendorfer"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"295241","messageId":"7vodq3a136.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":null,"subject":"What's cooking in git.git (topics)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-16T23:10:53Z","receivedAt":"2006-12-16T23:10:53Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Things that I feel should be done need to be done to complete\nv1.5.0 are:\n\n - 'git-rm' needs to be fixed up as Linus outlined; remove\n   working tree file and index entry but have a sanity check to\n   make sure the working tree file match the index and HEAD.\n\n - tutorials and other Porcelain documentation pages need to be\n   updated to match the updated 'git-add' and 'git-rm' (to be\n   updated), and their description should be made much less\n   about implementation; they should talk in terms of end-user\n   workflows.\n\n   We need a full sweep on Porcelain-ish documentation.\n\n - now reflog is enabled by default for user repositories, I\n   have two worries about its effect, fortunately can be killed\n   with a single stone.\n\n   * the reflog grows unbounded;\n\n   * revisions recorded in the reflog can be pruned out,\n     rendering some entries in reflog useless.\n\n   I am thinking about teaching fsck-objects and prune to keep\n   revisions recorded in the reflog; we would need an end-user\n   way to prune older reflog entries and I would appreciate\n   somebody codes it up, but even without it, people can always\n   use \"vi\" or \"ed\" on reflog files ;-).\n\n - 'git-add' might want to do 'update-index --replace'; probably\n   needs a sanity-checking discussion before implementing it.\n\n - 'git-svn' users should speak out about two issues:\n\n   * use of svn command line client as the backend is being\n     removed;\n\n   * 'git-svn commit' command is being renamed to avoid\n     confusion, and potentially 'dcommit' will be renamed to \n     'commit'.\n\n   Please discuss these with Eric.\n\n - we might want to address the issue that 'git-status' output\n   does not make it easy to tell mode changes from content\n   changes.  Personally I do not like cryptic \"M+\" output format\n   proposed by Lars and find the current output more readable.\n\n----------------------------------------------------------------\nAs usual, '+' are both in 'next' and 'pu', '-' are in 'pu' only.\n\n*  jn/web (Sat Dec 16 17:12:55 2006 +0100) 9 commits\n - gitweb: Add some mod_perl specific support\n + gitweb: Add \"next\" link to commit view\n + gitweb: Add title attribute to ref marker with full ref name\n + gitweb: Do not show difftree for merges in \"commit\" view\n + gitweb: SHA-1 in commit log message links to \"object\" view\n + gitweb: Hyperlink target of symbolic link in \"tree\" view (if\n   possible)\n + gitweb: Add generic git_object subroutine to display object of any\n   type\n + gitweb: Show target of symbolic link in \"tree\" view\n + gitweb: Don't use Content-Encoding: header in git_snapshot\n\nAll except the tip (mod_perl) looked good and should be in\nv1.5.0; I haven't formed an opinion on mod_perl change yet.\n\n*  js/branch-config (Sat Dec 16 15:15:02 2006 +0100) 2 commits\n + git-branch: rename config vars branch.<branch>.*, too\n + add a function to rename sections in the config\n\nThis moves branch.$foo.* variables to branch.$bar.* when $foo\nbranch is renamed to $bar.  Because we already have branch -m\n(stands for \"mv\"), this series is a must-have in v1.5.0.\n\n*  jc/clone (Sat Dec 16 01:53:10 2006 -0800) 4 commits\n + git-clone: lose the traditional 'no-separate-remote' layout\n + git-clone: lose the artificial \"first\" fetch refspec\n + git-pull: refuse default merge without branch.*.merge\n + git-clone: use wildcard specification for tracking branches\n\nFixes the workflow wart and removes the traditional layout that\nmaps remote 'master' to refs/heads/origin.  Also 'git pull' and\n'git pull origin' would not merge the ref on the first Pull:\nline (nor remote.*.fetch item) anymore.  You either have to give\nan explicit command line parameter or branch.$currbranch.merge\nitem.  With blessing from Linus, this will be in v1.5.0.\n\n*  ew/svn-pm (Fri Dec 15 23:58:08 2006 -0800) 3 commits\n + git-svn: rename 'commit' command to 'set-tree'\n + git-svn: remove support for the svn command-line client\n + git-svn: convert to using Git.pm\n\nIt is in 'next' because I agree it is in the right direction in\nthe longer term, but not in 'master' because this might be\ncontrovertial for shorter term.  The users should decide.\n\n** jc/reflog (Thu Dec 14 15:58:56 2006 -0800) 1 commit\n - Teach show-branch how to show ref-log data.\n\nA strawman to make reflog data a bit more browsable; it would be\nuseful while recovering from a mistake you made recently.  Not\nessential and can wait or be dropped if people do not find it\nuseful.\n\n** jc/git-add--interactive (Mon Dec 11 17:09:26 2006 -0800) 2 commits\n - git-add --interactive: hunk splitting\n - git-add --interactive\n\nI've thought about further allowing to edit the patches in the\n'patch' subcommand, but the more I think about it, the less it\nmakes sense from the workflow point of view.  Will be the topic\nfor a separate message.\n\n** sv/git-svn (Tue Dec 5 16:17:38 2006 +1100) 5 commits\n . git-svn: re-map repository URLs and UUIDs on SVK mirror paths\n . git-svn: collect revision properties when fetching\n . git-svn: collect SVK source URL on mirror paths\n . git-svn: let libsvn_ls_fullurl return properties too\n . git-svn: make test for SVK mirror path import\n\nStill held but dropped from 'pu' for now (depends on \"sub sys\"\nthat was removed from git-svn).\n\n** jc/explain (Mon Dec 4 19:35:04 2006 -0800) 1 commit\n - git-explain\n\nBackburnered.\n\n*  jc/blame-boundary (Fri Dec 1 20:45:45 2006 -0800) 1 commit\n + git-blame: show lines attributed to boundary commits differently.\n\nWill merge.\n\n*  jc/3way (Wed Nov 29 18:53:13 2006 -0800) 1 commit\n + git-merge: preserve and merge local changes when doing fast\n   forward\n\nWill merge, if only to see what breaks.\n\n*  js/shallow (Fri Nov 24 16:00:13 2006 +0100) 15 commits\n + fetch-pack: Do not fetch tags for shallow clones.\n + get_shallow_commits: Avoid memory leak if a commit has been\n   reached already.\n + git-fetch: Reset shallow_depth before auto-following tags.\n + upload-pack: Check for NOT_SHALLOW flag before sending a shallow\n   to the client.\n + fetch-pack: Properly remove the shallow file when it becomes\n   empty.\n + shallow clone: unparse and reparse an unshallowed commit\n + Why didn't we mark want_obj as ~UNINTERESTING in the old code?\n + Why does it mean we do not have to register shallow if we have\n   one?\n + We should make sure that the protocol is still extensible.\n + add tests for shallow stuff\n + Shallow clone: do not ignore shallowness when following tags\n + allow deepening of a shallow repository\n + allow cloning a repository \"shallowly\"\n + support fetching into a shallow repository\n + upload-pack: no longer call rev-list\n\nUndecided but not likely to be in v1.5.0.  Needs more real\nproject testing.\n\n** jc/web (Wed Nov 8 14:54:09 2006 -0800) 1 commit\n - gitweb: steal loadavg throttle from kernel.org\n\nUndecided.\n\n** jc/pickaxe (Sun Nov 5 11:52:43 2006 -0800) 1 commit\n - blame: --show-stats for easier optimization work.\n\nDeveloper only.\n\n** jc/leftright (Sun Oct 22 17:32:47 2006 -0700) 1 commit\n - rev-list --left-right\n\nBackburnered.\n\n** jc/diff (Mon Sep 25 23:03:34 2006 -0700) 1 commit\n - para-walk: walk n trees, index and working tree in parallel\n\nBackburnered.\n\n*  jc/diff-apply-patch (Fri Sep 22 16:17:58 2006 -0700) 1 commit\n + git-diff/git-apply: make diff output a bit friendlier to GNU patch\n   (part 2)\n\nNot in v1.5.0.\n"},{"id":"295634","messageId":"em1vgj$bc3$1@sea.gmane.org","threadId":"43093","inReplyTo":"7vodq3a136.fsf@assigned-by-dhcp.cox.net","subject":"Re: What's cooking in git.git (topics)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-12-16T23:29:25Z","receivedAt":"2006-12-16T23:29:25Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n> Things that I feel should be done need to be done to complete\n> v1.5.0 are:\n[...]\n>  - now reflog is enabled by default for user repositories, I\n>    have two worries about its effect, fortunately can be killed\n>    with a single stone.\n> \n>    * the reflog grows unbounded;\n> \n>    * revisions recorded in the reflog can be pruned out,\n>      rendering some entries in reflog useless.\n> \n>    I am thinking about teaching fsck-objects and prune to keep\n>    revisions recorded in the reflog; we would need an end-user\n>    way to prune older reflog entries and I would appreciate\n>    somebody codes it up, but even without it, people can always\n>    use \"vi\" or \"ed\" on reflog files ;-).\n\nI'd rather not have prune keep revisions recorded in reflog. Reflog\nkeeps also amended commits, and blobs from incrementally staged\ncommits. Or perhaps make it an configuration option, default to\ntrue for new users (or have an option to git-prune to ignore reflog).\n\nAs of \"reflog grows unbounded\"... perhaps we should encourage to use\nlogrotate for that (well, perhaps git-prune and porcelains which deal\nwith reflog should be able to uncompress reflog if needed).\n\n>  - 'git-svn' users should speak out about two issues:\n> \n>    * use of svn command line client as the backend is being\n>      removed;\n> \n>    * 'git-svn commit' command is being renamed to avoid\n>      confusion, and potentially 'dcommit' will be renamed to \n>      'commit'.\n> \n>    Please discuss these with Eric.\n\nWhat about remote.<repo>.url = svn://ser.ver/repo/ idea?\n \n> ** jc/reflog (Thu Dec 14 15:58:56 2006 -0800) 1 commit\n>  - Teach show-branch how to show ref-log data.\n> \n> A strawman to make reflog data a bit more browsable; it would be\n> useful while recovering from a mistake you made recently.  Not\n> essential and can wait or be dropped if people do not find it\n> useful.\n\nLooks useful.\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n\n"},{"id":"298503","messageId":"7v4prv8jcn.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"em1vgj$bc3$1@sea.gmane.org","subject":"Re: What's cooking in git.git (topics)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-17T00:19:20Z","receivedAt":"2006-12-17T00:19:20Z","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> Junio C Hamano wrote:\n>\n>> Things that I feel should be done need to be done to complete\n>> v1.5.0 are:\n> [...]\n>>  - now reflog is enabled by default for user repositories, I\n>>    have two worries about its effect, fortunately can be killed\n>>    with a single stone.\n>> \n>>    * the reflog grows unbounded;\n>> \n>>    * revisions recorded in the reflog can be pruned out,\n>>      rendering some entries in reflog useless.\n>> \n>>    I am thinking about teaching fsck-objects and prune to keep\n>>    revisions recorded in the reflog; we would need an end-user\n>>    way to prune older reflog entries and I would appreciate\n>>    somebody codes it up, but even without it, people can always\n>>    use \"vi\" or \"ed\" on reflog files ;-).\n>\n> I'd rather not have prune keep revisions recorded in reflog. Reflog\n> keeps also amended commits, and blobs from incrementally staged\n> commits.\n\nThat is exactly why I would want to protect them from pruning;\nthe current alternative, git-lost-found, is usable but not so\nnice from the point of view of end users .  The user should be\nable to use show-branch --reflog, or use a different mode of\noperation in the log family [*1*] to inspect the otherwise lost\ncommits, and as you prune unneeded reflog entries you could\nprune those objects.\n\nYou could certainly arrange things the other way around.  As a\npart of prune, you can prune the reflog entries that refer to\ncommits that were pruned away and no longer available.\n\nHOWEVER, that is very unfriendly to the end users, because they\ndo not have much control in what 'prune' removes.  If you want\nto keep a dozen or so recent states just in case you may have to\nsalvage rewound states (e.g. you may realize your amended commit\nwas faulty), how would you tell 'prune' to keep only those\nobjects from getting pruned?\n\nThat's right -- by holding references to them.  And that is\nexactly how making prune to take reflog into account would help\nthe user.  If the user has unwanted commits (say, everything\nthat are more than 7 days old, plus this and that commits you\nrewound an hour ago), they can be pruned away from reflog and\nprune will take care of the rest.\n\nSo doing it in the way I described makes a lot more sense than\ndoing the other way around.\n\n[Footnote]\n\n*1* I have to warn you that this would require quite different\ncode to walk the commits, but certainly a lot simpler than the\nancestry traversal.  If you are interested in learning the\ninternals, this may be a good project to start with.\n"},{"id":"294990","messageId":"3C540990-B78E-405B-ACFF-F558DB776C85@silverinsanity.com","threadId":"43093","inReplyTo":"7vodq3a136.fsf@assigned-by-dhcp.cox.net","subject":"Re: What's cooking in git.git (topics)","fromName":"Brian Gernhardt","fromEmail":"benji@silverinsanity.com","sentAt":"2006-12-17T04:35:20Z","receivedAt":"2006-12-17T04:35:20Z","isPatch":false,"sender":{"key":"benji@silverinsanity.com","avatar":"https://gravatar.com/avatar/e06c101dbc25c68114d859b4a9ec7cf8a2c52fd2b0270ef0eac0e2e63ff22311?d=mp&s=160"},"body":"> ** jc/reflog (Thu Dec 14 15:58:56 2006 -0800) 1 commit\n>  - Teach show-branch how to show ref-log data.\n>\n> A strawman to make reflog data a bit more browsable; it would be\n> useful while recovering from a mistake you made recently.  Not\n> essential and can wait or be dropped if people do not find it\n> useful.\n\nI'd prefer not to add clutter into show-branch.  I use it on a  \nregular basis to see what I've added to what topic branch recently,  \nand to look at branches before rebasing.  It also just seems like the  \nwrong place to have that kind of data, although I guess it's more  \nuseful for people who do merges more often than I do.\n\nWhat about a \"git reflog [<branch>]\" command instead?  Would show  \noutput similar to \"git log\" (or \"git show-branch\" for brevity).\n\n"},{"id":"294855","messageId":"20061217044237.GC19636@spearce.org","threadId":"43093","inReplyTo":"3C540990-B78E-405B-ACFF-F558DB776C85@silverinsanity.com","subject":"Re: What's cooking in git.git (topics)","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-12-17T04:42:37Z","receivedAt":"2006-12-17T04:42:37Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Brian Gernhardt <benji@silverinsanity.com> wrote:\n> >** jc/reflog (Thu Dec 14 15:58:56 2006 -0800) 1 commit\n> > - Teach show-branch how to show ref-log data.\n> \n> What about a \"git reflog [<branch>]\" command instead?  Would show  \n> output similar to \"git log\" (or \"git show-branch\" for brevity).\n\nIt has been proposed on the list.  I even sketched out what such\na command would look like, how it should present the data, etc.\nBut I never wrote it.  Nobody else has taken up the task either.  :-)\n\n-- \n"},{"id":"298485","messageId":"7vbqm36mv6.fsf_-_@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"3C540990-B78E-405B-ACFF-F558DB776C85@silverinsanity.com","subject":"[PATCH] revision: introduce ref@{N..M} syntax.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-17T06:46:21Z","receivedAt":"2006-12-17T06:46:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brian Gernhardt <benji@silverinsanity.com> writes:\n\n>> ** jc/reflog (Thu Dec 14 15:58:56 2006 -0800) 1 commit\n>>  - Teach show-branch how to show ref-log data.\n>>\n>> A strawman to make reflog data a bit more browsable; it would be\n>> useful while recovering from a mistake you made recently.  Not\n>> essential and can wait or be dropped if people do not find it\n>> useful.\n>\n> I'd prefer not to add clutter into show-branch.  I use it on a regular\n> basis to see what I've added to what topic branch recently,  and to\n> look at branches before rebasing.  It also just seems like the  wrong\n> place to have that kind of data, although I guess it's more  useful\n> for people who do merges more often than I do.\n\nI happen to find it a reasonable way to present how a topic was\nrewind and rebuilt, but I think that is I rewind my internal\ntopic (i.e. the parts that have not been merged into 'next' yet)\nall the time.\n\n> What about a \"git reflog [<branch>]\" command instead?  Would show\n> output similar to \"git log\" (or \"git show-branch\" for brevity).\n\nThis is not a 'git reflog' command, but is another way to show\nthe tips of reflog entries (use it with 'git show').  I find the\nshow-branch variant easier to see, but you can judge for\nyourself.\n\nThis happens to show why pruning while not culling reflog\nentries is a bad idea.  If your master@{2} is gone due to rewind\nand prune, and master@{0}, master@{1} and master@{3} are still\navailable, the pattern master@{0..3} would not give you a usable\nresult.\n\n-- >8 --\nThis allows you to add between Nth and Mth (inclusive) reflog entries.\n\"git show master@{1} master@{2} master@{3}\" is equivalent to\n\"git show master@{1..3}\".\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n revision.c |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 59 insertions(+), 0 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 993bb66..3f1d65e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -592,6 +592,59 @@ static void prepare_show_merge(struct rev_info *revs)\n \trevs->prune_data = prune;\n }\n \n+static int parse_digits(const char *p, int len)\n+{\n+\tint accum = 0;\n+\twhile (0 < len--) {\n+\t\tint ch = *p++;\n+\t\tif ('0' <= ch && ch <= '9')\n+\t\t\taccum = accum * 10 + ch - '0';\n+\t\telse\n+\t\t\treturn -1;\n+\t}\n+\treturn accum;\n+}\n+\n+static int list_of_reflog_entries(const char *arg, const char *dotdot,\n+\t\t\t\t  struct rev_info *revs, int flags)\n+{\n+\t/*\n+\t * \"ref@{N..M}\" -- push them for \"git show\".\n+\t * dotdot points at the first dot\n+\t */\n+\tint n, m, i, added;\n+\tint len;\n+\tchar *at_brace = strstr(arg, \"@{\");\n+\n+\n+\tif (!at_brace)\n+\t\treturn 0;\n+\tlen = strlen(arg);\n+\tif (arg[len-1] != '}')\n+\t\treturn 0;\n+\tif ((m = parse_digits(dotdot + 2, len - (dotdot - arg) - 3)) < 0)\n+\t\treturn 0;\n+\tif ((n = parse_digits(at_brace + 2, dotdot - at_brace - 2)) < 0)\n+\t\treturn 0;\n+\tif (n > m)\n+\t\treturn 0;\n+\n+\tadded = 0;\n+\tfor (i = n; i <= m; i++) {\n+\t\tchar buf[1024];\n+\t\tunsigned char sha1[20];\n+\n+\t\tsnprintf(buf, sizeof(buf), \"%.*s@{%d}\",\n+\t\t\t (int) (at_brace - arg), arg, i);\n+\t\tif (!get_sha1(buf, sha1)) {\n+\t\t\t/* this is synthetic -- do not check filename */\n+\t\t\thandle_revision_arg(buf, revs, flags, 1);\n+\t\t\tadded = 1;\n+\t\t}\n+\t}\n+\treturn added;\n+}\n+\n int handle_revision_arg(const char *arg, struct rev_info *revs,\n \t\t\tint flags,\n \t\t\tint cant_be_filename)\n@@ -648,7 +701,13 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,\n \t\t\tadd_pending_object(revs, &b->object, next);\n \t\t\treturn 0;\n \t\t}\n+\n \t\t*dotdot = '.';\n+\n+\t\t/* It could be ref@{N..M} */\n+\t\tif (list_of_reflog_entries(arg, dotdot, revs, flags))\n+\t\t\treturn 0;\n+\n \t}\n \tdotdot = strstr(arg, \"^@\");\n \tif (dotdot && !dotdot[2]) {\n-- \n1.4.4.2.g83c5\n"},{"id":"297848","messageId":"20061217173534.GA16838@nan92-1-81-57-214-146.fbx.proxad.net","threadId":"43093","inReplyTo":"em1vgj$bc3$1@sea.gmane.org","subject":"Re: What's cooking in git.git (topics)","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2006-12-17T17:35:34Z","receivedAt":"2006-12-17T17:35:34Z","isPatch":false,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"On Sun, Dec 17, 2006 at 12:29:25AM +0100, Jakub Narebski wrote:\n> >    I am thinking about teaching fsck-objects and prune to keep\n> >    revisions recorded in the reflog; we would need an end-user\n> >    way to prune older reflog entries and I would appreciate\n> >    somebody codes it up, but even without it, people can always\n> >    use \"vi\" or \"ed\" on reflog files ;-).\n> \n> I'd rather not have prune keep revisions recorded in reflog. Reflog\n> keeps also amended commits, and blobs from incrementally staged\n> commits. Or perhaps make it an configuration option, default to\n> true for new users (or have an option to git-prune to ignore reflog).\n\nI think that is quite near to other issues: we already have other pieces\nof information that we would like to sometimes have ignored and\nsometimes not, when running fsck-objects/prune.  Namely, revisions\nhidden by grafts, as already discussed on this list.\n\nAn idea I had to handle that case, and which could be useful with the\ncurrent problem, as well as others, like dealing with stgit's patch\nlogging, would be to define \"reachable commits\" using a modular\narchitecture.  That way we would be able to select what we want\nfsck-object/prune to consider reachable, in objects reachable from:\n\n- raw \"parents\" field of commit objects\n- the latter as modified by info/grafts\n- reflogs\n- stgit patchlogs\n\nThe set of rules to consider could be declared in repo-config, thus\nstgit would be able to declare that its patchlogs should not be ignored,\nand people wishing to prune commits hidden by grafts in one repo could\njust remove the \"raw-parents\" rule from their repo's config.\n\nObviously, mentionning stgit-specific rules here immediately suggests a\nplugin-based architecture.\n\nDoes that make any sense ?\n\n-- \n"},{"id":"294007","messageId":"Pine.LNX.4.64.0612171009550.3479@woody.osdl.org","threadId":"43093","inReplyTo":"7vbqm36mv6.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] revision: introduce ref@{N..M} syntax.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-12-17T18:14:12Z","receivedAt":"2006-12-17T18:14:12Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 16 Dec 2006, Junio C Hamano wrote:\n>\n> This allows you to add between Nth and Mth (inclusive) reflog entries.\n> \"git show master@{1} master@{2} master@{3}\" is equivalent to\n> \"git show master@{1..3}\".\n\nWell, logically, if you do that, then you should also allow\n\n\tgit log master@{one.week.ago..yesterday}\n\nas a reflog expression.\n\n\"Because It Only Makes Sense(tm)\".\n\n\t\tLinus\n\nPS. Yeah, I'm only half serious. I like our revision parsing, and the \nabove _would_ actually be consistent with the \"master@{1..3}\" kind of \nspecification, but at the same time, it's also obviously more complex, and \nmaybe it's not THAT usable.\n\nBut I think the \"master@{date..date}\" syntax would actually fall out \nautomatically if you did the {x..y} parsing at a higher level and didn't \n"},{"id":"294830","messageId":"7vy7p65n3j.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"Pine.LNX.4.64.0612171009550.3479@woody.osdl.org","subject":"Re: [PATCH] revision: introduce ref@{N..M} syntax.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-17T19:38:56Z","receivedAt":"2006-12-17T19:38:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Well, logically, if you do that, then you should also allow\n>\n> \tgit log master@{one.week.ago..yesterday}\n>\n> as a reflog expression.\n> ...\n> PS. Yeah, I'm only half serious. I like our revision parsing, and the \n> above _would_ actually be consistent with the \"master@{1..3}\" kind of \n> specification, but at the same time, it's also obviously more complex, and \n> maybe it's not THAT usable.\n>\n> But I think the \"master@{date..date}\" syntax would actually fall out \n> automatically if you did the {x..y} parsing at a higher level and didn't \n> force \"x\" and \"y\" to be digits only.\n\nSyntax, yes, usage of it in \"git show\" yes,\n\nBut giving it to \"git log\" would not work as a naive user would\nexpect, which your example suggested ;-).\n\n"},{"id":"298174","messageId":"200612180038.34525.Josef.Weidendorfer@gmx.de","threadId":"43093","inReplyTo":"20061217173534.GA16838@nan92-1-81-57-214-146.fbx.proxad.net","subject":"Re: What's cooking in git.git (topics)","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2006-12-17T23:38:34Z","receivedAt":"2006-12-17T23:38:34Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Sunday 17 December 2006 18:35, Yann Dirson wrote:\n> An idea I had to handle that case, and which could be useful with the\n> current problem, as well as others, like dealing with stgit's patch\n> logging, would be to define \"reachable commits\" using a modular\n> architecture.  That way we would be able to select what we want\n> fsck-object/prune to consider reachable, in objects reachable from:\n> \n> - raw \"parents\" field of commit objects\n> - the latter as modified by info/grafts\n> - reflogs\n> - stgit patchlogs\n\nCould be interesting for pruning support in submodules, too.\n\n> The set of rules to consider could be declared in repo-config, thus\n> stgit would be able to declare that its patchlogs should not be ignored,\n> and people wishing to prune commits hidden by grafts in one repo could\n> just remove the \"raw-parents\" rule from their repo's config.\n> \n> Obviously, mentionning stgit-specific rules here immediately suggests a\n> plugin-based architecture.\n\nIsn't it enough to specify further subdirectories of .git/, holding\nreferences which should be taken into account while pruning?\nHmm.. Grafting would be a special case.\n\n"},{"id":"298419","messageId":"200612172341.27709.andyparkins@gmail.com","threadId":"43093","inReplyTo":"7vodq3a136.fsf@assigned-by-dhcp.cox.net","subject":"Re: What's cooking in git.git (topics)","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2006-12-17T23:41:25Z","receivedAt":"2006-12-17T23:41:25Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Saturday 2006, December 16 23:10, Junio C Hamano wrote:\n\n>    * revisions recorded in the reflog can be pruned out,\n>      rendering some entries in reflog useless.\n\nCan I suggest that it should be fine to prune reflog entries but that the act \nof pruning be a log entry itself?\n\nAndy\n-- \nDr Andrew Parkins, M Eng (Hons), AMIEE\n"},{"id":"296291","messageId":"7vac1l1v8e.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"200612172341.27709.andyparkins@gmail.com","subject":"Re: What's cooking in git.git (topics)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-18T08:09:05Z","receivedAt":"2006-12-18T08:09:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Parkins <andyparkins@gmail.com> writes:\n\n> On Saturday 2006, December 16 23:10, Junio C Hamano wrote:\n>\n>>    * revisions recorded in the reflog can be pruned out,\n>>      rendering some entries in reflog useless.\n>\n> Can I suggest that it should be fine to prune reflog entries but that the act \n> of pruning be a log entry itself?\n\nI do not understand.  What would that \"pruning event\" log entry\nwould say?\n\nBy definition each reflog entry says \"it was pointing at this\nobject before, and it was changed by this user to point at that\nobject at this time and the reason for the change was this\".\n\nI personally do not think recording \"at this point these things\nwere pruned\" makes _any_ sense whatsoever --- if you care about\nthe pruned objects that simply means you pruned them before you\nare ready to lose them.  But even if for whatever reason you\nchoose to log that anyway, I have a feeling that that record\ndoes not belong to the reflog itself.\n\n"},{"id":"294468","messageId":"200612180917.46214.andyparkins@gmail.com","threadId":"43093","inReplyTo":"7vac1l1v8e.fsf@assigned-by-dhcp.cox.net","subject":"Re: What's cooking in git.git (topics)","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2006-12-18T09:17:44Z","receivedAt":"2006-12-18T09:17:44Z","isPatch":false,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Monday 2006 December 18 08:09, Junio C Hamano wrote:\n\n> By definition each reflog entry says \"it was pointing at this\n> object before, and it was changed by this user to point at that\n> object at this time and the reason for the change was this\".\n\nI'm daft.  I've realised, pruning doesn't remove the ref, it removes one of \nthe hashes in the reflog.  I withdraw my comment.\n\nI'd imagined it' as the opposite of a creation.\n\n000000 abcdef  branch created\nabcdef 000000  branch deleted\n\nWhich is fine, except that isn't what prune is doing at all.\n\n> I personally do not think recording \"at this point these things\n> were pruned\" makes _any_ sense whatsoever --- if you care about\n\nI think you're right. :-)\n\n\nAndy\n\n-- \nDr Andy Parkins, M Eng (hons), MIEE\n"},{"id":"297473","messageId":"20061218093339.GB9727@spearce.org","threadId":"43093","inReplyTo":"200612180917.46214.andyparkins@gmail.com","subject":"Re: What's cooking in git.git (topics)","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-12-18T09:33:40Z","receivedAt":"2006-12-18T09:33:40Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Andy Parkins <andyparkins@gmail.com> wrote:\n> I'm daft.  I've realised, pruning doesn't remove the ref, it removes one of \n> the hashes in the reflog.  I withdraw my comment.\n> \n> I'd imagined it' as the opposite of a creation.\n> \n> 000000 abcdef  branch created\n> abcdef 000000  branch deleted\n\nExcept that branch deletion also deletes the reflog.  So yes, we\ncould log it as you show above, but right after we appended it to\nthe log we'd delete the log anyway.  :-)\n\nThe immediate log deletion is necessary to support something like:\n\n\tgit branch foo\n\tgit branch -d foo\n\tgit branch foo/bar\n\nas foo switches from being a file to a directory, which means that\n.git/logs/refs/heads/foo also needs to switch from being a file to\nbeing a directory.\n\n\nThe only way to fix the above situation is to make the reflog a\nsingle log for the entire repository, rather than one log per ref.\nThis may cause locking problems for us as we need to lock not only\nthe ref but also the repository-wide reflog lock.  Note that right\nnow the reflog is also protected by the ref lock itself, killing\ntwo birds with one stone.  :-)\n\n-- \n"},{"id":"297305","messageId":"7vzm9lzgnf.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"7vodq3a136.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 1/2] add for_each_reflog_ent() iterator","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-18T09:40:04Z","receivedAt":"2006-12-18T09:40:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n refs.c |   25 +++++++++++++++++++++++++\n refs.h |    4 ++++\n 2 files changed, 29 insertions(+), 0 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex d911b9e..db8fdd4 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1093,3 +1093,28 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *\n \t\tlogfile, show_rfc2822_date(date, tz));\n \treturn 0;\n }\n+\n+void for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)\n+{\n+\tconst char *logfile;\n+\tFILE *logfp;\n+\tchar buf[1024];\n+\n+\tlogfile = git_path(\"logs/%s\", ref);\n+\tlogfp = fopen(logfile, \"r\");\n+\tif (!logfp)\n+\t\treturn;\n+\twhile (fgets(buf, sizeof(buf), logfp)) {\n+\t\tunsigned char osha1[20], nsha1[20];\n+\t\tint len;\n+\n+\t\t/* old SP new SP name <email> SP time TAB msg LF */\n+\t\tlen = strlen(buf);\n+\t\tif (len < 83 || buf[len-1] != '\\n' ||\n+\t\t    get_sha1_hex(buf, osha1) || buf[40] != ' ' ||\n+\t\t    get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ')\n+\t\t\tcontinue; /* corrupt? */\n+\t\tfn(osha1, nsha1, buf+82, cb_data);\n+\t}\n+\tfclose(logfp);\n+}\ndiff --git a/refs.h b/refs.h\nindex 51aab1e..de43cc7 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -44,6 +44,10 @@ extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, cons\n /** Reads log for the value of ref during at_time. **/\n extern int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1);\n \n+/* iterate over reflog entries */\n+typedef int each_reflog_ent_fn(unsigned char *osha1, unsigned char *nsha1, char *, void *);\n+void for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data);\n+\n /** Returns 0 if target has the right format for a ref. **/\n extern int check_ref_format(const char *target);\n \n-- \n1.4.4.2.gc30f\n\n"},{"id":"294865","messageId":"7vr6uxzgjb.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"7vodq3a136.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 2/2] Protect commits recorded in reflog from pruning.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-18T09:42:32Z","receivedAt":"2006-12-18T09:42:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This teaches fsck-objects and prune to protect objects referred\nto by reflog entries.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n >>  - now reflog is enabled by default for user repositories, I\n >>    have two worries about its effect, fortunately can be killed\n >>    with a single stone.\n >> \n >>    * the reflog grows unbounded;\n >> \n >>    * revisions recorded in the reflog can be pruned out,\n >>      rendering some entries in reflog useless.\n >> \n >>    I am thinking about teaching fsck-objects and prune to keep\n >>    revisions recorded in the reflog; we would need an end-user\n >>    way to prune older reflog entries and I would appreciate\n >>    somebody codes it up, but even without it, people can always\n >>    use \"vi\" or \"ed\" on reflog files ;-).\n\n Rewinding would not lose any objects from the object database\n with this; somebody needs to code up a garbage collector and/or\n expiration mechanism for reflogs.\n\n builtin-prune.c |   16 ++++++++++++++++\n fsck-objects.c  |   22 ++++++++++++++++++++++\n 2 files changed, 38 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-prune.c b/builtin-prune.c\nindex 8591d28..00a53b3 100644\n--- a/builtin-prune.c\n+++ b/builtin-prune.c\n@@ -181,12 +181,28 @@ static void walk_commit_list(struct rev_info *revs)\n \t}\n }\n \n+static int add_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1, char *datail, void *cb_data)\n+{\n+\tstruct object *object;\n+\n+\tobject = parse_object(osha1);\n+\tif (object)\n+\t\tadd_pending_object(&revs, object, \"\");\n+\tobject = parse_object(nsha1);\n+\tif (object)\n+\t\tadd_pending_object(&revs, object, \"\");\n+\treturn 0;\n+}\n+\n static int add_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)\n {\n \tstruct object *object = parse_object(sha1);\n \tif (!object)\n \t\tdie(\"bad object ref: %s:%s\", path, sha1_to_hex(sha1));\n \tadd_pending_object(&revs, object, \"\");\n+\n+\tfor_each_reflog_ent(path, add_one_reflog_ent, NULL);\n+\n \treturn 0;\n }\n \ndiff --git a/fsck-objects.c b/fsck-objects.c\nindex 46b628c..e3746e8 100644\n--- a/fsck-objects.c\n+++ b/fsck-objects.c\n@@ -402,6 +402,25 @@ static void fsck_dir(int i, char *path)\n \n static int default_refs;\n \n+static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1, char *datail, void *cb_data)\n+{\n+\tstruct object *obj;\n+\n+\tif (!is_null_sha1(osha1)) {\n+\t\tobj = lookup_object(osha1);\n+\t\tif (obj) {\n+\t\t\tobj->used = 1;\n+\t\t\tmark_reachable(obj, REACHABLE);\n+\t\t}\n+\t}\n+\tobj = lookup_object(nsha1);\n+\tif (obj) {\n+\t\tobj->used = 1;\n+\t\tmark_reachable(obj, REACHABLE);\n+\t}\n+\treturn 0;\n+}\n+\n static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n {\n \tstruct object *obj;\n@@ -419,6 +438,9 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f\n \tdefault_refs++;\n \tobj->used = 1;\n \tmark_reachable(obj, REACHABLE);\n+\n+\tfor_each_reflog_ent(refname, fsck_handle_reflog_ent, NULL);\n+\n \treturn 0;\n }\n \n-- \n1.4.4.2.gc30f\n\n"},{"id":"294229","messageId":"20061218140813.GA32446@spearce.org","threadId":"43093","inReplyTo":"7vr6uxzgjb.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] Protect commits recorded in reflog from pruning.","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-12-18T14:08:13Z","receivedAt":"2006-12-18T14:08:13Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> This teaches fsck-objects and prune to protect objects referred\n> to by reflog entries.\n\nNice!\n\nBut its not enough.\n\n  $ git-repack -a -d\n  $ git reset --hard HEAD^\n  $ git-repack -a -d\n  $ git reset --hard HEAD@{1}\n\nthat last reset would fail now, wouldn't it?  pack-objects needs\nto know it should be pulling in the objects stuff reachable from\nreflogs too.\n\n-- \n"},{"id":"298458","messageId":"7vy7p4u1au.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"20061218140813.GA32446@spearce.org","subject":"Re: [PATCH 2/2] Protect commits recorded in reflog from pruning.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-19T01:22:49Z","receivedAt":"2006-12-19T01:22:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Shawn Pearce <spearce@spearce.org> writes:\n\n> Junio C Hamano <junkio@cox.net> wrote:\n>> This teaches fsck-objects and prune to protect objects referred\n>> to by reflog entries.\n>\n> Nice!\n>\n> But its not enough.\n>\n>   $ git-repack -a -d\n>   $ git reset --hard HEAD^\n>   $ git-repack -a -d\n>   $ git reset --hard HEAD@{1}\n>\n> that last reset would fail now, wouldn't it?  pack-objects needs\n> to know it should be pulling in the objects stuff reachable from\n> reflogs too.\n\nSure.\n\n-- >8 --\nTeach git-repack to preserve objects referred to by reflog entries.\n\nThis adds a new option --reflog to pack-objects and revision\nmachinery; do not bother documenting it for now, since this is\nonly useful for local repacking.\n\nWhen the option is passed, objects reachable from reflog entries\nare marked as interesting while computing the set of objects to\npack.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n builtin-pack-objects.c |    3 +-\n git-repack.sh          |    2 +-\n revision.c             |   56 ++++++++++++++++++++++++++++++++++++++++++------\n 3 files changed, 52 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin-pack-objects.c b/builtin-pack-objects.c\nindex a2dc7d1..928684b 100644\n--- a/builtin-pack-objects.c\n+++ b/builtin-pack-objects.c\n@@ -19,7 +19,7 @@ static const char pack_usage[] = \"\\\n git-pack-objects [{ -q | --progress | --all-progress }] \\n\\\n \t[--local] [--incremental] [--window=N] [--depth=N] \\n\\\n \t[--no-reuse-delta] [--delta-base-offset] [--non-empty] \\n\\\n-\t[--revs [--unpacked | --all]*] [--stdout | base-name] \\n\\\n+\t[--revs [--unpacked | --all]*] [--reflog] [--stdout | base-name] \\n\\\n \t[<ref-list | <object-list]\";\n \n struct object_entry {\n@@ -1577,6 +1577,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tif (!strcmp(\"--unpacked\", arg) ||\n \t\t    !strncmp(\"--unpacked=\", arg, 11) ||\n+\t\t    !strcmp(\"--reflog\", arg) ||\n \t\t    !strcmp(\"--all\", arg)) {\n \t\t\tuse_internal_rev_list = 1;\n \t\t\tif (ARRAY_SIZE(rp_av) - 1 <= rp_ac)\ndiff --git a/git-repack.sh b/git-repack.sh\nindex 067898f..375434b 100755\n--- a/git-repack.sh\n+++ b/git-repack.sh\n@@ -62,7 +62,7 @@ case \",$all_into_one,\" in\n esac\n \n args=\"$args $local $quiet $no_reuse_delta$extra\"\n-name=$(git-pack-objects --non-empty --all $args </dev/null \"$PACKTMP\") ||\n+name=$(git-pack-objects --non-empty --all --reflog $args </dev/null \"$PACKTMP\") ||\n \texit 1\n if [ -z \"$name\" ]; then\n \techo Nothing new to pack.\ndiff --git a/revision.c b/revision.c\nindex 993bb66..cbf1045 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -462,21 +462,59 @@ static void limit_list(struct rev_info *revs)\n \trevs->commits = newlist;\n }\n \n-static int all_flags;\n-static struct rev_info *all_revs;\n+struct all_refs_cb {\n+\tint all_flags;\n+\tstruct rev_info *all_revs;\n+\tconst char *name_for_errormsg;\n+};\n \n static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)\n {\n-\tstruct object *object = get_reference(all_revs, path, sha1, all_flags);\n-\tadd_pending_object(all_revs, object, \"\");\n+\tstruct all_refs_cb *cb = cb_data;\n+\tstruct object *object = get_reference(cb->all_revs, path, sha1,\n+\t\t\t\t\t      cb->all_flags);\n+\tadd_pending_object(cb->all_revs, object, \"\");\n \treturn 0;\n }\n \n static void handle_all(struct rev_info *revs, unsigned flags)\n {\n-\tall_revs = revs;\n-\tall_flags = flags;\n-\tfor_each_ref(handle_one_ref, NULL);\n+\tstruct all_refs_cb cb;\n+\tcb.all_revs = revs;\n+\tcb.all_flags = flags;\n+\tfor_each_ref(handle_one_ref, &cb);\n+}\n+\n+static int handle_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1, char *detail, void *cb_data)\n+{\n+\tstruct all_refs_cb *cb = cb_data;\n+\tstruct object *object;\n+\n+\tif (!is_null_sha1(osha1)) {\n+\t\tobject = get_reference(cb->all_revs, cb->name_for_errormsg,\n+\t\t\t\t       osha1, cb->all_flags);\n+\t\tadd_pending_object(cb->all_revs, object, \"\");\n+\t}\n+\tobject = get_reference(cb->all_revs, cb->name_for_errormsg,\n+\t\t\t       nsha1, cb->all_flags);\n+\tadd_pending_object(cb->all_revs, object, \"\");\n+\treturn 0;\n+}\n+\n+static int handle_one_reflog(const char *path, const unsigned char *sha1, int flag, void *cb_data)\n+{\n+\tstruct all_refs_cb *cb = cb_data;\n+\tcb->name_for_errormsg = path;\n+\tfor_each_reflog_ent(path, handle_one_reflog_ent, cb_data);\n+\treturn 0;\n+}\n+\n+static void handle_reflog(struct rev_info *revs, unsigned flags)\n+{\n+\tstruct all_refs_cb cb;\n+\tcb.all_revs = revs;\n+\tcb.all_flags = flags;\n+\tfor_each_ref(handle_one_reflog, &cb);\n }\n \n static int add_parents_only(struct rev_info *revs, const char *arg, int flags)\n@@ -803,6 +841,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch\n \t\t\t\thandle_all(revs, flags);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--reflog\")) {\n+\t\t\t\thandle_reflog(revs, flags);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--not\")) {\n \t\t\t\tflags ^= UNINTERESTING;\n \t\t\t\tcontinue;\n"},{"id":"293835","messageId":"7vbqm0thr5.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"7vy7p4u1au.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 1/2] Move in_merge_bases() to commit.c","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-19T08:25:02Z","receivedAt":"2006-12-19T08:25:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This reasonably useful function was hidden inside builtin-branch.c\n---\n\n * This is used by the next one, which is why this is part of\n   the 'reflog entry and pruning' series.\n\n builtin-branch.c |   21 +--------------------\n commit.c         |   17 +++++++++++++++++\n commit.h         |    1 +\n 3 files changed, 19 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex 560309c..12eebc0 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -70,25 +70,6 @@ const char *branch_get_color(enum color_branch ix)\n \treturn \"\";\n }\n \n-static int in_merge_bases(const unsigned char *sha1,\n-\t\t\t  struct commit *rev1,\n-\t\t\t  struct commit *rev2)\n-{\n-\tstruct commit_list *bases, *b;\n-\tint ret = 0;\n-\n-\tbases = get_merge_bases(rev1, rev2, 1);\n-\tfor (b = bases; b; b = b->next) {\n-\t\tif (!hashcmp(sha1, b->item->object.sha1)) {\n-\t\t\tret = 1;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\tfree_commit_list(bases);\n-\treturn ret;\n-}\n-\n static void delete_branches(int argc, const char **argv, int force)\n {\n \tstruct commit *rev, *head_rev = head_rev;\n@@ -119,7 +100,7 @@ static void delete_branches(int argc, const char **argv, int force)\n \t\t */\n \n \t\tif (!force &&\n-\t\t    !in_merge_bases(sha1, rev, head_rev)) {\n+\t\t    !in_merge_bases(rev, head_rev)) {\n \t\t\tfprintf(stderr,\n \t\t\t\t\"The branch '%s' is not a strict subset of your current HEAD.\\n\"\n \t\t\t\t\"If you are sure you want to delete it, run 'git branch -D %s'.\\n\",\ndiff --git a/commit.c b/commit.c\nindex a6d543e..4bddcbe 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -1009,3 +1009,20 @@ struct commit_list *get_merge_bases(struct commit *one,\n \tfree(rslt);\n \treturn result;\n }\n+\n+int in_merge_bases(struct commit *rev1, struct commit *rev2)\n+{\n+\tstruct commit_list *bases, *b;\n+\tint ret = 0;\n+\n+\tbases = get_merge_bases(rev1, rev2, 1);\n+\tfor (b = bases; b; b = b->next) {\n+\t\tif (!hashcmp(rev1->object.sha1, b->item->object.sha1)) {\n+\t\t\tret = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tfree_commit_list(bases);\n+\treturn ret;\n+}\ndiff --git a/commit.h b/commit.h\nindex fc13de9..10eea9f 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -107,4 +107,5 @@ int read_graft_file(const char *graft_file);\n \n extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);\n \n+int in_merge_bases(struct commit *rev1, struct commit *rev2);\n #endif /* COMMIT_H */\n-- \n1.4.4.2.g688739\n\n"},{"id":"298478","messageId":"7v64c8thr4.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"7vy7p4u1au.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 2/2] git reflog expire","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-19T08:25:03Z","receivedAt":"2006-12-19T08:25:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This prepares a place to collect reflog management subcommands,\nand implements \"expire\" action.\n\n\t$ git reflog expire --dry-run \\\n\t\t--expire=4.weeks \\\n\t\t--expire-lost=1.week \\\n\t\trefs/heads/master\n\nThe expiration uses two timestamps: --expire and --expire-lost.\nEntries older than expire time (defaults to 90 days), and\nentries older than expire-lost time (defaults to 30 days) and\ntalk about a commit that has been rewound and made unreachable\nfrom the current tip of the ref are removed from the reflog.\n\nThe parameter handling is still rough, but I think the\ncore logic for expiration is already sound.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n Makefile         |    1 +\n builtin-reflog.c |  175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n builtin.h        |    1 +\n git.c            |    1 +\n 4 files changed, 178 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8919dab..17dabde 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -292,6 +292,7 @@ BUILTIN_OBJS = \\\n \tbuiltin-prune-packed.o \\\n \tbuiltin-push.o \\\n \tbuiltin-read-tree.o \\\n+\tbuiltin-reflog.o \\\n \tbuiltin-repo-config.o \\\n \tbuiltin-rev-list.o \\\n \tbuiltin-rev-parse.o \\\ndiff --git a/builtin-reflog.c b/builtin-reflog.c\nnew file mode 100644\nindex 0000000..aef2fc2\n--- /dev/null\n+++ b/builtin-reflog.c\n@@ -0,0 +1,175 @@\n+#include \"cache.h\"\n+#include \"builtin.h\"\n+#include \"commit.h\"\n+#include \"refs.h\"\n+#include \"dir.h\"\n+#include <time.h>\n+\n+struct expire_reflog_cb {\n+\tFILE *newlog;\n+\tconst char *ref;\n+\tstruct commit *ref_commit;\n+\tunsigned long expire_total;\n+\tunsigned long expire_lost;\n+};\n+\n+static int keep_entry(struct commit **it, unsigned char *sha1)\n+{\n+\t*it = NULL;\n+\tif (is_null_sha1(sha1))\n+\t\treturn 1;\n+\t*it = lookup_commit_reference_gently(sha1, 1);\n+\treturn (*it != NULL);\n+}\n+\n+static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n+\t\t\t     char *data, void *cb_data)\n+{\n+\tstruct expire_reflog_cb *cb = cb_data;\n+\tunsigned long timestamp;\n+\tchar *cp, *ep;\n+\tstruct commit *old, *new;\n+\n+\tcp = strchr(data, '>');\n+\tif (!cp || *++cp != ' ')\n+\t\tgoto prune;\n+\ttimestamp = strtoul(cp, &ep, 10);\n+\tif (*ep != ' ')\n+\t\tgoto prune;\n+\tif (timestamp < cb->expire_total)\n+\t\tgoto prune;\n+\n+\tif (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1))\n+\t\tgoto prune;\n+\n+\tif ((timestamp < cb->expire_lost) &&\n+\t    ((old && !in_merge_bases(old, cb->ref_commit)) ||\n+\t     (new && !in_merge_bases(new, cb->ref_commit))))\n+\t\tgoto prune;\n+\n+\tif (cb->newlog)\n+\t\tfprintf(cb->newlog, \"%s %s %s\",\n+\t\t\tsha1_to_hex(osha1), sha1_to_hex(nsha1), data);\n+\treturn 0;\n+ prune:\n+\tif (!cb->newlog)\n+\t\tfprintf(stderr, \"would prune %s\", data);\n+\treturn 0;\n+}\n+\n+struct cmd_reflog_expire_cb {\n+\tint dry_run;\n+\tunsigned long expire_total;\n+\tunsigned long expire_lost;\n+};\n+\n+static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)\n+{\n+\tstruct cmd_reflog_expire_cb *cmd = cb_data;\n+\tstruct expire_reflog_cb cb;\n+\tstruct ref_lock *lock;\n+\tchar *newlog_path = NULL;\n+\tint status = 0;\n+\n+\tif (strncmp(ref, \"refs/\", 5))\n+\t\treturn error(\"not a ref '%s'\", ref);\n+\n+\tmemset(&cb, 0, sizeof(cb));\n+\t/* we take the lock for the ref itself to prevent it from\n+\t * getting updated.\n+\t */\n+\tlock = lock_ref_sha1(ref + 5, sha1);\n+\tif (!lock)\n+\t\treturn error(\"cannot lock ref '%s'\", ref);\n+\tif (!file_exists(lock->log_file))\n+\t\tgoto finish;\n+\tif (!cmd->dry_run) {\n+\t\tnewlog_path = xstrdup(git_path(\"logs/%s.lock\", ref));\n+\t\tcb.newlog = fopen(newlog_path, \"w\");\n+\t}\n+\n+\tcb.ref_commit = lookup_commit_reference_gently(sha1, 1);\n+\tif (!cb.ref_commit) {\n+\t\tstatus = error(\"ref '%s' does not point at a commit\", ref);\n+\t\tgoto finish;\n+\t}\n+\tcb.ref = ref;\n+\tcb.expire_total = cmd->expire_total;\n+\tcb.expire_lost = cmd->expire_lost;\n+\tfor_each_reflog_ent(ref, expire_reflog_ent, &cb);\n+ finish:\n+\tif (cb.newlog) {\n+\t\tif (fclose(cb.newlog))\n+\t\t\tstatus |= error(\"%s: %s\", strerror(errno),\n+\t\t\t\t\tnewlog_path);\n+\t\tif (rename(newlog_path, lock->log_file)) {\n+\t\t\tstatus |= error(\"cannot rename %s to %s\",\n+\t\t\t\t\tnewlog_path, lock->log_file);\n+\t\t\tunlink(newlog_path);\n+\t\t}\n+\t}\n+\tfree(newlog_path);\n+\tunlock_ref(lock);\n+\treturn status;\n+}\n+\n+static const char reflog_expire_usage[] =\n+\"git-reflog expire [--dry-run] [--expire=<time>] [--expire-lost=<time>] [--all] <refs>...\";\n+\n+static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct cmd_reflog_expire_cb cb;\n+\tunsigned long now = time(NULL);\n+\tint i, status, do_all;\n+\n+\tsave_commit_buffer = 0;\n+\tdo_all = status = 0;\n+\tmemset(&cb, 0, sizeof(cb));\n+\tcb.expire_total = now - 90 * 24 * 3600;\n+\tcb.expire_lost = now - 30 * 24 * 3600;\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tconst char *arg = argv[i];\n+\t\tif (!strcmp(arg, \"--dry-run\") || !strcmp(arg, \"-n\"))\n+\t\t\tcb.dry_run = 1;\n+\t\telse if (!strncmp(arg, \"--expire=\", 9))\n+\t\t\tcb.expire_total = approxidate(arg + 9);\n+\t\telse if (!strncmp(arg, \"--expire-lost=\", 14))\n+\t\t\tcb.expire_lost = approxidate(arg + 14);\n+\t\telse if (!strcmp(arg, \"--all\"))\n+\t\t\tdo_all = 1;\n+\t\telse if (!strcmp(arg, \"--\")) {\n+\t\t\ti++;\n+\t\t\tbreak;\n+\t\t}\n+\t\telse if (arg[0] == '-')\n+\t\t\tusage(reflog_expire_usage);\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\tif (do_all)\n+\t\tstatus |= for_each_ref(expire_reflog, &cb);\n+\twhile (i < argc) {\n+\t\tconst char *ref = argv[i++];\n+\t\tunsigned char sha1[20];\n+\t\tif (!resolve_ref(ref, sha1, 1, NULL)) {\n+\t\t\tstatus |= error(\"%s points nowhere!\", ref);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tstatus |= expire_reflog(ref, sha1, 0, &cb);\n+\t}\n+\treturn status;\n+}\n+\n+static const char reflog_usage[] =\n+\"git-reflog (expire | ...)\";\n+\n+int cmd_reflog(int argc, const char **argv, const char *prefix)\n+{\n+\tif (argc < 2)\n+\t\tusage(reflog_usage);\n+\telse if (!strcmp(argv[1], \"expire\"))\n+\t\treturn cmd_reflog_expire(argc - 1, argv + 1, prefix);\n+\telse\n+\t\tusage(reflog_usage);\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 08519e7..fdc0907 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -51,6 +51,7 @@ extern int cmd_prune(int argc, const char **argv, const char *prefix);\n extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_reflog(int argc, const char **argv, const char *prefix);\n extern int cmd_repo_config(int argc, const char **argv, const char *prefix);\n extern int cmd_rev_list(int argc, const char **argv, const char *prefix);\n extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);\ndiff --git a/git.c b/git.c\nindex 016ee8a..ae4c99f 100644\n--- a/git.c\n+++ b/git.c\n@@ -256,6 +256,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)\n \t\t{ \"prune-packed\", cmd_prune_packed, RUN_SETUP },\n \t\t{ \"push\", cmd_push, RUN_SETUP },\n \t\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n+\t\t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t\t{ \"repo-config\", cmd_repo_config },\n \t\t{ \"rev-list\", cmd_rev_list, RUN_SETUP },\n \t\t{ \"rev-parse\", cmd_rev_parse, RUN_SETUP },\n-- \n1.4.4.2.g688739\n\n"},{"id":"295227","messageId":"20061219090851.GH2511@spearce.org","threadId":"43093","inReplyTo":"7v64c8thr4.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-12-19T09:08:51Z","receivedAt":"2006-12-19T09:08:51Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> This prepares a place to collect reflog management subcommands,\n> and implements \"expire\" action.\n> \n> \t$ git reflog expire --dry-run \\\n> \t\t--expire=4.weeks \\\n> \t\t--expire-lost=1.week \\\n> \t\trefs/heads/master\n> \n> The expiration uses two timestamps: --expire and --expire-lost.\n> Entries older than expire time (defaults to 90 days), and\n> entries older than expire-lost time (defaults to 30 days) and\n> talk about a commit that has been rewound and made unreachable\n> from the current tip of the ref are removed from the reflog.\n> \n> The parameter handling is still rough, but I think the\n> core logic for expiration is already sound.\n\nI agree, this looked pretty good to me.\n\nI disagree with the option name '--expire-lost'.  The way I\ninitially read that was:\n\n    --expire-lost: ok, if the object was already pruned out of\n    the ODB and the reflog entry is older than 1 week, remove it;\n    otherwise keep it in case the user could manually recover the\n    object from another ODB.\n\nOf course that's not what the code does, because if either the\nold or the new object is no longer in the ODB you are pruning away\nthe log entry.  I cannot however come up with a better name than\n--expire-lost.  :-(\n\nPerhaps --expire-lost should default to just be 1/3 of the time of\n--expire, whatever --expire is: 90 day default or command line value?\n\n\nI'm thinking that we may want the 'expire' subcommand to simply be\nimplied by '--expire' instead.  Basically my rational here is I want\nto be able to do 'git reflog HEAD' to view the reflog associated with\nmy current branch, effectively seeing the Git operational history\nof this branch.  Or 'git reflog a b' to see the operational history\nof two branches with their reflogs interleaved based on entry time.\n\nNeeding a subcommand like 'git reflog show HEAD' is just a lot\nof typing[*1*].\n\nI would also say maybe we want to make --dry-run the default, with\na final message which tells the user that if they really want to\nmake it possible to throw away the commits printed above then\nrestart the expire operation, e.g.:\n\n  $ git reflog --expire=4.weeks --expire-lost=1.week master\n  would expire ...\n  would expire ...\n  would expire ...\n\n  Restart with '--prune' to expire the above log entries and commits.\n  $ git reflog --expire=4.weeks --expire-lost=1.week master --prune\n\n?\n\n\nI'd like to take a stab at the log display code for the reflog\ncommand, but I'd also really like to port forward (aka rewrite)\nthat mmap window code I keep saying I'll work on, but never quite\nseem to do...\n\n\n*1* Yes, I know, I'll do bash completion for this command too.  ;-)\n\n-- \n"},{"id":"297072","messageId":"7vhcvsry2c.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"20061219090851.GH2511@spearce.org","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-19T10:15:39Z","receivedAt":"2006-12-19T10:15:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Shawn Pearce <spearce@spearce.org> writes:\n\n> Of course that's not what the code does, because if either the\n> old or the new object is no longer in the ODB you are pruning away\n> the log entry.  I cannot however come up with a better name than\n> --expire-lost.  :-(\n\nHow about --expire-unreachable?\n\n> I'm thinking that we may want the 'expire' subcommand to simply be\n> implied by '--expire' instead.\n\nAfter coding this, my conclusion is the same as yours, but\nreasoning behind it is slightly different.\n\nTo have 'expire' action as a subcommand to 'git-reflog' is from\nimplementor's point of view, and is a horrible organization from\nthe UI standpoint.  To the end users, it may be easier to have a\nsingle 'git-gc' command that runs these commands with reasonable\nset of defaults:\n\n\t- rerere gc\n        - reflog expire --all\n\t- (possibly) repack -a -d\n        - prune\n\nIf we go that route, it probably is not even necessary to\nadvertise that 'expire' is a subcommand of reflog.  The users\nwould not run it from the command line; it is an implementation\ndetail of 'git-gc' command.\n\n> Needing a subcommand like 'git reflog show HEAD' is just a lot\n> of typing[*1*].\n\nI am very interested in seeing how 'git reflog show HEAD' would\nshow the reflog entries.  I've tried showing it just like log\nfamily shows (it is reasonably easy; you build the list of revs\nout of reflog entries and feed them to 'git-show' machinery),\nand while it works, it is unusable for the purpose of seeing\nwhich ones are the lost ones (amended commits and rebased branch\nremnants).\n\nThe best I came up with is still my \"show-branch --reflog\" so\nfar.  You really need to show not just the commit title but how\nthey topologically relate to the commits on the surviving\nbranch, and I think having something graphical or semi-graphical\nis a must.\n\n> I would also say maybe we want to make --dry-run the default, with\n> a final message which tells the user that if they really want to\n> make it possible to throw away the commits printed above then\n> restart the expire operation.\n\nI am moderately negative on that.  Nobody does it like that;\nprune, branch -d, tag -d,...\n\n> I'd like to take a stab at the log display code for the reflog\n> command, but I'd also really like to port forward (aka rewrite)\n> that mmap window code I keep saying I'll work on, but never quite\n> seem to do...\n\nAfter today's pread() thing, I was also wondering about that too\n;-).\n"},{"id":"296355","messageId":"20061219102741.GA21324@spearce.org","threadId":"43093","inReplyTo":"7vhcvsry2c.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-12-19T10:27:42Z","receivedAt":"2006-12-19T10:27:42Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Shawn Pearce <spearce@spearce.org> writes:\n> > I'd like to take a stab at the log display code for the reflog\n> > command, but I'd also really like to port forward (aka rewrite)\n> > that mmap window code I keep saying I'll work on, but never quite\n> > seem to do...\n> \n> After today's pread() thing, I was also wondering about that too\n> ;-).\n\nI'm working on it now.  I have rather long days on Monday and\nTuesday which keep me otherwise occupied and away from Git work.\nHopefully I'll have something sometime on Wednesday, which so far\nI have all day free for hacking.\n\nSmaller mmap units may help on some larger projects. For example\n'git whatchanged' shouldn't need to setup page table entries for\nthe entire pack file when only the front and middle are needed to\nobtain the data for the most recent 25 commits, before the user\nkills the pager.\n\nBut that's just me pulling words out of the air.  I'm tired too,\ntime to catch a few hours of sleep.  Probably by the time I get back\nto my email our local kernel hackers will tell me how wrong I am.\n\n-- \n"},{"id":"297139","messageId":"20061219104032.GB21324@spearce.org","threadId":"43093","inReplyTo":"7vhcvsry2c.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-12-19T10:40:32Z","receivedAt":"2006-12-19T10:40:32Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Shawn Pearce <spearce@spearce.org> writes:\n> \n> > Of course that's not what the code does, because if either the\n> > old or the new object is no longer in the ODB you are pruning away\n> > the log entry.  I cannot however come up with a better name than\n> > --expire-lost.  :-(\n> \n> How about --expire-unreachable?\n\nThat actually does make more sense.  Those commits are what we would\ntraditionally have called unreachable commits, or dangling commits.\nHmm.  Flip a coin.  I'm probably as bad at UI as you are.  :-)\n \n> To have 'expire' action as a subcommand to 'git-reflog' is from\n> implementor's point of view, and is a horrible organization from\n> the UI standpoint.  To the end users, it may be easier to have a\n> single 'git-gc' command that runs these commands with reasonable\n> set of defaults:\n> \n>   - rerere gc\n>   - reflog expire --all\n>   - (possibly) repack -a -d\n>   - prune\n> \n> If we go that route, it probably is not even necessary to\n> advertise that 'expire' is a subcommand of reflog.  The users\n> would not run it from the command line; it is an implementation\n> detail of 'git-gc' command.\n\nYes!  I agree with you completely here.  I'd also include 'pack-refs\n--prune' to your list above, at least for refs/tags.  Those suckers\ncan eat up a lot of disk, slow down viualizers, and well, just\ndon't change.  Pack 'em!\n\n> > Needing a subcommand like 'git reflog show HEAD' is just a lot\n> > of typing[*1*].\n> \n> I am very interested in seeing how 'git reflog show HEAD' would\n> show the reflog entries.  I've tried showing it just like log\n> family shows (it is reasonably easy; you build the list of revs\n> out of reflog entries and feed them to 'git-show' machinery),\n> and while it works, it is unusable for the purpose of seeing\n> which ones are the lost ones (amended commits and rebased branch\n> remnants).\n\nAt this point I'm going to wind up getting less than 4 hours of\nsleep tonight (I'll be lucky if I get 3).  So I'm just going to skip\ntrying to draft out what I might want this to look like right now.\nI'll try to sketch out a dump by hand from a couple of my own reflogs\nand post 'em later tonight.  Ugh.  Tonight.  Its Tuesday already.\nMy body still thinks its Monday.\n\n> The best I came up with is still my \"show-branch --reflog\" so\n> far.  You really need to show not just the commit title but how\n> they topologically relate to the commits on the surviving\n> branch, and I think having something graphical or semi-graphical\n> is a must.\n\nProbably right.  But I can't make heads or tails out of that\noutput for just one topic branch whose reflog consists of only\nthe following:\n\n  $ cut -f2 .git/logs/refs/heads/sp/mapwin \n  checkout: Created from origin^0\n  am: Create read_or_die utility routine.\n  reset --hard 106d710b\n  am: Create read_or_die utility routine.\n  reset --hard \n  rebase: Create read_or_die utility routine.\n\n`show-branch --reflog --topics sp/mapwin` prints much shorter output\nand almost says something useful, but not really.\n\n-- \n"},{"id":"298461","messageId":"7vmz5kqh2h.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"20061219104032.GB21324@spearce.org","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-19T11:08:06Z","receivedAt":"2006-12-19T11:08:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Shawn Pearce <spearce@spearce.org> writes:\n\n>> The best I came up with is still my \"show-branch --reflog\" so\n>> far.  You really need to show not just the commit title but how\n>> they topologically relate to the commits on the surviving\n>> branch, and I think having something graphical or semi-graphical\n>> is a must.\n>\n> Probably right.  But I can't make heads or tails out of that\n> output for just one topic branch...\n\nHere is what my private 'pu' look like:\n\n! [pu@{0}] Merge branch 'jc/fsck-reflog' into pu\n ! [pu@{1}] Merge branch 'jc/pickaxe' into pu\n  ! [pu@{2}] Merge branches 'jn/web', 'jc/explain', 'jc/web' and\n   ! [pu@{3}] Merge branch 'jc/leftright' into next\n    ! [pu@{4}] Merge branch 'jc/fsck-reflog' into pu\n     ! [pu@{5}] Merge branch 'jc/pickaxe' into pu\n      ! [pu@{6}] Merge branches 'jc/fsck-reflog', 'jc/clone', 'j\n       ! [pu@{7}] Merge branch 'jc/blame' into next\n--------\n-        [pu@{0}] Merge branch 'jc/fsck-reflog' into pu\n+        [pu@{0}^2] git reflog expire\n+        [pu@{0}^2^] Move in_merge_bases() to commit.c\n+        [pu@{0}^2~2] reflog: fix warning message.\n--       [pu@{1}] Merge branch 'jc/pickaxe' into pu\n---      [pu@{2}] Merge branches 'jn/web', 'jc/explain', 'jc/web\n----     [pu@{3}] Merge branch 'jc/leftright' into next\n++++     [pu@{3}^2] Revert \"Make left-right automatic.\"\n      ...\n++++     [pu@{3}~2^2~3^2^] Revert \"fix testsuite: make sure they\n    -    [pu@{4}] Merge branch 'jc/fsck-reflog' into pu\n+   +    [pu@{0}^2~3] Teach git-repack to preserve objects refer\n    --   [pu@{5}] Merge branch 'jc/pickaxe' into pu\n    ---  [pu@{6}] Merge branches 'jc/fsck-reflog', 'jc/clone', '\n+++ +++  [pu@{2}^5] para-walk: walk n trees, index and working t\n      ...\n+   +++  [pu@{0}^2~5] add for_each_reflog_ent() iterator\n-------- [pu@{7}] Merge branch 'jc/blame' into next\n\nWhat matters most is the leftmost column.  Most of the time when\nyou are looking at reflog, you are looking for what's rewound\nand lost.  Stretches of lines with symbols (e.g. pu@{3}^2 to\npu@{3}~2^2~3^2^, and pu@{0}^2 to pu@{0}^2~2) are not so\ninteresting [*1*].\n\nThe entry whose column have whitespace there are the lost ones\n(rewound or amended).  pu@{4} used to be the tip of 'pu', but\nafter I whipped 'next' into a reasonable shape, I did \"git\nbranch -f pu next\" to bundle the tips of topics that are not\nready for 'next' into it (and all the rest pu@{3}, pu@{2},\npu@{1} and pu@{0} are sequence of merges into 'pu').\n\n\n[Footnote]\n\n*1* We might want to add an output filter that lets the command\nomit such lines with the same set of reachable tips when showing\nthe reflog entries.\n\n\n"},{"id":"294731","messageId":"Pine.LNX.4.64.0612191524180.6766@woody.osdl.org","threadId":"43093","inReplyTo":"20061219102741.GA21324@spearce.org","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-12-19T23:29:54Z","receivedAt":"2006-12-19T23:29:54Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 19 Dec 2006, Shawn Pearce wrote:\n> \n> Smaller mmap units may help on some larger projects. For example\n> 'git whatchanged' shouldn't need to setup page table entries for\n> the entire pack file when only the front and middle are needed to\n> obtain the data for the most recent 25 commits, before the user\n> kills the pager.\n\nAt least on Linux, we do NOT set up page table entries unnecessarily. The \ncost of a mmap() is largely independent of the size of the mmap, and the \ncosts will be on page fault time (which is obviously O(n) in number of \npages you need).\n\nThe same is _largely_ true of munmap() too. There's a small cost to large \nmmaps that were only sparsely accessed being unmapped (we have to look at \nthe page tables closely, even if they end up being empty), but quite \nfrankly, it's not going to be all that noticeable.\n\nSo mmap() costs end up largely being one (fairly small) fixed cost, plus a \n(fairly small) cost for each page beign demand-mapped in. \n\nOf course, Linux is just _better_ than the competition, so things that \ndon't help Linux might still help other systems. Linux does both page \nfaults and the mmap system call well, other systems will generally be an \norder of magnitude worse in both. And as we've seen, it can be more.\n\n(Things that are really fast on Linux: VM manipulation, and filename path \nlookup. Those are both ops that Linux _really_ shines on. It may not sound \nlike much, but when you do millions of them, it's the difference between \nseconds and hours).\n\n"},{"id":"294522","messageId":"7vvek7o15v.fsf@assigned-by-dhcp.cox.net","threadId":"43093","inReplyTo":"Pine.LNX.4.64.0612191524180.6766@woody.osdl.org","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-20T00:34:36Z","receivedAt":"2006-12-20T00:34:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> (Things that are really fast on Linux: VM manipulation, and filename path \n> lookup. Those are both ops that Linux _really_ shines on. It may not sound \n> like much, but when you do millions of them, it's the difference between \n> seconds and hours).\n>\n> \t\tLinus\n\n... and both have been _heavily_ used in/assumed to be fast by\ngit implementation.\n\nLinus, your userland programming skills are _spoiled_ by Linux\n;-).\n"},{"id":"295694","messageId":"Pine.LNX.4.64.0612191644290.6766@woody.osdl.org","threadId":"43093","inReplyTo":"7vvek7o15v.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] git reflog expire","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-12-20T00:58:25Z","receivedAt":"2006-12-20T00:58:25Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 19 Dec 2006, Junio C Hamano wrote:\n>\n> Linus, your userland programming skills are _spoiled_ by Linux\n> ;-).\n\nMaybe. On the other hand, there's definitely a bit of just my programming \nstyle involved: the things I care most about are the kinds of things I'd \npersonally use in programming. So I claim that one of the reasons Linux \ndoes pathname lookup well is simply that every single program I've ever \ndone that cared about performance of either open() or stat() or both. And \nyes, I tend to have a tendency to mmap() rather than read. So I optimize \nstuff I do.\n\nThat said, Linux does a lot of _other_ things well too, so it's not like \nit's just the things I do.\n\n"}]}