wfxr / forgit

:zzz: A utility tool powered by fzf for using git interactively.
MIT License
4.32k stars 136 forks source link

Issues with special characters in filenames #325

Closed misaflo closed 1 month ago

misaflo commented 8 months ago

Check list

Environment info

Problem / Steps to reproduce

git clone https://github.com/wfxr/forgit.git
cd forgit
echo "hello world" > my_filé

Git add with ga does not work

fatal: pathspec 'my_fil\303\251' did not match any files
Nothing to add.

Add the file manually and commit:

git add my_filé
git commit -m "add file"

Try to view log with glo, it works. Then press "enter" in this commit, it show empty screen for the file "my_fil\303\251".

sandr01d commented 8 months ago

Git escapes paths by default, leading to the described behavior. You can disable this with git config core.quotePath false. Afterwards you should be able to work with the file you mentioned in forgit. For more details, see the git documentation on core.quotePath. Let me know if that fixes the issue for you.

misaflo commented 8 months ago

Yes, thanks!

Is it easy to fix it in forgit? If not, it may be usefull to add this workaround in the README.

sandr01d commented 8 months ago

It does not appear to be a super easy fix, but seems doable. I'll leave this issue open and will take a closer look once I find the time if nobody beats me to it. You are of course also more than welcome to send in a PR to fix the issue, if you like to. Note to myself and anybody trying to solve this:

git has a -z option for many commands that prevents escaping. Unfortunately it appears to also disable colored output which we make use of in _forgit_add.

sandr01d commented 5 months ago

Looking further into this, I see the following options:

  1. Add a _forgit_git function that simply runs git with the core.quotePath option set to false like this
    _forgit_git() {
    git -c core.quotePath=false "$@"
    }

    and replace all git calls with the function. This would also allow to quickly configure other git behavior for all functions, but is tedious.

  2. Set the option before running any forgit function and reset it afterwards:
old_quote=$(git config core.quotePath)
git config core.quotePath false
_forgit_"${cmd}" "$@"
git config core.quotePath "$old_quote"

This is a bit ugly, but should work reliably and is the smallest change.

  1. Leave the current behavior as is and add it to the documentation.

I think I would prefer option 1. Would be interested in other peoples ideas/preferred approach. Any suggestions @carlfriedrich @cjappl?

carlfriedrich commented 5 months ago

Thanks for digging into this @sandr01d. Solution 2 definitely seems ugly.

I haven't understood, yet, why this happens in forgit but not with git directly. Where is the difference? We're calling git as well, so why does it behave differently?

sandr01d commented 5 months ago

I haven't understood, yet, why this happens in forgit but not with git directly. Where is the difference? We're calling git as well, so why does it behave differently?

When core.quotePath is set to unset or true, git escapes "unusual" file names in its output, but does not expect to receive quoted file names as input. The issue then arises when we consume quoted file nams from git and feed it back into other git commands, as we do in _forgit_add where we consume output from git status and feed it back into git add.

carlfriedrich commented 5 months ago

I see, thanks for the explanation. That makes sense and should definitely go into a comment for why we are doing this. And in this case I would also prefer option 1.