{"thread":{"id":"2141","subject":"Wanted - a file browser interface to git","startedAt":"2005-10-19T00:58:30Z","lastAt":"2005-10-19T04:01:00Z","messageCount":6,"participants":["John Ellson","Linus Torvalds"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"10242","messageId":"dj45np$e88$1@sea.gmane.org","threadId":"2141","inReplyTo":null,"subject":"Wanted - a file browser interface to git","fromName":"John Ellson","fromEmail":"ellson@research.att.com","sentAt":"2005-10-19T00:58:30Z","receivedAt":"2005-10-19T00:58:30Z","isPatch":false,"sender":{"key":"ellson@research.att.com","avatar":null},"body":"I know that Linus thinks that files are less important than commits, but we are \nfinding a real need to be able to browse though old versions of files and we \nhave not yet found an efficient way to do it with git.\n\nAn example is:  \"I know that file xxx contained algorithm yyy at some point in \nthe past and now I'd like to browse back through the history of xxx to find the \nexact details.\"\n\nI think what I'd like is a file browser on git that:\n\n- can navigate the directory tree, starting by default with the HEAD\ntree, but able to browse the state of the tree at any time in the history.\n\n- can select any file from the tree, and then view the state of that file at any \ntime in its history by stepping forward or back through commits that have \naffected that file.\n\t\n- can view the difference between any pair of states of the file, with \nannotations as to the source of the changes.\n\n- can search for a string across the complete history of a file.\n\n- can invoke the users choice of editor on the file.\n\n\nNeither gitk nor qgit provide tree browsing, so it can be hard to get at a\nspecific file.\n\nqgit has nice file browser that annotates all changes, but I think I'd prefer a \ntwo panel diff view.\n\nNeither qgit not gitk provide links to an editor so that a file can be worked on \nonce found.\n\n\nAm I out in left field here, or does anyone else feel the need for something \nlike this?\n\nJohn\n"},{"id":"10244","messageId":"Pine.LNX.4.64.0510181806250.3369@g5.osdl.org","threadId":"2141","inReplyTo":"dj45np$e88$1@sea.gmane.org","subject":"Re: Wanted - a file browser interface to git","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-19T01:07:53Z","receivedAt":"2005-10-19T01:07:53Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 18 Oct 2005, John Ellson wrote:\n> \n> An example is:  \"I know that file xxx contained algorithm yyy at some point in\n> the past and now I'd like to browse back through the history of xxx to find\n> the exact details.\"\n\nYou are aware of \"git whatchanged -p xxx\", right?\n\nYeah, it's not graphical, and I agree that it might be very cool to have a \ngraphical version of it. But I thought I'd mention it even so. A \nsurprising number of people seem to have never realized, and at least for \nme personally, it's one of the most common things I do.\n\n\t\tLinus\n"},{"id":"10248","messageId":"4355A00B.4000806@research.att.com","threadId":"2141","inReplyTo":"Pine.LNX.4.64.0510181806250.3369@g5.osdl.org","subject":"Re: Wanted - a file browser interface to git","fromName":"John Ellson","fromEmail":"ellson@research.att.com","sentAt":"2005-10-19T01:23:23Z","receivedAt":"2005-10-19T01:23:23Z","isPatch":false,"sender":{"key":"ellson@research.att.com","avatar":null},"body":"Linus Torvalds wrote:\n> On Tue, 18 Oct 2005, John Ellson wrote:\n>   \n>> An example is:  \"I know that file xxx contained algorithm yyy at some point in\n>> the past and now I'd like to browse back through the history of xxx to find\n>> the exact details.\"\n>>     \n>\n> You are aware of \"git whatchanged -p xxx\", right?\n>\n> Yeah, it's not graphical, and I agree that it might be very cool to have a \n> graphical version of it. But I thought I'd mention it even so. A \n> surprising number of people seem to have never realized, and at least for \n> me personally, it's one of the most common things I do.\n>\n> \t\tLinus\n>   \nLinus,\n\nI wasn't aware of it, no.  Looks very useful.  Thanks.\n\nI see that you can take the tree id from the diff-tree lines and\nthen produce the state of the file at that time with \"cg-admin-cat -r \n<id> xxx\"\nIs that how you would do it?\n\nAre there any plans for cogito to support it?\n\nJohn\n"},{"id":"10252","messageId":"Pine.LNX.4.64.0510181952350.3369@g5.osdl.org","threadId":"2141","inReplyTo":"4355A00B.4000806@research.att.com","subject":"Re: Wanted - a file browser interface to git","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-19T03:03:17Z","receivedAt":"2005-10-19T03:03:17Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 18 Oct 2005, John Ellson wrote:\n> Linus Torvalds wrote:\n> > \n> > You are aware of \"git whatchanged -p xxx\", right?\n> \n> I wasn't aware of it, no.  Looks very useful.  Thanks.\n> \n> I see that you can take the tree id from the diff-tree lines and\n> then produce the state of the file at that time with \"cg-admin-cat -r <id>\n> xxx\"\n> Is that how you would do it?\n\nWell, I'd do it with the git commands: once you see the diff, you should \nknow the SHA1's of the source and destination, and then you can just do\n\n\tgit-cat-file blob [sha1]\n\nto get the before (or after) state.\n\nThe way I'd get the SHA1 is either (now with the extended diff format) in \nthe short form from the diff itself (the \"index\" line), or by just \nseparately doing a\n\n\tgit-diff-tree -r [sha-of-commit]\n\nto see the \"raw\" diff format.\n\nAll the diff things can take a pathname limiter, the same way \n\"git-whatchanged\" does, so if you are only interested in one file, just \nname the file:\n\n\tgit-diff-tree -r [sha-of-commit] [filename]\n\nAnd just to make clear how powerful this is: \"filename\" doesn't have to be \na single file. It can be a set of files and/or directories, so if you want \nto track multiple things at the same time, just do multiple filenames.\n\nWhat I do a lot is to check what has changed in some particular subsystem, \nie somebody says that something broke in SCSI, and then I do\n\n\tgit-whatchanged -p drivers/scsi/ include/scsi/\n\nand it will show any changes to anything under either of those \ndirectories.\n\n\"git-whatchanged\" really is very powerful. The silly thing is that it \nreally boils down to just a single line script (well, with various \nargument handling etc it's actually five lines, but the \"core\" is really \njust a single pipeline of \"git-rev-list | git-diff-tree --stdin\".\n\n> Are there any plans for cogito to support it?\n\nWell, cogito could certainly just do a \"cg-whatchanged\", but it's really \nthe same thing. Since cogito depends on git anyway, cogito users could \njust use the git-whatchanged functionality.\n\nOr to make it more seamless, just do\n\n\talias cg-whatchanged=git-whatchanged\n\nor something like that ;^)\n\n\t\t\tLinus\n"},{"id":"10254","messageId":"4355BA43.5030509@research.att.com","threadId":"2141","inReplyTo":"Pine.LNX.4.64.0510181806250.3369@g5.osdl.org","subject":"[PATCH] cg-history FILE [NTH_PARENT] - was: Re: Wanted - a file browser interface to git","fromName":"John Ellson","fromEmail":"ellson@research.att.com","sentAt":"2005-10-19T03:15:15Z","receivedAt":"2005-10-19T03:15:15Z","isPatch":true,"sender":{"key":"ellson@research.att.com","avatar":null},"body":"Linus Torvalds wrote:\n> \n> On Tue, 18 Oct 2005, John Ellson wrote:\n>> An example is:  \"I know that file xxx contained algorithm yyy at some point in\n>> the past and now I'd like to browse back through the history of xxx to find\n>> the exact details.\"\n> \n> You are aware of \"git whatchanged -p xxx\", right?\n> \n> Yeah, it's not graphical, and I agree that it might be very cool to have a \n> graphical version of it. But I thought I'd mention it even so. A \n> surprising number of people seem to have never realized, and at least for \n> me personally, it's one of the most common things I do.\n> \n> \t\tLinus\n\n\nOK.  Here is a not-very-smart cogito command to display the history of a file, \nor the state of the nth parent of the file in its history.\n\nFeedback and or complete rewrites are requested ;-)\n\nJohn\n\n\nproduce the history of a file, or its state at its nth_parent\n\n---\ncommit 8478ad1164e37e9cca039a3f9552d2a98f7bead6\ntree 40b39d5f9af573a7815f073cada03c7903bfc6fa\nparent 5d74e4859afc81a4658133d5a83809ac814dbf34\nauthor John Ellson <ellson@ontap.ellson.com> Tue, 18 Oct 2005 23:13:44 -0400\ncommitter John Ellson <ellson@ontap.ellson.com> Tue, 18 Oct 2005 23:13:44 -0400\n\n  cg-history |   36 ++++++++++++++++++++++++++++++++++++\n  1 files changed, 36 insertions(+), 0 deletions(-)\n\ndiff --git a/cg-history b/cg-history\nnew file mode 100755\nindex 0000000..ba86f71\n--- /dev/null\n+++ b/cg-history\n@@ -0,0 +1,36 @@\n+#!/usr/bin/env bash\n+#\n+# Display the change history of a file.\n+# Copyright (c) John Ellson, 2005\n+#\n+# The change history of a file is displayed on stdout, or\n+# if an integer is provided for NTH_PARENT, then the complete\n+# state of the file at that step in its history is sent to stdout.\n+#\n+\n+USAGE=\"cg-history FILE [NTH_PARENT]\"\n+\n+. ${COGITO_LIB}cg-Xlib || exit 1\n+\n+[ \"$ARGS\" ] || usage\n+\n+if [ \"${ARGS[1]}\" = \"\" ]; then\n+       git-whatchanged -p \"${ARGS[0]}\"\n+else\n+       i=0\n+       git-whatchanged -p \"${ARGS[0]}\" |\n+       while read -r cmd sha rest\n+       do\n+               case \"$cmd\" in\n+               diff-tree)\n+                       i=`expr $i + 1`\n+                       if [ $i = ${ARGS[1]} ] ; then\n+                               cg-admin-cat -r \"$sha\" \"${ARGS[0]}\"\n+                               exit 0\n+                       fi\n+                       ;;\n+               *)\n+                       ;;\n+               esac\n+       done\n+fi\n"},{"id":"10255","messageId":"Pine.LNX.4.64.0510182029240.3369@g5.osdl.org","threadId":"2141","inReplyTo":"4355BA43.5030509@research.att.com","subject":"Re: [PATCH] cg-history FILE [NTH_PARENT]","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-19T04:01:00Z","receivedAt":"2005-10-19T04:01:00Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n[ Ok, time for some serious power-git usage ]\n\nOn Tue, 18 Oct 2005, John Ellson wrote:\n> \n> produce the history of a file, or its state at its nth_parent\n>\n> +       git-whatchanged -p \"${ARGS[0]}\" |\n\nActually, you're much better of _not_ using \"-p\" to generate a patch.\n\nIn fact, you don't even want the pretty format that \"git-whatchanged\" \ndoes, you really want the raw output.\n\nTry this instead:\n\n\tgit-rev-list HEAD | git-diff-tree --stdin -s -r \"$ARG\"\n\nwhich will give _just_ a list of the commits that change the file \"$ARG\".\n\nHere, the \"--stdin\" to git-diff-tree means that it should take its \nrevision input from stdin (ie obvously the list of commits generated by \ngit-rev-list), and the \"-s\" stands for \"silent\", ie git-diff-tree won't \nactually output the diff itself.\n\nAnd the \"-r\" means that it should check the trees \"recursively\", which is \nneeded since we want the diff-tree to traverse down the tree rather than \njust look at the top-level (\"-p\" to generate patches enables recursive by \ndefault since patches don't make sense on raw trees, but without the -p \nyou need to do it explicitly).\n\nAnd since we didn't ask for the header, the only thing you get is the list \nof commits that changed the file describled by the argument.\n\nSo now, you can just pick the n'th such commit, and do something like this\n\n\t#\n\t# Get the \"${ARGS[1]}\"th commit that changes  file \"${ARGS[0]}\"\n\t#\n\trev=$(git-rev-list HEAD |\n\t\tgit-diff-tree --stdin -s -r \"${ARGS[0]}\" |\n\t\thead -n \"${ARGS[1]}\" |\n\t\ttail -1)\n\n\t#\n\t# Pick up the file from that tree\n\t#\n\tfilerev=$(git-ls-tree -r \"$rev\" \"${ARGS[0]}\" |\n\t\tcut -f1 |\n\t\tcut -d' ' -f3)\n\n\t#\n\t# And show it\n\t#\n\tgit-cat-file blob $filerev\n\nand you're done (untested, but you should get the idea).\n\nNow, the interesting part about is that you can feed the output from \ngit-diff-tree _back_ to git-diff-tree, so you can do some really fancy \nfootwork like:\n\n\tgit-rev-list rev1..rev2 |\n\t\tgit-diff-tree --stdin -s -r \"$ARG\" |\n\t\tgit-diff-tree --stdin -M --pretty -p\n\nand what this will do is:\n\n - generate a list of all commits between rev1 and rev2\n\n - filter out just the commits that change the file \"$ARG\", and pass those \n   on.\n\n - for those commits, show the _whole_ diff, with rename detection and \n   with pretty-printed commit comment headers\n\nIn other words, you can basically look at all the full commits that \nchanged one file (or a set of files). Efficiently.\n\nThis is kind of like \"git-whatchanged\", but it shows the full context of \nwhat changed. Of course, the second git-diff-tree can be used to limit the \ncontext to something else, ie you could do a variation of the above, \nsomething like\n\n\tgit-rev-list v2.6.12.. |\n\t\tgit-diff-tree --stdin -s -r drivers/usb/ |\n\t\tgit-diff-tree --stdin -M --pretty -p drivers/ include/\n\nwhich will show any commit that changed the drivers/usb/ directory after \nv2.6.12, but then limit the output of those commits to the drivers/ and \ninclude/ subdirectories (so anything that was changed in that same commit \nin a filesystem would _not_ be shown, for example, but if there were \nchanges to drivers/scsi/ at the same time, they _would_ show).\n\nOr, if you want to go really wild, do something like this on the kernel \ngit tree:\n\n\tgit-rev-list v2.6.12.. |\n\t\tgit-diff-tree --stdin -s -r drivers/usb/ |\n\t\tgit-diff-tree --stdin -s -r drivers/scsi/ |\n\t\tgit-diff-tree --stdin -M --pretty -p drivers/scsi/ drivers/usb/ |\n\t\tless -S\n\nwhich says to print out only those commits that change something _both_ in \ndrivers/usb/ _and_ in drivers/scsi/ at the same time, and then show only \nthose parts of the changes. \n\nTry it out. It really does work, and is extremely powerful. It's even \npretty efficient (make sure your tree is packed first, though ;). I can do \nthe above in about three seconds for the current kernel history on my \nmachine. That's 3 _seconds_ to go through what right now is 8005 commits:\n\n\tgit-rev-list v2.6.12.. | wc -l\n\nand the reason is exactly that the filename-based parsing is very good at \nefficiently pruning out all the tree information that isn't needed.\n\nVery cool.\n\nHowever, the \"normal\" situation is just the standard \"git-whatchanged\", \nwhich is much easier to use than something more complex like the above.\n\nThe core git commands are really designed to be scriptable, but \"real \nlife\" seldom wants the complexity of quite that much flexibility.\n\n\t\tLinus\n"}]}