Cannot push Git commits by LibGit2

I am trying to write a script that commits changes in files and pushes them to the upstream using LibGit2, but push() is not working.

I am able to create a LibGit2.GitRepo, add changes to it, and commit the changes by

repo = LibGit2.GitRepo(repo_path)
LibGit2.add!(repo, ".")
LibGit2.commit(repo, "Commit message")

git log in the terminal confirms that the commit is correctly created with the commit message.

Then, if I attempt to push the commit by

LibGit2.push(repo)

I get the following error:

SSH host verification: the identity of the server `<URL of my organization's GitHub Enterprise>:22` does not match its known hosts record. Someone could be trying to man-in-the-middle your connection. It is also possible that the server has changed its key, in which case you should check with the server administrator and if they confirm that the key has been changed, update your known hosts file.
ERROR: GitError(Code:ERROR, Class:Net, user cancelled hostkey check)
Stacktrace:
 [1] macro expansion
   @ ~/pkg/julia/julia-1.9/usr/share/julia/stdlib/v1.9/LibGit2/src/error.jl:111 [inlined]
 [2] push(rmt::LibGit2.GitRemote, refspecs::Vector{AbstractString}; force::Bool, options::LibGit2.PushOptions)
   @ LibGit2 ~/pkg/julia/julia-1.9/usr/share/julia/stdlib/v1.9/LibGit2/src/remote.jl:324
 [3] push
   @ ~/pkg/julia/julia-1.9/usr/share/julia/stdlib/v1.9/LibGit2/src/remote.jl:321 [inlined]
 [4] push(repo::GitRepo; remote::String, remoteurl::String, refspecs::Vector{AbstractString}, force::Bool, credentials::Nothing, callbacks::Dict{Symbol, Tuple{Ptr{Nothing}, Any}})
   @ LibGit2 ~/pkg/julia/julia-1.9/usr/share/julia/stdlib/v1.9/LibGit2/src/LibGit2.jl:349
 [5] push(repo::GitRepo)
   @ LibGit2 ~/pkg/julia/julia-1.9/usr/share/julia/stdlib/v1.9/LibGit2/src/LibGit2.jl:325
[...]

This is odd, because I can git push from the terminal without any issue.

I’m wondering if anyone knows a solution to this problem. The Julia version is 1.9.3.

Just a guess:
There is a known_hosts file in ...\share\julia\stdlib\v1.9\LibGit2\test\
You may search for it in your HOME\.julia folder.
Perhaps there is a wrong or old server key in this file for your remote github/lab server. You can delete the line and try again.
Typically, the file known_hosts is in HOME\.ssh\known_hosts and stores the public keys of your remote servers you are connecting via ssh.

I don’t know the answer but generally I would recommend using an external git rather than LibGit2. If you need it to work on computers where you don’t know if git is installed you can use the Git package.

4 Likes

@oheil, I am able to find a known_hosts file at ~/pkg/julia/julia-1.9/stdlib/LibGit2/test/known_hosts. But I guess this is only the file used during test, as the name of the directory suggests. Even if I replace it with .ssh/known_hosts, I get the same error.

@GunnarFarneback, I’m wary of using the Git package because it hasn’t been updated for last two years. LibGit2 is already included in Julia and is supposed to provide the functions I need, so it will be nice to achieve what I want using LibGit2.

Funny, the last commit I see in GitHub - JuliaVersionControl/Git.jl: Use command-line Git in your Julia packages is from last February.

“supposed” being the key word here: libgit2 is not a fully-equivalent replacement of CLI git.

1 Like

Sorry, my recollection was about the GitREPL package, not Git.

If I don’t find a solution eventually, I will give the Git package a try.

I found a related discussion. The person says libgit2 does not verify hosts, so s/he had to do it using libssh2.

I also find that pushing using libgit2 uses push options: c - How to push (with libgit2) - Stack Overflow. I’m wondering if I need to set LibGit2.PushOptions.

I found a solution. First, in order to use LibGit2, I had to have a properly generated SSH private–public key pair. I describe the procedure here, which is hugely helped by @GunnarFarneback’s analysis on the LibGit2-related issue.

Then, I was able to push commits to the remote Git hosting service simply by

LibGit2.push(repo; refspecs=["refs/heads/main"])

where main in "refs/heads/main" is my Git branch name to push.

1 Like