{"thread":{"id":"28708","subject":"[PATCH 0/3] stupid git tricks","startedAt":"2011-10-18T04:49:55Z","lastAt":"2011-11-01T18:14:52Z","messageCount":24,"participants":["Jeff King","Junio C Hamano","Jonathan Nieder","Matthieu Moy","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"177916","messageId":"20111018044955.GA8976@sigill.intra.peff.net","threadId":"28708","inReplyTo":null,"subject":"[PATCH 0/3] stupid git tricks","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-18T04:49:55Z","receivedAt":"2011-10-18T04:49:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Here are a few contrib tidbits that I find invaluable when working with\ngit. They're pretty simple ideas, but I've been using them all for\nat least a year[1], and they've made my life more pleasant and\nproductive. So I thought I'd share.\n\n  [1/3]: contrib: add diff highlight script\n  [2/3]: contrib: add git-jump script\n  [3/3]: completion: match ctags symbol names in grep patterns\n\n-Peff\n\n[1] Actually, they all needed significant cleanup for me not to be\n    embarrassed to share them, which I just did recently. Undoubtedly I\n    introduced scores of new bugs during the cleanup, so take my \"at\n    least a year\" with a grain of salt. The _concepts_ have been proven,\n    at least. :)\n"},{"id":"177917","messageId":"20111018045220.GA9008@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111018044955.GA8976@sigill.intra.peff.net","subject":"[PATCH 1/3] contrib: add diff highlight script","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-18T04:52:20Z","receivedAt":"2011-10-18T04:52:20Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This is a simple and stupid script for highlighting\ndiffering parts of lines in a unified diff. See the README\nfor a discussion of the limitations.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nI posted a similar script before, but not as a contrib patch. Many of\nthe comments were that this could be done more accurately inside git\nitself. Undoubtedly. But this is already written, and I have found it\nvery useful in practice. If somebody wants to come along with an\nimplementation inside git-diff, I'd be happy to compare output.\n\n contrib/diff-highlight/README         |   57 +++++++++++++++\n contrib/diff-highlight/diff-highlight |  124 +++++++++++++++++++++++++++++++++\n 2 files changed, 181 insertions(+), 0 deletions(-)\n create mode 100644 contrib/diff-highlight/README\n create mode 100755 contrib/diff-highlight/diff-highlight\n\ndiff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README\nnew file mode 100644\nindex 0000000..1b7b6df\n--- /dev/null\n+++ b/contrib/diff-highlight/README\n@@ -0,0 +1,57 @@\n+diff-highlight\n+==============\n+\n+Line oriented diffs are great for reviewing code, because for most\n+hunks, you want to see the old and the new segments of code next to each\n+other. Sometimes, though, when an old line and a new line are very\n+similar, it's hard to immediately see the difference.\n+\n+You can use \"--color-words\" to highlight only the changed portions of\n+lines. However, this can often be hard to read for code, as it loses\n+the line structure, and you end up with oddly formatted bits.\n+\n+Instead, this script post-processes the line-oriented diff, finds pairs\n+of lines, and highlights the differing segments.  It's currently very\n+simple and stupid about doing these tasks. In particular:\n+\n+  1. It will only highlight a pair of lines if they are the only two\n+     lines in a hunk.  It could instead try to match up \"before\" and\n+     \"after\" lines for a given hunk into pairs of similar lines.\n+     However, this may end up visually distracting, as the paired\n+     lines would have other highlighted lines in between them. And in\n+     practice, the lines which most need attention called to their\n+     small, hard-to-see changes are touching only a single line.\n+\n+  2. It will find the common prefix and suffix of two lines, and\n+     consider everything in the middle to be \"different\". It could\n+     instead do a real diff of the characters between the two lines and\n+     find common subsequences. However, the point of the highlight is to\n+     call attention to a certain area. Even if some small subset of the\n+     highlighted area actually didn't change, that's OK. In practice it\n+     ends up being more readable to just have a single blob on the line\n+     showing the interesting bit.\n+\n+The goal of the script is therefore not to be exact about highlighting\n+changes, but to call attention to areas of interest without being\n+visually distracting.  Non-diff lines and existing diff coloration is\n+preserved; the intent is that the output should look exactly the same as\n+the input, except for the occasional highlight.\n+\n+Use\n+---\n+\n+You can try out the diff-highlight program with:\n+\n+---------------------------------------------\n+git log -p --color | /path/to/diff-highlight\n+---------------------------------------------\n+\n+If you want to use it all the time, drop it in your $PATH and put the\n+following in your git configuration:\n+\n+---------------------------------------------\n+[pager]\n+\tlog = diff-highlight | less\n+\tshow = diff-highlight | less\n+\tdiff = diff-highlight | less\n+---------------------------------------------\ndiff --git a/contrib/diff-highlight/diff-highlight b/contrib/diff-highlight/diff-highlight\nnew file mode 100755\nindex 0000000..d893898\n--- /dev/null\n+++ b/contrib/diff-highlight/diff-highlight\n@@ -0,0 +1,124 @@\n+#!/usr/bin/perl\n+\n+# Highlight by reversing foreground and background. You could do\n+# other things like bold or underline if you prefer.\n+my $HIGHLIGHT   = \"\\x1b[7m\";\n+my $UNHIGHLIGHT = \"\\x1b[27m\";\n+my $COLOR = qr/\\x1b\\[[0-9;]*m/;\n+\n+my @window;\n+\n+while (<>) {\n+\t# We highlight only single-line changes, so we need\n+\t# a 4-line window to make a decision on whether\n+\t# to highlight.\n+\tpush @window, $_;\n+\tnext if @window < 4;\n+\tif ($window[0] =~ /^$COLOR*(\\@| )/ &&\n+\t    $window[1] =~ /^$COLOR*-/ &&\n+\t    $window[2] =~ /^$COLOR*\\+/ &&\n+\t    $window[3] !~ /^$COLOR*\\+/) {\n+\t\tprint shift @window;\n+\t\tshow_pair(shift @window, shift @window);\n+\t}\n+\telse {\n+\t\tprint shift @window;\n+\t}\n+\n+\t# Most of the time there is enough output to keep things streaming,\n+\t# but for something like \"git log -Sfoo\", you can get one early\n+\t# commit and then many seconds of nothing. We want to show\n+\t# that one commit as soon as possible.\n+\t#\n+\t# Since we can receive arbitrary input, there's no optimal\n+\t# place to flush. Flushing on a blank line is a heuristic that\n+\t# happens to match git-log output.\n+\tif (!length) {\n+\t\tlocal $| = 1;\n+\t}\n+}\n+\n+# Special case a single-line hunk at the end of file.\n+if (@window == 3 &&\n+    $window[0] =~ /^$COLOR*(\\@| )/ &&\n+    $window[1] =~ /^$COLOR*-/ &&\n+    $window[2] =~ /^$COLOR*\\+/) {\n+\tprint shift @window;\n+\tshow_pair(shift @window, shift @window);\n+}\n+\n+# And then flush any remaining lines.\n+while (@window) {\n+\tprint shift @window;\n+}\n+\n+exit 0;\n+\n+sub show_pair {\n+\tmy @a = split_line(shift);\n+\tmy @b = split_line(shift);\n+\n+\t# Find common prefix, taking care to skip any ansi\n+\t# color codes.\n+\tmy $seen_plusminus;\n+\tmy ($pa, $pb) = (0, 0);\n+\twhile ($pa < @a && $pb < @b) {\n+\t\tif ($a[$pa] =~ /$COLOR/) {\n+\t\t\t$pa++;\n+\t\t}\n+\t\telsif ($b[$pb] =~ /$COLOR/) {\n+\t\t\t$pb++;\n+\t\t}\n+\t\telsif ($a[$pa] eq $b[$pb]) {\n+\t\t\t$pa++;\n+\t\t\t$pb++;\n+\t\t}\n+\t\telsif (!$seen_plusminus && $a[$pa] eq '-' && $b[$pb] eq '+') {\n+\t\t\t$seen_plusminus = 1;\n+\t\t\t$pa++;\n+\t\t\t$pb++;\n+\t\t}\n+\t\telse {\n+\t\t\tlast;\n+\t\t}\n+\t}\n+\n+\t# Find common suffix, ignoring colors.\n+\tmy ($sa, $sb) = ($#a, $#b);\n+\twhile ($sa >= $pa && $sb >= $pb) {\n+\t\tif ($a[$sa] =~ /$COLOR/) {\n+\t\t\t$sa--;\n+\t\t}\n+\t\telsif ($b[$sb] =~ /$COLOR/) {\n+\t\t\t$sb--;\n+\t\t}\n+\t\telsif ($a[$sa] eq $b[$sb]) {\n+\t\t\t$sa--;\n+\t\t\t$sb--;\n+\t\t}\n+\t\telse {\n+\t\t\tlast;\n+\t\t}\n+\t}\n+\n+\tprint highlight(\\@a, $pa, $sa);\n+\tprint highlight(\\@b, $pb, $sb);\n+}\n+\n+sub split_line {\n+\tlocal $_ = shift;\n+\treturn map { /$COLOR/ ? $_ : (split //) }\n+\t       split /($COLOR*)/;\n+}\n+\n+sub highlight {\n+\tmy ($line, $prefix, $suffix) = @_;\n+\n+\treturn join('',\n+\t\t@{$line}[0..($prefix-1)],\n+\t\t$HIGHLIGHT,\n+\t\t@{$line}[$prefix..$suffix],\n+\t\t$UNHIGHLIGHT,\n+\t\t@{$line}[($suffix+1)..$#$line]\n+\t);\n+}\n-- \n1.7.7.rc3.37.gc4dc8\n"},{"id":"177918","messageId":"20111018045416.GB9008@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111018044955.GA8976@sigill.intra.peff.net","subject":"[PATCH 2/3] contrib: add git-jump script","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-18T04:54:16Z","receivedAt":"2011-10-18T04:54:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This is a small script for helping your editor jump to\nspecific points of interest. See the README for details.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n contrib/git-jump/README   |   92 +++++++++++++++++++++++++++++++++++++++++++++\n contrib/git-jump/git-jump |   68 +++++++++++++++++++++++++++++++++\n 2 files changed, 160 insertions(+), 0 deletions(-)\n create mode 100644 contrib/git-jump/README\n create mode 100755 contrib/git-jump/git-jump\n\ndiff --git a/contrib/git-jump/README b/contrib/git-jump/README\nnew file mode 100644\nindex 0000000..1cebc32\n--- /dev/null\n+++ b/contrib/git-jump/README\n@@ -0,0 +1,92 @@\n+git-jump\n+========\n+\n+Git-jump is a script for helping you jump to \"interesting\" parts of your\n+project in your editor. It works by outputting a set of interesting\n+spots in the \"quickfix\" format, which editors like vim can use as a\n+queue of places to visit (this feature is usually used to jump to errors\n+produced by a compiler). For example, given a diff like this:\n+\n+------------------------------------\n+diff --git a/foo.c b/foo.c\n+index a655540..5a59044 100644\n+--- a/foo.c\n++++ b/foo.c\n+@@ -1,3 +1,3 @@\n+ int main(void) {\n+-  printf(\"hello word!\\n\");\n++  printf(\"hello world!\\n\");\n+ }\n+-----------------------------------\n+\n+git-jump will feed this to the editor:\n+\n+-----------------------------------\n+foo.c:2: printf(\"hello word!\\n\");\n+-----------------------------------\n+\n+Obviously this trivial case isn't that interesting; you could just open\n+`foo.c` yourself. But when you have many changes scattered across a\n+project, you can use the editor's support to \"jump\" from point to point.\n+\n+Git-jump can generate three types of interesting lists:\n+\n+  1. The beginning of any diff hunks.\n+\n+  2. The beginning of any merge conflict markers.\n+\n+  3. Any grep matches.\n+\n+\n+Using git-jump\n+--------------\n+\n+To use it, just drop git-jump in your PATH, and then invoke it like\n+this:\n+\n+--------------------------------------------------\n+# jump to changes not yet staged for commit\n+git jump diff\n+\n+# jump to changes that are staged for commit; you can give\n+# arbitrary diff options\n+git jump diff --cached\n+\n+# jump to merge conflicts\n+git jump merge\n+\n+# jump to all instances of foo_bar\n+git jump grep foo_bar\n+\n+# same as above, but case-insensitive; you can give\n+# arbitrary grep options\n+git jump grep -i foo_bar\n+--------------------------------------------------\n+\n+\n+Related Programs\n+----------------\n+\n+You can accomplish some of the same things with individual tools. For\n+example, you can use `git mergetool` to start vimdiff on each unmerged\n+file. `git jump merge` is for the vim-wielding luddite who just wants to\n+jump straight to the conflict text with no fanfare.\n+\n+As of git v1.7.2, `git grep` knows the `--open-files-in-pager` option,\n+which does something similar to `git jump grep`. However, it is limited\n+to positioning the cursor to the correct line in only the first file,\n+leaving you to locate subsequent hits in that file or other files using\n+the editor or pager. By contrast, git-jump provides the editor with a\n+complete list of files and line numbers for each match.\n+\n+\n+Limitations\n+-----------\n+\n+This scripts was written and tested with vim. Given that the quickfix\n+format is the same as what gcc produces, I expect emacs users have a\n+similar feature for iterating through the list, but I know nothing about\n+how to activate it.\n+\n+The shell snippets to generate the quickfix lines will almost certainly\n+choke on filenames with exotic characters (like newlines).\ndiff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump\nnew file mode 100755\nindex 0000000..13b8e9f\n--- /dev/null\n+++ b/contrib/git-jump/git-jump\n@@ -0,0 +1,68 @@\n+#!/bin/sh\n+\n+usage() {\n+\tcat <<\\EOF\n+usage: git jump <mode> [<args>]\n+\n+Jump to interesting elements in an editor.\n+The <mode> parameter is one of:\n+\n+diff: elements are diff hunks. Arguments are given to diff.\n+\n+merge: elements are merge conflicts. Arguments are ignored.\n+\n+grep: elements are grep hits. Arguments are given to grep.\n+EOF\n+}\n+\n+open_editor() {\n+\teditor=`git var GIT_EDITOR`\n+\teval \"$editor -q \\$1\"\n+}\n+\n+mode_diff() {\n+\tgit diff --relative \"$@\" |\n+\tperl -ne '\n+\tif (m{^\\+\\+\\+ b/(.*)}) { $file = $1; next }\n+\tdefined($file) or next;\n+\tif (m/^@@ .*\\+(\\d+)/) { $line = $1; next }\n+\tdefined($line) or next;\n+\tif (/^ /) { $line++; next }\n+\tif (/^[-+]\\s*(.*)/) {\n+\t\tprint \"$file:$line: $1\\n\";\n+\t\t$line = undef;\n+\t}\n+\t'\n+}\n+\n+mode_merge() {\n+\tgit ls-files -u |\n+\tperl -pe 's/^.*?\\t//' |\n+\tsort -u |\n+\twhile IFS= read fn; do\n+\t\tgrep -Hn '^<<<<<<<' \"$fn\"\n+\tdone\n+}\n+\n+# Grep -n generates nice quickfix-looking lines by itself,\n+# but let's clean up extra whitespace, so they look better if the\n+# editor shows them to us in the status bar.\n+mode_grep() {\n+\tgit grep -n \"$@\" |\n+\tperl -pe '\n+\ts/[ \\t]+/ /g;\n+\ts/^ *//;\n+\t'\n+}\n+\n+if test $# -lt 1; then\n+\tusage >&2\n+\texit 1\n+fi\n+mode=$1; shift\n+\n+trap 'rm -f \"$tmp\"' 0 1 2 3 15\n+tmp=`mktemp -t git-jump.XXXXXX` || exit 1\n+\"mode_$mode\" \"$@\" >\"$tmp\" || { usage >&2; exit 1; }\n+test -s \"$tmp\" || exit 0\n+open_editor \"$tmp\"\n-- \n1.7.7.rc3.37.gc4dc8\n"},{"id":"177919","messageId":"20111018050105.GC9008@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111018044955.GA8976@sigill.intra.peff.net","subject":"[PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-18T05:01:05Z","receivedAt":"2011-10-18T05:01:05Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"A common thing to grep for is the name of a symbol. This\npatch teaches the completion for \"git grep\" to look in\na 'tags' file, if present, to complete a pattern. For\nexample, in git.git:\n\n  $ make tags\n  $ git grep get_sha1<Tab><Tab>\n  get_sha1                 get_sha1_oneline\n  get_sha1_1               get_sha1_with_context\n  get_sha1_basic           get_sha1_with_context_1\n  get_sha1_hex             get_sha1_with_mode\n  get_sha1_hex_segment     get_sha1_with_mode_1\n  get_sha1_mb\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nIt's debatable whether this belongs in the generic completion code, as\nit really only works if your project uses ctags. But I find it to be a\nhuge timesaver for finding callsites of functions, especially when\ncoupled with \"git jump grep\" from the previous patch.\n\nUndoubtedly you can do something similar with cscope, or with an editor\nplugin, but using grep feels very natural and simple to me.\n\nFor using with \"git jump grep\", I do this:\n\n  # much easier to type\n  git config --global alias.vgrep 'jump grep'\n\n  # and set up completion for it, too\n  cat >>~/.bashrc\n  _git_vgrep() {\n          _git_grep\n  }\n\n contrib/completion/git-completion.bash |   11 +++++++++++\n 1 files changed, 11 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 8648a36..f4ab13d 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1432,6 +1432,10 @@ _git_gitk ()\n \t_gitk\n }\n \n+_git_grep_ctag_match() {\n+\tawk -v ORS=' ' \"/^${1////\\\\/}/ { print \\$1 }\" \"$2\"\n+}\n+\n _git_grep ()\n {\n \t__git_has_doubledash && return\n@@ -1454,6 +1458,13 @@ _git_grep ()\n \t\t;;\n \tesac\n \n+\tcase \"$COMP_CWORD,$prev\" in\n+\t2,*|*,-*)\n+\t\ttest -r tags || return\n+\t\tCOMPREPLY=( $(compgen -W \"`_git_grep_ctag_match \"$cur\" tags`\") )\n+\t\treturn\n+\tesac\n+\n \t__gitcomp \"$(__git_refs)\"\n }\n \n-- \n1.7.7.rc3.37.gc4dc8\n"},{"id":"177931","messageId":"7vd3duixdg.fsf@alter.siamese.dyndns.org","threadId":"28708","inReplyTo":"20111018050105.GC9008@sigill.intra.peff.net","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-18T07:15:23Z","receivedAt":"2011-10-18T07:15:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> A common thing to grep for is the name of a symbol. This\n> patch teaches the completion for \"git grep\" to look in\n> a 'tags' file, if present, to complete a pattern. For\n> example, in git.git:\n>\n>   $ make tags\n>   $ git grep get_sha1<Tab><Tab>\n>   get_sha1                 get_sha1_oneline\n>   get_sha1_1               get_sha1_with_context\n>   get_sha1_basic           get_sha1_with_context_1\n>   get_sha1_hex             get_sha1_with_mode\n>   get_sha1_hex_segment     get_sha1_with_mode_1\n>   get_sha1_mb\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> It's debatable whether this belongs in the generic completion code, as\n> it really only works if your project uses ctags. But I find it to be a\n> huge timesaver for finding callsites of functions, especially when\n> coupled with \"git jump grep\" from the previous patch.\n\nCould you elaborate a bit more on how this would help for finding\ncallsites? You are looking at a function and do not want to break its\ncallers, so at that point presumably you already know the name of the\nfunction, no?\n\nAhh, Ok, you do not necessarily want to type the long function name.\n\nBy the way, I notice that \"make tags\" runs \"find .\" looking for any files\nand directories that match \"*.[hcS]\" (so do $(ETAGS_TARGET) and cscope),\nwithout even excluding .git metadirectory.\n\nPerhaps something like this is in order?\n\n Makefile |   14 +++++++++++---\n 1 files changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 17404c4..b38f55b 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2127,17 +2127,25 @@ po/git.pot: $(LOCALIZED_C)\n \n pot: po/git.pot\n \n+git_check = $(shell git ls-files >/dev/null 2>&1; echo $$?)\n+ifeq ($(git_check),0)\n+FIND_SOURCE_FILES = git ls-files '*.[hcS]'\n+else\n+FIND_SOURCE_FILES = $(FIND) . \\( -name .git -type d -prune \\) \\\n+\t\t-o \\( -name '*.[hcS]' -type f -print \\)\n+endif\n+\n $(ETAGS_TARGET): FORCE\n \t$(RM) $(ETAGS_TARGET)\n-\t$(FIND) . -name '*.[hcS]' -print | xargs etags -a -o $(ETAGS_TARGET)\n+\t$(FIND_SOURCE_FILES) | xargs etags -a -o $(ETAGS_TARGET)\n \n tags: FORCE\n \t$(RM) tags\n-\t$(FIND) . -name '*.[hcS]' -print | xargs ctags -a\n+\t$(FIND_SOURCE_FILES) | xargs ctags -a\n \n cscope:\n \t$(RM) cscope*\n-\t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n+\t$(FIND_SOURCE_FILES) | xargs cscope -b\n \n ### Detect prefix changes\n TRACK_CFLAGS = $(CC):$(subst ','\\'',$(ALL_CFLAGS)):\\\n"},{"id":"177932","messageId":"20111018072655.GA22309@elie.hsd1.il.comcast.net","threadId":"28708","inReplyTo":"7vd3duixdg.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-10-18T07:26:55Z","receivedAt":"2011-10-18T07:26:55Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n\n> Perhaps something like this is in order?\n[...]\n> +++ b/Makefile\n> @@ -2127,17 +2127,25 @@ po/git.pot: $(LOCALIZED_C)\n>  \n>  pot: po/git.pot\n>  \n> +git_check = $(shell git ls-files >/dev/null 2>&1; echo $$?)\n> +ifeq ($(git_check),0)\n> +FIND_SOURCE_FILES = git ls-files '*.[hcS]'\n> +else\n> +FIND_SOURCE_FILES = $(FIND) . \\( -name .git -type d -prune \\) \\\n> +\t\t-o \\( -name '*.[hcS]' -type f -print \\)\n> +endif\n\nNeat.  I'd prefer something like\n\n\tFIND_SOURCE_FILES = \\\n\t\tgit ls-files '*.[hcS]' 2>/dev/null || \\\n\t\t$(FIND) . -name .git -prune -o -name '*.[hcS]' -type f -print\n\nthat avoid punishing people who were using the makefile for some\npurpose unrelated to tags and cscope, though. ;)\n"},{"id":"177933","messageId":"7v8voiiwfo.fsf@alter.siamese.dyndns.org","threadId":"28708","inReplyTo":"20111018072655.GA22309@elie.hsd1.il.comcast.net","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-18T07:35:39Z","receivedAt":"2011-10-18T07:35:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>\n>> Perhaps something like this is in order?\n> [...]\n>> +++ b/Makefile\n>> @@ -2127,17 +2127,25 @@ po/git.pot: $(LOCALIZED_C)\n>>  \n>>  pot: po/git.pot\n>>  \n>> +git_check = $(shell git ls-files >/dev/null 2>&1; echo $$?)\n>> +ifeq ($(git_check),0)\n>> +FIND_SOURCE_FILES = git ls-files '*.[hcS]'\n>> +else\n>> +FIND_SOURCE_FILES = $(FIND) . \\( -name .git -type d -prune \\) \\\n>> +\t\t-o \\( -name '*.[hcS]' -type f -print \\)\n>> +endif\n>\n> Neat.  I'd prefer something like\n>\n> \tFIND_SOURCE_FILES = \\\n> \t\tgit ls-files '*.[hcS]' 2>/dev/null || \\\n> \t\t$(FIND) . -name .git -prune -o -name '*.[hcS]' -type f -print\n>\n> that avoid punishing people who were using the makefile for some\n> purpose unrelated to tags and cscope, though. ;)\n\nHmm, how would this punish anybody exactly (I just took the structure\nfrom the way how the auto-depend is done)?\n\nBesides, you would need to have the whole thing in a subshell or\nsomething, as this is used as the upstream to \"| xargs\".\n"},{"id":"177934","messageId":"vpqpqhug31l.fsf@bauges.imag.fr","threadId":"28708","inReplyTo":"7v8voiiwfo.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2011-10-18T07:41:10Z","receivedAt":"2011-10-18T07:41:10Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>>> +git_check = $(shell git ls-files >/dev/null 2>&1; echo $$?)\n>>> +ifeq ($(git_check),0)\n\n> Hmm, how would this punish anybody exactly (I just took the structure\n> from the way how the auto-depend is done)?\n\nThe \"shell git ls-files\" is ran unconditionnally, hence a small\nperformance penality even if you don't run ctags.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"177936","messageId":"20111018075521.GB20976@elie.hsd1.il.comcast.net","threadId":"28708","inReplyTo":"7v8voiiwfo.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-10-18T07:55:21Z","receivedAt":"2011-10-18T07:55:21Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n>> Junio C Hamano wrote:\n\n>>> +git_check = $(shell git ls-files >/dev/null 2>&1; echo $$?)\n[...]\n>> Neat.  I'd prefer something like\n[...]\n>> that avoid punishing people who were using the makefile for some\n>> purpose unrelated to tags and cscope, though. ;)\n>\n> Hmm, how would this punish anybody exactly (I just took the structure\n> from the way how the auto-depend is done)?\n\nAs Matthieu mentioned, the code in $(shell ...) gets run once each\ntime the makefile is loaded, adding to the runtime and possible\nfailure modes of\n\n\tmake clean\n\nthat does not care about the result.  The dep_check test has that same\nproblem, and I was a little nervous about that when we added it.  But:\n\n i.   it seemed to be worth the convenience\n\n ii.  computing whether the compiler supports -MMD once each time $(CC)\n      is launched would slow enough not to be an option\n\n iii. in the end, most uses of the makefile are to compile something,\n      anyway, so it is not _that_ much of a waste.\n\n iv.  if someone finds the per-make-invocation to be too high, we\n      could introduce a DONT_COMPUTE_HEADER_DEPENDENCIES variable that\n      causes the check to be skipped by forcing that particular result.\n\nGreat.\n\nIn this new tags/cscope example, one could make an argument that\nrunning exactly once is similarly better than running as needed (as in\n(ii) above), by pointing out that\n\n\tmake tags TAGS cscope\n\nwould have to check for a working \"git ls-files\" once instead of three\ntimes.  But I don't buy it. :)\n\n> Besides, you would need to have the whole thing in a subshell or\n> something, as this is used as the upstream to \"| xargs\".\n\nGood catch, thanks.\n"},{"id":"177937","messageId":"7vvcrmhgxr.fsf@alter.siamese.dyndns.org","threadId":"28708","inReplyTo":"vpqpqhug31l.fsf@bauges.imag.fr","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-18T07:55:44Z","receivedAt":"2011-10-18T07:55:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>>>> +git_check = $(shell git ls-files >/dev/null 2>&1; echo $$?)\n>>>> +ifeq ($(git_check),0)\n>\n>> Hmm, how would this punish anybody exactly (I just took the structure\n>> from the way how the auto-depend is done)?\n>\n> The \"shell git ls-files\" is ran unconditionnally, hence a small\n> performance penality even if you don't run ctags.\n\nYou mean it is run once whenever you type \"make <RETURN>\"?  Doesn't the\nsame argument apply for the auto-depend thingy against \"make doc<RETURN>\"?\n"},{"id":"177949","messageId":"20111018150423.GA11593@sigill.intra.peff.net","threadId":"28708","inReplyTo":"7vd3duixdg.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-18T15:04:23Z","receivedAt":"2011-10-18T15:04:23Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Oct 18, 2011 at 12:15:23AM -0700, Junio C Hamano wrote:\n\n> > It's debatable whether this belongs in the generic completion code, as\n> > it really only works if your project uses ctags. But I find it to be a\n> > huge timesaver for finding callsites of functions, especially when\n> > coupled with \"git jump grep\" from the previous patch.\n> \n> Could you elaborate a bit more on how this would help for finding\n> callsites? You are looking at a function and do not want to break its\n> callers, so at that point presumably you already know the name of the\n> function, no?\n> \n> Ahh, Ok, you do not necessarily want to type the long function name.\n\nExactly. Actually, it is often not so much \"do not want to type\" as\n\"cannot remember the exact name\", but the effect is the same. :)\n\nI use the same completion for \"vim -t\" which will jump to the\ndefinition.\n\n> By the way, I notice that \"make tags\" runs \"find .\" looking for any files\n> and directories that match \"*.[hcS]\" (so do $(ETAGS_TARGET) and cscope),\n> without even excluding .git metadirectory.\n> \n> Perhaps something like this is in order?\n> [...]\n> +FIND_SOURCE_FILES = git ls-files '*.[hcS]'\n\nMakes sense to me. I doubt it matters much in practice, though, as we\ndon't tend to have random untracked source files lying around.\n\nMy version of ctags will actually do the recursion itself with \"ctags\n-R\", picking out any files with with languages it knows about. But maybe\nnot all versions do that.\n\nAlso, I have often found myself trying to do completion on shell\nfunctions. I wonder if it's worth adding them to the list (again, my\nversion of ctags understands bourne shell just fine, but I don't know if\nall do).\n\n-Peff\n"},{"id":"177954","messageId":"7vipnmgr2w.fsf@alter.siamese.dyndns.org","threadId":"28708","inReplyTo":"20111018075521.GB20976@elie.hsd1.il.comcast.net","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-18T17:14:15Z","receivedAt":"2011-10-18T17:14:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> In this new tags/cscope example, one could make an argument that\n> running exactly once is similarly better than running as needed (as in\n> (ii) above), by pointing out that\n>\n> \tmake tags TAGS cscope\n>\n> would have to check for a working \"git ls-files\" once instead of three\n> times.\n\nI tend to agree that once instead of three times is not such an\nimprovement, especially given how cheap builtin-invocation of ls-files is,\nbut then once every invocation of $(MAKE) would also be negligible (it is\nnot once every internal target evaluation).\n\nIn any case, here is what I'll queue. I like the fact that your suggestion\navoids an extra \"test invocation\" that spends cycles to read the full\nindex without contributing to the end result.\n\nBy the way, did anybody know that \"git ls-files >/dev/null\" is more\nexpensive than \"git ls-files '~/' >/dev/null\" as a way to see if there is\nls-files command available?\n\n-- >8 --\nSubject: [PATCH] Makefile: ask \"ls-files\" to list source files if available\n\nThe [ce]tags and cscope targets used to run \"find\" looking for any paths\nthat match '*.[chS]' to feed the list of source files to downstream xargs.\n\nUse \"git ls-files\" if it is already available to us, and otherwise use a\ntighter \"find\" expression that does not list directories and does not go\ninto our .git directory.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile |   10 +++++++---\n 1 files changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8d6d451..badfb77 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2115,17 +2115,21 @@ po/git.pot: $(LOCALIZED_C)\n \n pot: po/git.pot\n \n+FIND_SOURCE_FILES = ( git ls-files '*.[hcS]' 2>/dev/null || \\\n+\t\t\t$(FIND) . \\( -name .git -type d -prune \\) \\\n+\t\t\t\t-o \\( -name '*.[hcS]' -type f -print \\) )\n+\n $(ETAGS_TARGET): FORCE\n \t$(RM) $(ETAGS_TARGET)\n-\t$(FIND) . -name '*.[hcS]' -print | xargs etags -a -o $(ETAGS_TARGET)\n+\t$(FIND_SOURCE_FILES) | xargs etags -a -o $(ETAGS_TARGET)\n \n tags: FORCE\n \t$(RM) tags\n-\t$(FIND) . -name '*.[hcS]' -print | xargs ctags -a\n+\t$(FIND_SOURCE_FILES) | xargs ctags -a\n \n cscope:\n \t$(RM) cscope*\n-\t$(FIND) . -name '*.[hcS]' -print | xargs cscope -b\n+\t$(FIND_SOURCE_FILES) | xargs cscope -b\n \n ### Detect prefix changes\n TRACK_CFLAGS = $(CC):$(subst ','\\'',$(ALL_CFLAGS)):\\\n-- \n1.7.7.388.g3a4b7\n"},{"id":"178123","messageId":"20111021132545.GA27385@goldbirke","threadId":"28708","inReplyTo":"20111018050105.GC9008@sigill.intra.peff.net","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2011-10-21T13:25:45Z","receivedAt":"2011-10-21T13:25:45Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Hi,\n\n\nOn Tue, Oct 18, 2011 at 01:01:05AM -0400, Jeff King wrote:\n> A common thing to grep for is the name of a symbol. This\n> patch teaches the completion for \"git grep\" to look in\n> a 'tags' file, if present, to complete a pattern. For\n> example, in git.git:\n> \n>   $ make tags\n>   $ git grep get_sha1<Tab><Tab>\n>   get_sha1                 get_sha1_oneline\n>   get_sha1_1               get_sha1_with_context\n>   get_sha1_basic           get_sha1_with_context_1\n>   get_sha1_hex             get_sha1_with_mode\n>   get_sha1_hex_segment     get_sha1_with_mode_1\n>   get_sha1_mb\n> \n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> It's debatable whether this belongs in the generic completion code, as\n> it really only works if your project uses ctags. But I find it to be a\n> huge timesaver for finding callsites of functions\n\nInteresting idea.  I reckon most of the time I do 'git grep' in order\nto find callsites of a function or usage of a global variable.  I\nusually do that by copy-pasting the symbol name, but this change could\nlikely spare me that copy-paste.\n\n>  contrib/completion/git-completion.bash |   11 +++++++++++\n>  1 files changed, 11 insertions(+), 0 deletions(-)\n> \n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 8648a36..f4ab13d 100755\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -1432,6 +1432,10 @@ _git_gitk ()\n>  \t_gitk\n>  }\n>  \n> +_git_grep_ctag_match() {\n\nThis is a helper function, therefore it should have two underscores as\nprefix, i.e. __git_grep_ctag_match().  Single underscore prefixes are\n\"reserved\" for completion functions of the corresponding git command,\ni.e. if someone ever creates a git command or alias called\n'grep_ctag_match', then 'git grep_ctag_match <TAB>' will invoke this\nfunction to offer possible completion words.\n\n> +\tawk -v ORS=' ' \"/^${1////\\\\/}/ { print \\$1 }\" \"$2\"\n> +}\n> +\n>  _git_grep ()\n>  {\n>  \t__git_has_doubledash && return\n> @@ -1454,6 +1458,13 @@ _git_grep ()\n>  \t\t;;\n>  \tesac\n>  \n> +\tcase \"$COMP_CWORD,$prev\" in\n\nDepending on what is on the command line before the current word,\n$COMP_CWORD might have different value in Bash 3 and in Bash 4; see\nda48616f (bash: get --pretty=m<tab> completion to work with bash v4,\n2010-12-02).  Please use $cword instead.\n\n> +\t2,*|*,-*)\n> +\t\ttest -r tags || return\n\n1. This checks for the tags file in the current directory, so it would\n   only work at the top of the working tree, but not in any of the\n   subdirectories.\n\n2. The return in case of no tags file would cause file name\n   completion.  This is different from the current behavior, when the\n   completion script would offer refs.  Now, I don't think that refs\n   as grep pattern are any more useful than file names...  but neither\n   do I think that offering file names is an improvement over current\n   behavior.  Anyway, this is a side effect not mentioned in the\n   commit message.\n\n> +\t\tCOMPREPLY=( $(compgen -W \"`_git_grep_ctag_match \"$cur\" tags`\") )\n\n1. Nit: $() around _git_grep_ctag_match().\n   This would be the first backticks usage in the completion script.\n\n2. When the completion script offers possible completion words, then\n   usually a space is appended, e.g. 'git grep --e<TAB>' would\n   complete to '--extended-regexp ', unless the offered option\n   requires an argument, e.g. 'git commit --m<TAB>' would complete to\n   '--message='.  I think function names extracted from the tags file\n   should also get that trailing space.  No big deal, the easiest way\n   to do that is to pass the output of _git_grep_ctag_match() to\n   __gitcomp(), and it will take care of that.\n\n   However, this change will make 'git grep <TAB>' offer 9868 possible\n   completion words in my git repository, which is quite a lot.  I\n   posted some completion optimizations recently, currently cooking in\n   pu, which make processing that many possible completion words\n   faster (sg/complete-refs, tip currently at 175901a5; the important\n   commit is bd4139ca (completion: optimize refs completion,\n   2011-10-15)).  To be able to use that optimization possible\n   completion words must be separated by a newline, but your\n   _git_grep_ctag_match() lists symbol names separated by a space.  It\n   would be great if you could tweak _git_grep_ctag_match()'s awk\n   script to list newline-separated symbols, so that when both\n   branches are merged, then we could just change the __gitcomp() call\n   to __gitcomp_nl().\n\n\nBest,\nGábor\n"},{"id":"178131","messageId":"20111021172239.GA22289@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111021132545.GA27385@goldbirke","subject":"Re: [PATCH 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-21T17:22:39Z","receivedAt":"2011-10-21T17:22:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Oct 21, 2011 at 03:25:45PM +0200, SZEDER Gábor wrote:\n\n> Interesting idea.  I reckon most of the time I do 'git grep' in order\n> to find callsites of a function or usage of a global variable.  I\n> usually do that by copy-pasting the symbol name, but this change could\n> likely spare me that copy-paste.\n\nThanks. Glad somebody else finds it useful. :)\n\n> > +_git_grep_ctag_match() {\n> \n> This is a helper function, therefore it should have two underscores as\n> prefix, i.e. __git_grep_ctag_match().  Single underscore prefixes are\n> \"reserved\" for completion functions of the corresponding git command,\n> i.e. if someone ever creates a git command or alias called\n> 'grep_ctag_match', then 'git grep_ctag_match <TAB>' will invoke this\n> function to offer possible completion words.\n\nGood point. Will change.\n\n> > +\tcase \"$COMP_CWORD,$prev\" in\n> \n> Depending on what is on the command line before the current word,\n> $COMP_CWORD might have different value in Bash 3 and in Bash 4; see\n> da48616f (bash: get --pretty=m<tab> completion to work with bash v4,\n> 2010-12-02).  Please use $cword instead.\n\nThanks, I was completely unaware of this issue.\n\n> > +\t2,*|*,-*)\n> > +\t\ttest -r tags || return\n> \n> 1. This checks for the tags file in the current directory, so it would\n>    only work at the top of the working tree, but not in any of the\n>    subdirectories.\n\nYeah. I didn't want to spend a lot of effort looking up through the\nrepository directories for a 'tags' file. Especially for people who\naren't using ctags at all, and for whom that would just be unnecessary\nwork.\n\nOTOH, it is triggered only when they try to complete a pattern, which is\ncurrently pointless. So maybe it's not worth worrying about existing\nusers, as they won't do this completion anyway.\n\n> 2. The return in case of no tags file would cause file name\n>    completion.  This is different from the current behavior, when the\n>    completion script would offer refs.  Now, I don't think that refs\n>    as grep pattern are any more useful than file names...  but neither\n>    do I think that offering file names is an improvement over current\n>    behavior.  Anyway, this is a side effect not mentioned in the\n>    commit message.\n\nGood point. Will fix.\n\n> > +\t\tCOMPREPLY=( $(compgen -W \"`_git_grep_ctag_match \"$cur\" tags`\") )\n> \n> 1. Nit: $() around _git_grep_ctag_match().\n>    This would be the first backticks usage in the completion script.\n\nFunctionally irrelevant, I think, but style-wise, I agree it should\nmatch the rest of the script.\n\n> 2. When the completion script offers possible completion words, then\n>    usually a space is appended, e.g. 'git grep --e<TAB>' would\n>    complete to '--extended-regexp ', unless the offered option\n>    requires an argument, e.g. 'git commit --m<TAB>' would complete to\n>    '--message='.  I think function names extracted from the tags file\n>    should also get that trailing space.  No big deal, the easiest way\n>    to do that is to pass the output of _git_grep_ctag_match() to\n>    __gitcomp(), and it will take care of that.\n\nThanks, I had wanted to add the space at one point, but forgot about it\nand got used to the current behavior. I agree adding it is better, and\nit's nice that it's easy to do.\n\n>    However, this change will make 'git grep <TAB>' offer 9868 possible\n>    completion words in my git repository, which is quite a lot.\n\nHmm. I never thought of that as much, but after converting to use\n__gitcomp, there is a noticeable delay. I guess it's the loop of printfs\nin __gitcomp_1.\n\n...Ah, yes, reading your bd4139caa, it seems that is exactly the\nproblem.\n\n>    I posted some completion optimizations recently, currently cooking\n>    in pu, which make processing that many possible completion words\n>    faster (sg/complete-refs, tip currently at 175901a5; the important\n>    commit is bd4139ca (completion: optimize refs completion,\n>    2011-10-15)).  To be able to use that optimization possible\n>    completion words must be separated by a newline, but your\n>    _git_grep_ctag_match() lists symbol names separated by a space.  It\n>    would be great if you could tweak _git_grep_ctag_match()'s awk\n>    script to list newline-separated symbols, so that when both\n>    branches are merged, then we could just change the __gitcomp() call\n>    to __gitcomp_nl().\n\nEasy enough (just drop the ORS setting).\n\nThanks very much for your review. I have a fix for the first patch in\nthe series, too, so I'll send a whole new series in a moment.\n\n-Peff\n"},{"id":"178132","messageId":"20111021172630.GA24417@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111021172239.GA22289@sigill.intra.peff.net","subject":"[PATCHv2 1/3] contrib: add diff highlight script","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-21T17:26:30Z","receivedAt":"2011-10-21T17:26:30Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This is a simple and stupid script for highlighting\ndiffering parts of lines in a unified diff. See the README\nfor a discussion of the limitations.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nSame as v1.\n\n contrib/diff-highlight/README         |   57 +++++++++++++++\n contrib/diff-highlight/diff-highlight |  124 +++++++++++++++++++++++++++++++++\n 2 files changed, 181 insertions(+), 0 deletions(-)\n create mode 100644 contrib/diff-highlight/README\n create mode 100755 contrib/diff-highlight/diff-highlight\n\ndiff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README\nnew file mode 100644\nindex 0000000..1b7b6df\n--- /dev/null\n+++ b/contrib/diff-highlight/README\n@@ -0,0 +1,57 @@\n+diff-highlight\n+==============\n+\n+Line oriented diffs are great for reviewing code, because for most\n+hunks, you want to see the old and the new segments of code next to each\n+other. Sometimes, though, when an old line and a new line are very\n+similar, it's hard to immediately see the difference.\n+\n+You can use \"--color-words\" to highlight only the changed portions of\n+lines. However, this can often be hard to read for code, as it loses\n+the line structure, and you end up with oddly formatted bits.\n+\n+Instead, this script post-processes the line-oriented diff, finds pairs\n+of lines, and highlights the differing segments.  It's currently very\n+simple and stupid about doing these tasks. In particular:\n+\n+  1. It will only highlight a pair of lines if they are the only two\n+     lines in a hunk.  It could instead try to match up \"before\" and\n+     \"after\" lines for a given hunk into pairs of similar lines.\n+     However, this may end up visually distracting, as the paired\n+     lines would have other highlighted lines in between them. And in\n+     practice, the lines which most need attention called to their\n+     small, hard-to-see changes are touching only a single line.\n+\n+  2. It will find the common prefix and suffix of two lines, and\n+     consider everything in the middle to be \"different\". It could\n+     instead do a real diff of the characters between the two lines and\n+     find common subsequences. However, the point of the highlight is to\n+     call attention to a certain area. Even if some small subset of the\n+     highlighted area actually didn't change, that's OK. In practice it\n+     ends up being more readable to just have a single blob on the line\n+     showing the interesting bit.\n+\n+The goal of the script is therefore not to be exact about highlighting\n+changes, but to call attention to areas of interest without being\n+visually distracting.  Non-diff lines and existing diff coloration is\n+preserved; the intent is that the output should look exactly the same as\n+the input, except for the occasional highlight.\n+\n+Use\n+---\n+\n+You can try out the diff-highlight program with:\n+\n+---------------------------------------------\n+git log -p --color | /path/to/diff-highlight\n+---------------------------------------------\n+\n+If you want to use it all the time, drop it in your $PATH and put the\n+following in your git configuration:\n+\n+---------------------------------------------\n+[pager]\n+\tlog = diff-highlight | less\n+\tshow = diff-highlight | less\n+\tdiff = diff-highlight | less\n+---------------------------------------------\ndiff --git a/contrib/diff-highlight/diff-highlight b/contrib/diff-highlight/diff-highlight\nnew file mode 100755\nindex 0000000..d893898\n--- /dev/null\n+++ b/contrib/diff-highlight/diff-highlight\n@@ -0,0 +1,124 @@\n+#!/usr/bin/perl\n+\n+# Highlight by reversing foreground and background. You could do\n+# other things like bold or underline if you prefer.\n+my $HIGHLIGHT   = \"\\x1b[7m\";\n+my $UNHIGHLIGHT = \"\\x1b[27m\";\n+my $COLOR = qr/\\x1b\\[[0-9;]*m/;\n+\n+my @window;\n+\n+while (<>) {\n+\t# We highlight only single-line changes, so we need\n+\t# a 4-line window to make a decision on whether\n+\t# to highlight.\n+\tpush @window, $_;\n+\tnext if @window < 4;\n+\tif ($window[0] =~ /^$COLOR*(\\@| )/ &&\n+\t    $window[1] =~ /^$COLOR*-/ &&\n+\t    $window[2] =~ /^$COLOR*\\+/ &&\n+\t    $window[3] !~ /^$COLOR*\\+/) {\n+\t\tprint shift @window;\n+\t\tshow_pair(shift @window, shift @window);\n+\t}\n+\telse {\n+\t\tprint shift @window;\n+\t}\n+\n+\t# Most of the time there is enough output to keep things streaming,\n+\t# but for something like \"git log -Sfoo\", you can get one early\n+\t# commit and then many seconds of nothing. We want to show\n+\t# that one commit as soon as possible.\n+\t#\n+\t# Since we can receive arbitrary input, there's no optimal\n+\t# place to flush. Flushing on a blank line is a heuristic that\n+\t# happens to match git-log output.\n+\tif (!length) {\n+\t\tlocal $| = 1;\n+\t}\n+}\n+\n+# Special case a single-line hunk at the end of file.\n+if (@window == 3 &&\n+    $window[0] =~ /^$COLOR*(\\@| )/ &&\n+    $window[1] =~ /^$COLOR*-/ &&\n+    $window[2] =~ /^$COLOR*\\+/) {\n+\tprint shift @window;\n+\tshow_pair(shift @window, shift @window);\n+}\n+\n+# And then flush any remaining lines.\n+while (@window) {\n+\tprint shift @window;\n+}\n+\n+exit 0;\n+\n+sub show_pair {\n+\tmy @a = split_line(shift);\n+\tmy @b = split_line(shift);\n+\n+\t# Find common prefix, taking care to skip any ansi\n+\t# color codes.\n+\tmy $seen_plusminus;\n+\tmy ($pa, $pb) = (0, 0);\n+\twhile ($pa < @a && $pb < @b) {\n+\t\tif ($a[$pa] =~ /$COLOR/) {\n+\t\t\t$pa++;\n+\t\t}\n+\t\telsif ($b[$pb] =~ /$COLOR/) {\n+\t\t\t$pb++;\n+\t\t}\n+\t\telsif ($a[$pa] eq $b[$pb]) {\n+\t\t\t$pa++;\n+\t\t\t$pb++;\n+\t\t}\n+\t\telsif (!$seen_plusminus && $a[$pa] eq '-' && $b[$pb] eq '+') {\n+\t\t\t$seen_plusminus = 1;\n+\t\t\t$pa++;\n+\t\t\t$pb++;\n+\t\t}\n+\t\telse {\n+\t\t\tlast;\n+\t\t}\n+\t}\n+\n+\t# Find common suffix, ignoring colors.\n+\tmy ($sa, $sb) = ($#a, $#b);\n+\twhile ($sa >= $pa && $sb >= $pb) {\n+\t\tif ($a[$sa] =~ /$COLOR/) {\n+\t\t\t$sa--;\n+\t\t}\n+\t\telsif ($b[$sb] =~ /$COLOR/) {\n+\t\t\t$sb--;\n+\t\t}\n+\t\telsif ($a[$sa] eq $b[$sb]) {\n+\t\t\t$sa--;\n+\t\t\t$sb--;\n+\t\t}\n+\t\telse {\n+\t\t\tlast;\n+\t\t}\n+\t}\n+\n+\tprint highlight(\\@a, $pa, $sa);\n+\tprint highlight(\\@b, $pb, $sb);\n+}\n+\n+sub split_line {\n+\tlocal $_ = shift;\n+\treturn map { /$COLOR/ ? $_ : (split //) }\n+\t       split /($COLOR*)/;\n+}\n+\n+sub highlight {\n+\tmy ($line, $prefix, $suffix) = @_;\n+\n+\treturn join('',\n+\t\t@{$line}[0..($prefix-1)],\n+\t\t$HIGHLIGHT,\n+\t\t@{$line}[$prefix..$suffix],\n+\t\t$UNHIGHLIGHT,\n+\t\t@{$line}[($suffix+1)..$#$line]\n+\t);\n+}\n-- \n1.7.7.rc1.28.g5dd2ee\n"},{"id":"178133","messageId":"20111021172804.GB24417@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111021172239.GA22289@sigill.intra.peff.net","subject":"[PATCH 2/3] contrib: add git-jump script","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-21T17:28:04Z","receivedAt":"2011-10-21T17:28:04Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This is a small script for helping your editor jump to\nspecific points of interest. See the README for details.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis fixes a minor bug in v1 where doing \"git jump merge\" would display\nthe usage message when there were unmerged files, but none of the files\ncontained conflict markers (i.e., you had already fixed them up).\n\n contrib/git-jump/README   |   92 +++++++++++++++++++++++++++++++++++++++++++++\n contrib/git-jump/git-jump |   69 +++++++++++++++++++++++++++++++++\n 2 files changed, 161 insertions(+), 0 deletions(-)\n create mode 100644 contrib/git-jump/README\n create mode 100755 contrib/git-jump/git-jump\n\ndiff --git a/contrib/git-jump/README b/contrib/git-jump/README\nnew file mode 100644\nindex 0000000..1cebc32\n--- /dev/null\n+++ b/contrib/git-jump/README\n@@ -0,0 +1,92 @@\n+git-jump\n+========\n+\n+Git-jump is a script for helping you jump to \"interesting\" parts of your\n+project in your editor. It works by outputting a set of interesting\n+spots in the \"quickfix\" format, which editors like vim can use as a\n+queue of places to visit (this feature is usually used to jump to errors\n+produced by a compiler). For example, given a diff like this:\n+\n+------------------------------------\n+diff --git a/foo.c b/foo.c\n+index a655540..5a59044 100644\n+--- a/foo.c\n++++ b/foo.c\n+@@ -1,3 +1,3 @@\n+ int main(void) {\n+-  printf(\"hello word!\\n\");\n++  printf(\"hello world!\\n\");\n+ }\n+-----------------------------------\n+\n+git-jump will feed this to the editor:\n+\n+-----------------------------------\n+foo.c:2: printf(\"hello word!\\n\");\n+-----------------------------------\n+\n+Obviously this trivial case isn't that interesting; you could just open\n+`foo.c` yourself. But when you have many changes scattered across a\n+project, you can use the editor's support to \"jump\" from point to point.\n+\n+Git-jump can generate three types of interesting lists:\n+\n+  1. The beginning of any diff hunks.\n+\n+  2. The beginning of any merge conflict markers.\n+\n+  3. Any grep matches.\n+\n+\n+Using git-jump\n+--------------\n+\n+To use it, just drop git-jump in your PATH, and then invoke it like\n+this:\n+\n+--------------------------------------------------\n+# jump to changes not yet staged for commit\n+git jump diff\n+\n+# jump to changes that are staged for commit; you can give\n+# arbitrary diff options\n+git jump diff --cached\n+\n+# jump to merge conflicts\n+git jump merge\n+\n+# jump to all instances of foo_bar\n+git jump grep foo_bar\n+\n+# same as above, but case-insensitive; you can give\n+# arbitrary grep options\n+git jump grep -i foo_bar\n+--------------------------------------------------\n+\n+\n+Related Programs\n+----------------\n+\n+You can accomplish some of the same things with individual tools. For\n+example, you can use `git mergetool` to start vimdiff on each unmerged\n+file. `git jump merge` is for the vim-wielding luddite who just wants to\n+jump straight to the conflict text with no fanfare.\n+\n+As of git v1.7.2, `git grep` knows the `--open-files-in-pager` option,\n+which does something similar to `git jump grep`. However, it is limited\n+to positioning the cursor to the correct line in only the first file,\n+leaving you to locate subsequent hits in that file or other files using\n+the editor or pager. By contrast, git-jump provides the editor with a\n+complete list of files and line numbers for each match.\n+\n+\n+Limitations\n+-----------\n+\n+This scripts was written and tested with vim. Given that the quickfix\n+format is the same as what gcc produces, I expect emacs users have a\n+similar feature for iterating through the list, but I know nothing about\n+how to activate it.\n+\n+The shell snippets to generate the quickfix lines will almost certainly\n+choke on filenames with exotic characters (like newlines).\ndiff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump\nnew file mode 100755\nindex 0000000..a33674e\n--- /dev/null\n+++ b/contrib/git-jump/git-jump\n@@ -0,0 +1,69 @@\n+#!/bin/sh\n+\n+usage() {\n+\tcat <<\\EOF\n+usage: git jump <mode> [<args>]\n+\n+Jump to interesting elements in an editor.\n+The <mode> parameter is one of:\n+\n+diff: elements are diff hunks. Arguments are given to diff.\n+\n+merge: elements are merge conflicts. Arguments are ignored.\n+\n+grep: elements are grep hits. Arguments are given to grep.\n+EOF\n+}\n+\n+open_editor() {\n+\teditor=`git var GIT_EDITOR`\n+\teval \"$editor -q \\$1\"\n+}\n+\n+mode_diff() {\n+\tgit diff --relative \"$@\" |\n+\tperl -ne '\n+\tif (m{^\\+\\+\\+ b/(.*)}) { $file = $1; next }\n+\tdefined($file) or next;\n+\tif (m/^@@ .*\\+(\\d+)/) { $line = $1; next }\n+\tdefined($line) or next;\n+\tif (/^ /) { $line++; next }\n+\tif (/^[-+]\\s*(.*)/) {\n+\t\tprint \"$file:$line: $1\\n\";\n+\t\t$line = undef;\n+\t}\n+\t'\n+}\n+\n+mode_merge() {\n+\tgit ls-files -u |\n+\tperl -pe 's/^.*?\\t//' |\n+\tsort -u |\n+\twhile IFS= read fn; do\n+\t\tgrep -Hn '^<<<<<<<' \"$fn\"\n+\tdone\n+}\n+\n+# Grep -n generates nice quickfix-looking lines by itself,\n+# but let's clean up extra whitespace, so they look better if the\n+# editor shows them to us in the status bar.\n+mode_grep() {\n+\tgit grep -n \"$@\" |\n+\tperl -pe '\n+\ts/[ \\t]+/ /g;\n+\ts/^ *//;\n+\t'\n+}\n+\n+if test $# -lt 1; then\n+\tusage >&2\n+\texit 1\n+fi\n+mode=$1; shift\n+\n+trap 'rm -f \"$tmp\"' 0 1 2 3 15\n+tmp=`mktemp -t git-jump.XXXXXX` || exit 1\n+type \"mode_$mode\" >/dev/null 2>&1 || { usage >&2; exit 1; }\n+\"mode_$mode\" \"$@\" >\"$tmp\"\n+test -s \"$tmp\" || exit 0\n+open_editor \"$tmp\"\n-- \n1.7.7.rc1.28.g5dd2ee\n"},{"id":"178134","messageId":"20111021173021.GC24417@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111021172239.GA22289@sigill.intra.peff.net","subject":"[PATCHv2 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-21T17:30:21Z","receivedAt":"2011-10-21T17:30:21Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"A common thing to grep for is the name of a symbol. This\npatch teaches the completion for \"git grep\" to look in\na 'tags' file, if present, to complete a pattern. For\nexample, in git.git:\n\n  $ make tags\n  $ git grep get_sha1<Tab><Tab>\n  get_sha1                 get_sha1_oneline\n  get_sha1_1               get_sha1_with_context\n  get_sha1_basic           get_sha1_with_context_1\n  get_sha1_hex             get_sha1_with_mode\n  get_sha1_hex_segment     get_sha1_with_mode_1\n  get_sha1_mb\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis incorporates the suggestions from Gábor's review, with one\nexception: it still looks only in the current directory for the \"tags\"\nfiles. I think that might have some performance implications, so I'd\nrather add it separately, if at all.\n\n contrib/completion/git-completion.bash |   13 +++++++++++++\n 1 files changed, 13 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 888e8e1..af283cb 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1429,6 +1429,10 @@ _git_gitk ()\n \t_gitk\n }\n \n+__git_match_ctag() {\n+\tawk \"/^${1////\\\\/}/ { print \\$1 }\" \"$2\"\n+}\n+\n _git_grep ()\n {\n \t__git_has_doubledash && return\n@@ -1451,6 +1455,15 @@ _git_grep ()\n \t\t;;\n \tesac\n \n+\tcase \"$cword,$prev\" in\n+\t2,*|*,-*)\n+\t\tif test -r tags; then\n+\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" tags)\"\n+\t\t\treturn\n+\t\tfi\n+\t\t;;\n+\tesac\n+\n \t__gitcomp \"$(__git_refs)\"\n }\n \n-- \n1.7.7.rc1.28.g5dd2ee\n"},{"id":"178136","messageId":"20111021173528.GA24406@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111021172804.GB24417@sigill.intra.peff.net","subject":"Re: [PATCH 2/3] contrib: add git-jump script","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-21T17:35:28Z","receivedAt":"2011-10-21T17:35:28Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Oct 21, 2011 at 01:28:04PM -0400, Jeff King wrote:\n\n> Subject: [PATCH 2/3] contrib: add git-jump script\n> [...]\n> This fixes a minor bug in v1 where doing \"git jump merge\" would display\n> the usage message when there were unmerged files, but none of the files\n> contained conflict markers (i.e., you had already fixed them up).\n\nOops, the subject should read \"PATCHv2\", obviously.\n\n-Peff\n"},{"id":"178137","messageId":"20111021173748.GB24406@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111021173021.GC24417@sigill.intra.peff.net","subject":"[PATCHv2 4/3] completion: use __gitcomp_nl for ctag matching","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-21T17:37:48Z","receivedAt":"2011-10-21T17:37:48Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Oct 21, 2011 at 01:30:21PM -0400, Jeff King wrote:\n\n> +\t\tif test -r tags; then\n> +\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" tags)\"\n> +\t\t\treturn\n> +\t\tfi\n\nOnce this is merged with sg/complete-refs, this can be applied on top:\n\n-- >8 --\nSubject: [PATCH] completion: use __gitcomp_nl for ctag matching\n\nIt's much faster than __gitcomp for large numbers of matches\n(which ctags often have; there are almost 10,000 matches for\n\"\" in git.git).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nAs an aside, this is one of those patches that is easier to review using\n\"diff-highlight\" from patch 1 of this series.\n\n contrib/completion/git-completion.bash |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 391c054..53d3dcb 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1473,7 +1473,7 @@ _git_grep ()\n \tcase \"$cword,$prev\" in\n \t2,*|*,-*)\n \t\tif test -r tags; then\n-\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" tags)\"\n+\t\t\t__gitcomp_nl \"$(__git_match_ctag \"$cur\" tags)\"\n \t\t\treturn\n \t\tfi\n \t\t;;\n-- \n1.7.7.rc1.28.g5dd2ee\n"},{"id":"178208","messageId":"20111023212928.GG22551@goldbirke","threadId":"28708","inReplyTo":"20111021173021.GC24417@sigill.intra.peff.net","subject":"Re: [PATCHv2 3/3] completion: match ctags symbol names in grep patterns","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2011-10-23T21:29:28Z","receivedAt":"2011-10-23T21:29:28Z","isPatch":false,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Hi,\n\nOn Fri, Oct 21, 2011 at 01:30:21PM -0400, Jeff King wrote:\n> This incorporates the suggestions from Gábor's review, with one\n> exception: it still looks only in the current directory for the \"tags\"\n> files. I think that might have some performance implications, so I'd\n> rather add it separately, if at all.\n\nI agree that scanning through a whole working tree for tags files\nwould cost too much.  But I think that a tags file at the top of the\nworking tree is common enough to be supported, and checking its\nexistence is fairly cheap.\n\n> +\tcase \"$cword,$prev\" in\n> +\t2,*|*,-*)\n> +\t\tif test -r tags; then\n> +\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" tags)\"\n> +\t\t\treturn\n> +\t\tfi\n> +\t\t;;\n\nSo how about something like this for the case arm? (I didn't actually\ntested it.)\n\n\t\tlocal tagsfile\n\t\tif test -r tags; then\n\t\t\ttagsfile=tags\n\t\telse\n\t\t\tlocal dir=\"$(__gitdir)\"\n\t\t\tif test -r \"$dir\"/tags; then\n\t\t\t\ttagsfile=\"$dir\"/tags\n\t\t\tfi\n\t\tfi\n\t\tif [ -n \"tagsfile\" ]; then\n\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" \"$tagsfile\")\"\n\t\t\treturn\n\t\tfi\n\n\nBtw, there is a bug in the case statement: 'git --no-pager grep <TAB>'\noffers refs instead of symbols, because $cword is not 2 and $prev\ndoesn't start with a dash.  But it's not worse than the current\nbehavior, so I don't think this bug is a show-stopper for the patch.\n\n\nBest,\nGábor\n"},{"id":"178398","messageId":"20111028060517.GA3993@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111023212928.GG22551@goldbirke","subject":"Re: [PATCHv2 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-28T06:05:20Z","receivedAt":"2011-10-28T06:05:20Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Oct 23, 2011 at 11:29:28PM +0200, SZEDER Gábor wrote:\n\n> On Fri, Oct 21, 2011 at 01:30:21PM -0400, Jeff King wrote:\n> > This incorporates the suggestions from Gábor's review, with one\n> > exception: it still looks only in the current directory for the \"tags\"\n> > files. I think that might have some performance implications, so I'd\n> > rather add it separately, if at all.\n> \n> I agree that scanning through a whole working tree for tags files\n> would cost too much.  But I think that a tags file at the top of the\n> working tree is common enough to be supported, and checking its\n> existence is fairly cheap.\n\nActually, it's not too expensive. Asking git for the top of the working\ntree means it has to traverse up to there anyway. So the trick is just\ndoing our search without invoking too many external tools which would\ncause unnecessary forks.\n\nThe patch is below, but I'm still not sure it's a good idea.\n\nGrep only looks in the current subdirectory for matches. So if I am in\n\"src/foo/bar/\", and the tags file is in \"src/\", then is it really a good\nway to generate completions? Most of what's in the tags file will\nprobably be in _other_ subdirectories of \"src/\", and won't be matched by\ngrep at all. So we will give useless entries to bash to complete.\n\n> So how about something like this for the case arm? (I didn't actually\n> tested it.)\n> \n> \t\tlocal tagsfile\n> \t\tif test -r tags; then\n> \t\t\ttagsfile=tags\n> \t\telse\n> \t\t\tlocal dir=\"$(__gitdir)\"\n\nYou don't want __gitdir here, but rather \"git rev-parse --show-cdup\".\n\n> Btw, there is a bug in the case statement: 'git --no-pager grep <TAB>'\n> offers refs instead of symbols, because $cword is not 2 and $prev\n> doesn't start with a dash.  But it's not worse than the current\n> behavior, so I don't think this bug is a show-stopper for the patch.\n\nYeah. The intent of the \"$cword is 2\" thing is to know that we are the\nfirst non-option argument. Arguably, _get_comp_words_by_ref should\nsomehow tell us which position we are completing relative to the actual\ncommand name.\n\n-Peff\n\n---\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex af283cb..b0ed657 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1429,6 +1429,39 @@ _git_gitk ()\n \t_gitk\n }\n \n+__git_cdup_dirs() {\n+\tlocal prefix=$(git rev-parse --show-cdup 2>/dev/null)\n+\tlocal oldifs=$IFS\n+\tlocal dots\n+\tlocal i\n+\tIFS=/\n+\tfor i in $prefix; do\n+\t\tdots=$dots../\n+\t\techo \"$dots\"\n+\tdone\n+\tIFS=$oldifs\n+}\n+\n+__git_find_in_cdup_one() {\n+\tlocal dir=$1; shift\n+\tfor i in \"$@\"; do\n+\t\tif test -r \"$dir$i\"; then\n+\t\t\techo \"$dir$i\"\n+\t\t\treturn 0\n+\t\tfi\n+\tdone\n+\treturn 1\n+}\n+\n+__git_find_in_cdup() {\n+\t__git_find_in_cdup_one \"\" \"$@\" && return\n+\n+\tlocal dir\n+\tfor dir in $(__git_cdup_dirs); do\n+\t\t__git_find_in_cdup_one \"$dir\" \"$@\" && return\n+\tdone\n+}\n+\n __git_match_ctag() {\n \tawk \"/^${1////\\\\/}/ { print \\$1 }\" \"$2\"\n }\n@@ -1457,8 +1490,9 @@ _git_grep ()\n \n \tcase \"$cword,$prev\" in\n \t2,*|*,-*)\n-\t\tif test -r tags; then\n-\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" tags)\"\n+\t\tlocal tags=$(__git_find_in_cdup tags)\n+\t\tif test -n \"$tags\"; then\n+\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" \"$tags\")\"\n \t\t\treturn\n \t\tfi\n \t\t;;\n"},{"id":"178510","messageId":"20111029124755.GE2345@goldbirke","threadId":"28708","inReplyTo":"20111028060517.GA3993@sigill.intra.peff.net","subject":"Re: [PATCHv2 3/3] completion: match ctags symbol names in grep patterns","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2011-10-29T12:47:55Z","receivedAt":"2011-10-29T12:47:55Z","isPatch":false,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Hi,\n\n\nOn Thu, Oct 27, 2011 at 11:05:20PM -0700, Jeff King wrote:\n> On Sun, Oct 23, 2011 at 11:29:28PM +0200, SZEDER Gábor wrote:\n> \n> > On Fri, Oct 21, 2011 at 01:30:21PM -0400, Jeff King wrote:\n> > > This incorporates the suggestions from Gábor's review, with one\n> > > exception: it still looks only in the current directory for the \"tags\"\n> > > files. I think that might have some performance implications, so I'd\n> > > rather add it separately, if at all.\n> > \n> > I agree that scanning through a whole working tree for tags files\n> > would cost too much.  But I think that a tags file at the top of the\n> > working tree is common enough to be supported, and checking its\n> > existence is fairly cheap.\n> \n> Actually, it's not too expensive. Asking git for the top of the working\n> tree means it has to traverse up to there anyway. So the trick is just\n> doing our search without invoking too many external tools which would\n> cause unnecessary forks.\n> \n> The patch is below, but I'm still not sure it's a good idea.\n> \n> Grep only looks in the current subdirectory for matches.\n\nUnless the user explicitly specifies the path(s)...  But that comes at\nthe end of the command line, so the completion script could have no\nidea about it at the time of 'git grep <TAB>'.\n\n> > So how about something like this for the case arm? (I didn't actually\n> > tested it.)\n> > \n> > \t\tlocal tagsfile\n> > \t\tif test -r tags; then\n> > \t\t\ttagsfile=tags\n> > \t\telse\n> > \t\t\tlocal dir=\"$(__gitdir)\"\n> \n> You don't want __gitdir here, but rather \"git rev-parse --show-cdup\".\n\nOh, yes, indeed.\n\nBut there was a point in using __gitdir() here: it respects the\n--git-dir= option.  Which brings up the question: what\nshould 'git --git-dir=/some/where/.git grep <TAB>' offer?\n\nSo in the end I agree that it's not a good idea.\n\n> > Btw, there is a bug in the case statement: 'git --no-pager grep <TAB>'\n> > offers refs instead of symbols, because $cword is not 2 and $prev\n> > doesn't start with a dash.  But it's not worse than the current\n> > behavior, so I don't think this bug is a show-stopper for the patch.\n> \n> Yeah. The intent of the \"$cword is 2\" thing is to know that we are the\n> first non-option argument. Arguably, _get_comp_words_by_ref should\n> somehow tell us which position we are completing relative to the actual\n> command name.\n\n_get_comp_words_by_ref() is a general completion function, the purpose\nof which is to provide a bash-version-independent equivalent of\n$COMP_WORDS and $COMP_CWORD by working around the different word\nsplitting rules.  It doesn't know about git and its commands at all.\n\nBut there is the while loop in _git() that looks for the git command\n(among other things) on the command line, which could store the index\nof the command name in $words in a variable.  This variable could then\nbe used in that case statement (and probably in a couple of other\nplaces, too).\n\n\nBest,\nGábor\n\n\n> ---\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index af283cb..b0ed657 100755\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -1429,6 +1429,39 @@ _git_gitk ()\n>  \t_gitk\n>  }\n>  \n> +__git_cdup_dirs() {\n> +\tlocal prefix=$(git rev-parse --show-cdup 2>/dev/null)\n> +\tlocal oldifs=$IFS\n> +\tlocal dots\n> +\tlocal i\n> +\tIFS=/\n> +\tfor i in $prefix; do\n> +\t\tdots=$dots../\n> +\t\techo \"$dots\"\n> +\tdone\n> +\tIFS=$oldifs\n> +}\n\nNo need for $oldifs here; do a local IFS=/ instead, and then it just\ngoes out of scope when returning from the function.\n\n> +\n> +__git_find_in_cdup_one() {\n> +\tlocal dir=$1; shift\n> +\tfor i in \"$@\"; do\n> +\t\tif test -r \"$dir$i\"; then\n> +\t\t\techo \"$dir$i\"\n> +\t\t\treturn 0\n> +\t\tfi\n> +\tdone\n> +\treturn 1\n> +}\n> +\n> +__git_find_in_cdup() {\n> +\t__git_find_in_cdup_one \"\" \"$@\" && return\n> +\n> +\tlocal dir\n> +\tfor dir in $(__git_cdup_dirs); do\n> +\t\t__git_find_in_cdup_one \"$dir\" \"$@\" && return\n> +\tdone\n> +}\n> +\n>  __git_match_ctag() {\n>  \tawk \"/^${1////\\\\/}/ { print \\$1 }\" \"$2\"\n>  }\n> @@ -1457,8 +1490,9 @@ _git_grep ()\n>  \n>  \tcase \"$cword,$prev\" in\n>  \t2,*|*,-*)\n> -\t\tif test -r tags; then\n> -\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" tags)\"\n> +\t\tlocal tags=$(__git_find_in_cdup tags)\n> +\t\tif test -n \"$tags\"; then\n> +\t\t\t__gitcomp \"$(__git_match_ctag \"$cur\" \"$tags\")\"\n>  \t\t\treturn\n>  \t\tfi\n>  \t\t;;\n"},{"id":"178627","messageId":"20111101152148.GA5552@sigill.intra.peff.net","threadId":"28708","inReplyTo":"20111029124755.GE2345@goldbirke","subject":"Re: [PATCHv2 3/3] completion: match ctags symbol names in grep patterns","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-11-01T15:21:48Z","receivedAt":"2011-11-01T15:21:48Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Oct 29, 2011 at 02:47:55PM +0200, SZEDER Gábor wrote:\n\n> > Grep only looks in the current subdirectory for matches.\n> \n> Unless the user explicitly specifies the path(s)...  But that comes at\n> the end of the command line, so the completion script could have no\n> idea about it at the time of 'git grep <TAB>'.\n\nTrue. But that's a more general problem. You have a 'tags' file that\npresumably represents the working tree. But you are not necessarily\ngrepping there. You might be grepping something related (e.g., what's in\nthe index), which makes the tags file still a good guess.\n\nBut you might also be grepping some totally unrelated branch, in which\ncase this is not helpful.\n\nI tend to think that we are OK erring on the side of using the 'tags'\nfile, even if it might be wrong, since otherwise we have nothing to\ntab-complete. When the user hits <Tab>, they are asking us to make our\nbest guess, and if they know there is nothing to complete, they won't\nhit <Tab>. So it's not like we're hurting some existing workflow.\n\nAnd in that sense, maybe we should just do the \"search back up the\nworking tree\" thing. Sure, it may be return way more matches than are\naccurate, but even that's better than having no tab-completion at all.\n\n> > You don't want __gitdir here, but rather \"git rev-parse --show-cdup\".\n> \n> Oh, yes, indeed.\n> \n> But there was a point in using __gitdir() here: it respects the\n> --git-dir= option.  Which brings up the question: what\n> should 'git --git-dir=/some/where/.git grep <TAB>' offer?\n\nI guess if core.worktree is set, it would look there instead (and ditto\nfor specifying --work-tree on the command line).  Handling those is such\na corner case that I'm not too concerned if we don't. And if somebody\nreally cares, they can fix the completion later to pick up magic like\nthat from the early part of the command line. I don't see it as a\nblocker for an initial version of the patch.\n\n> _get_comp_words_by_ref() is a general completion function, the purpose\n> of which is to provide a bash-version-independent equivalent of\n> $COMP_WORDS and $COMP_CWORD by working around the different word\n> splitting rules.  It doesn't know about git and its commands at all.\n> \n> But there is the while loop in _git() that looks for the git command\n> (among other things) on the command line, which could store the index\n> of the command name in $words in a variable.  This variable could then\n> be used in that case statement (and probably in a couple of other\n> places, too).\n\nYeah, that makes sense. Again, my inclination is to just leave that for\na further patch if somebody really wants to make the completion (for\nthis and any other positional slots) more accurate.\n\n-Peff\n"},{"id":"178634","messageId":"7vipn3n203.fsf@alter.siamese.dyndns.org","threadId":"28708","inReplyTo":"20111101152148.GA5552@sigill.intra.peff.net","subject":"Re: [PATCHv2 3/3] completion: match ctags symbol names in grep patterns","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-11-01T18:14:52Z","receivedAt":"2011-11-01T18:14:52Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Yeah, that makes sense. Again, my inclination is to just leave that for\n> a further patch if somebody really wants to make the completion (for\n> this and any other positional slots) more accurate.\n\nI tend to agree with your inclination. Let's go with the current simple\nversion and see if real users want something different.\n"}]}