Open nixpulvis opened 5 months ago
For context: xcode ships some terrible shims that take ages to set up so the first git
call takes ages.
We kick off git in the background and then check if the xcrun cache-path exists to determine whether it's set up or not.
Apparently that got changed so that check is no longer working - wouldn't be the first time apple broke something around us (see the apropos saga).
I have no idea what the correct check now is and I don't have a mac to check, so I'm not going to be of help here.
My recommendation for now is to install a git outside of xcode and let that take precedence in $PATH.
For posterity and reference, can you do a which git
, ldd git
, and find / -samefile (which git)
and share the outputs?
Make that command -s git
and find / -samefile (command -s git)
@mqudsi
$ command -s git
/usr/bin/git
$ otool -L (command -s git)
/usr/bin/git:
/usr/lib/libxcselect.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.120.2)
$ find / -samefile (command -s git)
/usr/bin/indent
/usr/bin/xml2man
/usr/bin/gcov
/usr/bin/g++
/usr/bin/libtool
/usr/bin/Rez
/usr/bin/ctags
/usr/bin/c++
/usr/bin/strings
/usr/bin/gm4
/usr/bin/clang
/usr/bin/git-receive-pack
/usr/bin/objdump
/usr/bin/c99
/usr/bin/c++filt
/usr/bin/strip
/usr/bin/python3
/usr/bin/clangd
/usr/bin/lex
/usr/bin/ctf_insert
/usr/bin/sourcekit-lsp
/usr/bin/pip3
/usr/bin/ld
/usr/bin/lldb
/usr/bin/pagestuff
/usr/bin/headerdoc2html
/usr/bin/hdxml2manxml
/usr/bin/resolveLinks
/usr/bin/git-upload-archive
/usr/bin/gcc
/usr/bin/segedit
/usr/bin/dwarfdump
/usr/bin/gperf
/usr/bin/vtool
/usr/bin/dsymutil
/usr/bin/SplitForks
/usr/bin/rpcgen
/usr/bin/otool
/usr/bin/DeRez
/usr/bin/codesign_allocate
/usr/bin/cpp
/usr/bin/swift
/usr/bin/make
/usr/bin/nm
/usr/bin/flex++
/usr/bin/llvm-gcc
/usr/bin/ar
/usr/bin/unifdef
/usr/bin/lipo
/usr/bin/clang++
/usr/bin/m4
/usr/bin/asa
/usr/bin/swiftc
/usr/bin/as
/usr/bin/gnumake
/usr/bin/ResMerger
/usr/bin/bm4
/usr/bin/git-shell
/usr/bin/cc
/usr/bin/unifdefall
/usr/bin/size
/usr/bin/llvm-g++
/usr/bin/yacc
/usr/bin/c89
/usr/bin/git-upload-pack
/usr/bin/lorder
/usr/bin/ranlib
/usr/bin/flex
/usr/bin/SetFile
/usr/bin/nmedit
/usr/bin/bison
/usr/bin/mig
/usr/bin/GetFileInfo
/usr/bin/git
/usr/bin/install_name_tool
/usr/bin/cmpdylib
/usr/bin/gatherheaderdoc
...
Ok, we're in luck and as I suspected it's a hard link to a single binary that does this for a lot of other stuff.
Can you post the un-truncated list of find
output as an attachment?
Also, please attach the full profile so we can see in which order the commands are executed and how long specific git invocations take.
I don't think my truncation missed anything, I simply stopped the find
once it started returning permission errors searching folders this user doesn't have access to.
And here's the full profile: https://paste.rs/vBWhf.txt
Ok, thanks.
Going through the profile, it seems that the logic behind a77bc70defd47db9c401127465d7e71d05184200 no longer holds up. Specifically, we kick off a backgrounded git --version
task, but then the first time we run xcrun --show-cache-path
it returns something that passes the path is ...
check. We take that to mean that the cache has been populated and subsequent git
invocations will be quick, but immediately thereafter when we try to use git rev-parse ...
for real, it hangs for 12 seconds. Subsequent invocations are much faster, so it's not probably it's because the cache isn't being used; meaning most likely our assumption that xcrun --show-cache-path
returning a valid path implies a git
invocation will be quick is incorrect.
I don't see why we need to do this dance with xcrun
at all; maybe it's only because we can't background fish functions? It's an ugly hack, but instead of backgrounding git --version
then checking/waiting for xcrun --show-cache-path
to return a valid path, why don't we just do the following:
function __fish_is_git_ready
# Specifically use /tmp/ because that's where the xcrun cache is stored and
# it is cleared on startup. We have no guarantee that our normal fish temp
# directory would be cleared on startup.
if ! path is /tmp/__fish_git_xcrun_primed
# Ignore this race condition; it's unlikely to happen and OK if it does
if ! path is /tmp/__fish_git_xcrun_started
touch /tmp/__fish_git_xcrun_started
sh -c 'git --version && touch /tmp/__fish_git_xcrun_primed' &
disown
end
return 1
end
functions -e __fish_is_git_ready
return 0
end
# In fish_git_prompt:
# if Darwin
if functions -q __fish_is_git_ready && not __fish_is_git_ready
return 1
end
# endif
# Carry on
Would using gitoxide to access the repository directly, instead of calling the git binary, help here?
A new dependency is out of the question, as is the work necessary to make it accessible to scripts in a way that the git prompt can get all the info it needs.
People on macOS can already install git outside of xcode.
From what I can tell, on macOS 15 (Sequoia), installing the developer tools also eagerly populates the xcrun path, so that xcrun --show-cache-path
has a path and git
does not take multiple seconds to run.
I will try on 14.5 as well though I'm not sure how many heroics we want to go through this round.
@ridiculousfish I'm running 14.6.1 at the moment. Let me know if I can help test/debug anything.
Ok I'm able to reproduce this. Simple way is to use xcrun --kill-cache
and then it reproduces - approximately a six second hang.
What's changed is that the cache file is now created eagerly, but populated lazily:
function __fish_git_prompt_ready
path is (xcrun --show-cache-path 2>/dev/null) || return 1
# git is ready, erase the function.
functions -e __fish_git_prompt_ready
return 0
end
xcrun --show-cache-path
now returns a real path with a real file even though it hasn't cached git yet.
The ideal fix is to ask xcrun
if git is cached, but I'm not sure there's an option for that. One very hacky possibility is to look for git
in the cache, but that seems quite fragile. A third possibility is to do nothing: this will only reproduce on Macs which have the CLI tools installed but they have not yet run.
@nixpulvis can you confirm this only happens the first time you run git? That is, fish may hang for a few seconds on its first run, if you have never run git before; and after that new launches of fish are fast? We may be able to live with that.
Oh it will affect a fresh boot. That makes sense. So it will happen more often than once.
I haven't thought of something better than @mqudsi 's suggestion
This seems like a regression of the solution to #6625 but I'm not 100% sure.
I've restarted with
-p
enabled and the largest time is spent in these calls:I'm happy to try some other debugging steps if you let me know how I can help.