Skip to content

Commit d484e19

Browse files
authored
LibGit2: expose the depth option to clone and fetch (#60024)
1 parent dd80509 commit d484e19

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

stdlib/LibGit2/src/LibGit2.jl

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,21 @@ The keyword arguments are:
262262
* `remoteurl::AbstractString=""`: the URL of `remote`. If not specified,
263263
will be assumed based on the given name of `remote`.
264264
* `refspecs=AbstractString[]`: determines properties of the fetch.
265+
* `depth::Integer=0`: limit fetching to the specified number of commits from the tip
266+
of each remote branch. `0` indicates a full fetch (the default).
267+
Use `Consts.FETCH_DEPTH_UNSHALLOW` to fetch all missing data from a shallow clone.
268+
Note: depth is, at the time of writing, only supported for network protocols (http, https, git, ssh), not for local filesystem paths.
269+
(https://github.com/libgit2/libgit2/issues/6634)
265270
* `credentials=nothing`: provides credentials and/or settings when authenticating against
266271
a private `remote`.
267272
* `callbacks=Callbacks()`: user provided callbacks and payloads.
268273
269-
Equivalent to `git fetch [<remoteurl>|<repo>] [<refspecs>]`.
274+
Equivalent to `git fetch [--depth <depth>] [<remoteurl>|<repo>] [<refspecs>]`.
270275
"""
271276
function fetch(repo::GitRepo; remote::AbstractString="origin",
272277
remoteurl::AbstractString="",
273278
refspecs::Vector{<:AbstractString}=AbstractString[],
279+
depth::Integer=0,
274280
credentials::Creds=nothing,
275281
callbacks::Callbacks=Callbacks())
276282
rmt = if isempty(remoteurl)
@@ -290,7 +296,12 @@ function fetch(repo::GitRepo; remote::AbstractString="origin",
290296

291297
result = try
292298
remote_callbacks = RemoteCallbacks(callbacks)
293-
fo = FetchOptions(callbacks=remote_callbacks)
299+
@static if LibGit2.VERSION >= v"1.7.0"
300+
fo = FetchOptions(callbacks=remote_callbacks, depth=Cuint(depth))
301+
else
302+
depth != 0 && throw(ArgumentError("Depth parameter for fetch requires libgit2 >= 1.7.0"))
303+
fo = FetchOptions(callbacks=remote_callbacks)
304+
end
294305
fetch(rmt, refspecs, msg="from $(url(rmt))", options=fo)
295306
catch err
296307
if isa(err, GitError) && err.code === Error.EAUTH
@@ -539,11 +550,16 @@ The keyword arguments are:
539550
* `remote_cb::Ptr{Cvoid}=C_NULL`: a callback which will be used to create the remote
540551
before it is cloned. If `C_NULL` (the default), no attempt will be made to create
541552
the remote - it will be assumed to already exist.
553+
* `depth::Integer=0`: create a shallow clone with a history truncated to the
554+
specified number of commits. `0` indicates a full clone (the default).
555+
Use `Consts.FETCH_DEPTH_UNSHALLOW` to fetch all missing data from a shallow clone.
556+
Note: shallow clones are, at the time of writing, only supported for network protocols (http, https, git, ssh), not for local filesystem paths.
557+
(https://github.com/libgit2/libgit2/issues/6634)
542558
* `credentials::Creds=nothing`: provides credentials and/or settings when authenticating
543559
against a private repository.
544560
* `callbacks::Callbacks=Callbacks()`: user provided callbacks and payloads.
545561
546-
Equivalent to `git clone [-b <branch>] [--bare] <repo_url> <repo_path>`.
562+
Equivalent to `git clone [-b <branch>] [--bare] [--depth <depth>] <repo_url> <repo_path>`.
547563
548564
# Examples
549565
```julia
@@ -552,12 +568,15 @@ repo1 = LibGit2.clone(repo_url, "test_path")
552568
repo2 = LibGit2.clone(repo_url, "test_path", isbare=true)
553569
julia_url = "https://github.com/JuliaLang/julia"
554570
julia_repo = LibGit2.clone(julia_url, "julia_path", branch="release-0.6")
571+
# Shallow clone with only the most recent commit
572+
shallow_repo = LibGit2.clone(repo_url, "shallow_path", depth=1)
555573
```
556574
"""
557575
function clone(repo_url::AbstractString, repo_path::AbstractString;
558576
branch::AbstractString="",
559577
isbare::Bool = false,
560578
remote_cb::Ptr{Cvoid} = C_NULL,
579+
depth::Integer = 0,
561580
credentials::Creds=nothing,
562581
callbacks::Callbacks=Callbacks())
563582
cred_payload = reset!(CredentialPayload(credentials))
@@ -573,7 +592,12 @@ function clone(repo_url::AbstractString, repo_path::AbstractString;
573592
lbranch = Base.cconvert(Cstring, branch)
574593
GC.@preserve lbranch begin
575594
remote_callbacks = RemoteCallbacks(callbacks)
576-
fetch_opts = FetchOptions(callbacks=remote_callbacks)
595+
@static if LibGit2.VERSION >= v"1.7.0"
596+
fetch_opts = FetchOptions(callbacks=remote_callbacks, depth=Cuint(depth))
597+
else
598+
depth != 0 && throw(ArgumentError("Shallow clone (depth parameter) requires libgit2 >= 1.7.0"))
599+
fetch_opts = FetchOptions(callbacks=remote_callbacks)
600+
end
577601
clone_opts = CloneOptions(
578602
bare = Cint(isbare),
579603
checkout_branch = isempty(lbranch) ? Cstring(C_NULL) : Base.unsafe_convert(Cstring, lbranch),

stdlib/LibGit2/src/repository.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,27 @@ function isattached(repo::GitRepo)
112112
ccall((:git_repository_head_detached, libgit2), Cint, (Ptr{Cvoid},), repo) != 1
113113
end
114114

115+
"""
116+
isshallow(repo::GitRepo)::Bool
117+
118+
Determine if `repo` is a shallow clone. A shallow clone has a truncated history,
119+
created by cloning with a specific depth (e.g., `LibGit2.clone(url, path, depth=1)`).
120+
121+
# Examples
122+
```julia
123+
shallow_repo = LibGit2.clone(url, "shallow_path", depth=1)
124+
LibGit2.isshallow(shallow_repo) # returns true
125+
126+
normal_repo = LibGit2.clone(url, "normal_path")
127+
LibGit2.isshallow(normal_repo) # returns false
128+
```
129+
"""
130+
function isshallow(repo::GitRepo)
131+
ensure_initialized()
132+
@assert repo.ptr != C_NULL
133+
ccall((:git_repository_is_shallow, libgit2), Cint, (Ptr{Cvoid},), repo) == 1
134+
end
135+
115136
@doc """
116137
GitObject(repo::GitRepo, hash::AbstractGitHash)
117138
GitObject(repo::GitRepo, spec::AbstractString)

stdlib/LibGit2/test/libgit2-tests.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,23 @@ mktempdir() do dir
744744
cred_payload = LibGit2.CredentialPayload()
745745
@test_throws ArgumentError LibGit2.clone(cache_repo, test_repo, callbacks=callbacks, credentials=cred_payload)
746746
end
747+
@testset "shallow clone" begin
748+
@static if LibGit2.VERSION >= v"1.7.0"
749+
# Note: Shallow clones are not supported with local file:// transport
750+
# This is a limitation in libgit2 - shallow clones only work with
751+
# network protocols (http, https, git, ssh)
752+
# See online-tests.jl for tests with remote repositories
753+
754+
# Test normal clone is not shallow
755+
normal_path = joinpath(dir, "Example.NotShallow")
756+
LibGit2.with(LibGit2.clone(cache_repo, normal_path)) do repo
757+
@test !LibGit2.isshallow(repo)
758+
end
759+
else
760+
# Test that depth parameter throws error on older libgit2
761+
@test_throws ArgumentError LibGit2.clone(cache_repo, joinpath(dir, "Example.Shallow"), depth=1)
762+
end
763+
end
747764
end
748765

749766
@testset "Update cache repository" begin

stdlib/LibGit2/test/online-tests.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,22 @@ mktempdir() do dir
8787
@test ex.code == LibGit2.Error.EAUTH
8888
end
8989
end
90+
91+
@testset "Shallow clone" begin
92+
@static if LibGit2.VERSION >= v"1.7.0"
93+
# Test shallow clone with depth=1
94+
repo_path = joinpath(dir, "Example.Shallow")
95+
c = LibGit2.CredentialPayload(allow_prompt=false, allow_git_helpers=false)
96+
repo = LibGit2.clone(repo_url, repo_path, depth=1, credentials=c)
97+
try
98+
@test isdir(repo_path)
99+
@test isdir(joinpath(repo_path, ".git"))
100+
@test LibGit2.isshallow(repo)
101+
finally
102+
close(repo)
103+
end
104+
end
105+
end
90106
end
91107
end
92108

0 commit comments

Comments
 (0)