vim-gitgutter
                                
                                
                                
                                    vim-gitgutter copied to clipboard
                            
                            
                            
                        vim-gitgutter highlights incorrect lines when files are transformed via filter
Hi All,
In the same vein as #435, I am using a filter to convert files as they enter/leave GIT. This results in git-gutter highlighting almost everything in the file as changed.
The conversion I am doing results in the file in git looking quite different, however git-diff is unaffected.
I have edited the file gitgutter/diff/diff.vim to add the option --textconv to the 'git show' command, thus
ensuring all text conversion which diff would normally see is performed on the file before being returned for
vim-gitgutter to process.
Is there a downside to using --textconv in this way?   I understand it might be a new option compared to what was available when answering #435.  Would making it the default behaviour be a reasonable choice?
Thanks
I've never used filters so I don't know how they work in any great detail.
When you use --textconv are the line numbers in the git-diff output correct for the vim buffer?
For this reason, only git diff and the git log family of commands (i.e., log, whatchanged, show) will perform text conversion
– Performing text diffs of binary files
It sounds like it might not be possible to stage / undo hunks.
When you use --textconv are the line numbers in the git-diff output correct for the vim buffer?
Yes.   The logic is that GIT performs a text conversion when you first check out the file, and performs that conversion in the background when calling git-diff.  The output of git show --textconv is exactly what you get when you checkout the file.
It sounds like it might not be possible to stage / undo hunks.
This.  A "patch" prepared from the "smudged" copies cannot be applied.   Git will "clean" the working file and diff that with the existing blob when staging hunks.  Even git add -p doesn't work as expected.
Unfiltered files are unaffected by this.
I'm just happy that the file changes highlight correctly and it allows me to use ]c and [c to navigate changes.
That's all good to know.
Do you have steps for setting up a simple filter so I can experiment please?
I put together a contrived example using gitattributes and filters.
https://github.com/systemmonkey42/attribute-test
This uses two filters
bash.1 - filtered via "base64", hence the contents of GIT are completely different to what you see after checkout
bash.2 - filtered via "rev". The contents in git are the same length, same number of lines, same number of characters, each line of text is simply reversed.
As i said, contrived. But it should help demonstrate what is going on.
Hint:  use export GIT_TRACE=1 to confirm git is actually running the filters on each command.
Please refer to the README in the repository for instructions on enabling the filters. A feature of GIT is that the configuration changes required for filters to work cannot be part of the repository itself. For security reasons of course.
Thanks for this, much appreciated. I'll take a look as soon as I get some time.
Almost two years goes by...
Your demo repo is very helpful. I'm not sure I have set it up correctly – please see https://github.com/systemmonkey42/attribute-test/issues/1.
Anyway, it looks like adding --textconv to git-show was the only change you needed for this:
https://github.com/airblade/vim-gitgutter/compare/master...systemmonkey42:vim-gitgutter:master
Have you found any downsides over the past couple of years?
I was thinking it would be nice to detect when text conversion filters are active on a file so that gitgutter can disable the hunk staging.  The only way I can see to determine this is to parse .gitattributes and compare to the filename in question, which sounds a little fiddly.
Your demo repo is very helpful. I'm not sure I have set it up correctly – please see
I believe you set it up correctly. Git can behave a little strangely if the attributes are set up after checkout, because the index/stage/worktree get out of sync.
My reply shows a few workarounds, my favourite being "git update-index" because it almost always straightens out the mess.
Have you found any downsides over the past couple of years?
Apart from an inability to stage patches, it has all worked perfectly.
I agree detecting if a "filter" is in play, and showing an error for "stage" and "revert" commands will be the best option. Everything else works perfectly.
Also, git has a core function for checking attributes. You probably want the following:
$ git check-attr filter -- bash.2
bash.2: filter: rev
vs
A file with no filter attribute:
$ git check-attr filter -- install.sh
install.sh: filter: unspecified
You can also use git check-attr -a and just filter for the "filter" keyword, though technically any attribute (such as eol=crlf, or -text, etc) might have an impact on staging hunks...
I agree detecting if a "filter" is in play, and showing an error for "stage" and "revert" commands will be the best option. Everything else works perfectly.
Thinking about this, a File uses filter. Stage entire file? prompt allowing me to effectively git add <file> might be a nice to have.
You can also use
git check-attr -aand just filter for the "filter" keyword, though technically any attribute (such aseol=crlf, or-text, etc) might have an impact on staging hunks...
I think I'll look for "filter", ignore the rest, and hope for the best. GitGutter already tries to deal with line endings and it seems to work, in that nobody has opened an issue about it.
I found this interesting comment:
I have confirmed that
git applydoes not operate on the smudged (decrypted) versions of files, but rather on the clean (encrypted) versions of files. That means that the patch you apply needs to contain binary diffs of the encrypted files' ciphertexts, rather than their plaintexts. Such a diff can be generated by passing--no-textconv --binarytogit diff.
I wonder if it might be possible to stage hunks for a filtered file by generating the diff as per the comment. I just tried it and it seemed to work. I'll push up a branch shortly for you to try.
(Undoing a hunk doesn't use the index so it works anyway.)
Ah, it works when there is only one hunk. If there are, say, two, the binary diff still shows a single change. Which makes sense. So we can only stage the whole file, not part of it, as we originally thought.
Thinking about this, a "File uses filter. Stage entire file?" prompt allowing me to effectively
git add <file>might be a nice to have.
It does this now. Please try it out and let me know if it solves your problem.
Hi, Thanks for that.
I get the message File uses clean/smudge filter. Stage entire file (y/n)?
However after I choose "y", I get Patch does not apply
I tried to set g:gitgutter_log=1, but that results in
Error detected while processing function <lambda>2[1]..gitgutter#process_buffer[33]..function <lambda>2[1]..gitgutter#process_buffer[23]..script /root/.vim/pack/bundles/opt/vim-gitgutter/autoload/gitgutter/diff.v
im[13]..function <SNR>271_git_supports_command_line_config_override[1]..gitgutter#utility#system[1]..gitgutter#debug#log:
line    8:
E930: Cannot use :redir inside execute()
Edit: ignore that. gitgutter debug logging doesn't mix with YouCompleteMe. Disabled YouCompleteme for now.
Edit2:  The issue appears to be the command generated is
cd /home/user/git/erd/template/default/app && git  add template/default/app/app.conf which reads as
cd <absolute-path-to-file> && git  add <git-relative-path-to-file>
The specific git error is simply
warning: could not open directory 'template/default/app': No such file or directory
fatal: pathspec template/default/app/app.conf did not match any files
Either cd to $GIT_DIR, and add the full relative path to the file (preferred), or
cd to <absolute-path-to-file>, and add the base filename..
I tried to "cd" to the directory containing the file, and edit it from there, but gitgutter still generated full paths.
I have fixed the logging in 621b9e7.
Thanks for diagnosing the path problem. I hadn't noticed that when testing with your demo repo because the files are in the root directory.
GitGutter always changes to a file's directory when running commands to ensure that git figures out the correct repo.  I have updated the code (7d425ff) to run cd /repo/path/to && git add file instead of cd /repo/path/to && git add path/to/file.
That worked.   I can now apply changes in filtered files without resorting to !git add %  :)
I'll use this for a while and see if I have any issues.
Thanks.
Thanks for your patience :)