Skip to content

Commit 0973ace

Browse files
committed
LibGit2: expose the depth option to clone and fetch
why use many commits when few do trick?
1 parent ec5cf08 commit 0973ace

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

stdlib/LibGit2/src/LibGit2.jl

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,20 @@ 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 only supported for network protocols (http, https, git, ssh), not for local filesystem paths.
265269
* `credentials=nothing`: provides credentials and/or settings when authenticating against
266270
a private `remote`.
267271
* `callbacks=Callbacks()`: user provided callbacks and payloads.
268272
269-
Equivalent to `git fetch [<remoteurl>|<repo>] [<refspecs>]`.
273+
Equivalent to `git fetch [--depth <depth>] [<remoteurl>|<repo>] [<refspecs>]`.
270274
"""
271275
function fetch(repo::GitRepo; remote::AbstractString="origin",
272276
remoteurl::AbstractString="",
273277
refspecs::Vector{<:AbstractString}=AbstractString[],
278+
depth::Integer=0,
274279
credentials::Creds=nothing,
275280
callbacks::Callbacks=Callbacks())
276281
rmt = if isempty(remoteurl)
@@ -290,7 +295,12 @@ function fetch(repo::GitRepo; remote::AbstractString="origin",
290295

291296
result = try
292297
remote_callbacks = RemoteCallbacks(callbacks)
293-
fo = FetchOptions(callbacks=remote_callbacks)
298+
@static if LibGit2.VERSION >= v"1.7.0"
299+
fo = FetchOptions(callbacks=remote_callbacks, depth=Cuint(depth))
300+
else
301+
depth != 0 && throw(ArgumentError("Depth parameter for fetch requires libgit2 >= 1.7.0"))
302+
fo = FetchOptions(callbacks=remote_callbacks)
303+
end
294304
fetch(rmt, refspecs, msg="from $(url(rmt))", options=fo)
295305
catch err
296306
if isa(err, GitError) && err.code === Error.EAUTH
@@ -539,11 +549,15 @@ The keyword arguments are:
539549
* `remote_cb::Ptr{Cvoid}=C_NULL`: a callback which will be used to create the remote
540550
before it is cloned. If `C_NULL` (the default), no attempt will be made to create
541551
the remote - it will be assumed to already exist.
552+
* `depth::Integer=0`: create a shallow clone with a history truncated to the
553+
specified number of commits. `0` indicates a full clone (the default).
554+
Use `Consts.FETCH_DEPTH_UNSHALLOW` to fetch all missing data from a shallow clone.
555+
Note: shallow clones are only supported for network protocols (http, https, git, ssh), not for local filesystem paths.
542556
* `credentials::Creds=nothing`: provides credentials and/or settings when authenticating
543557
against a private repository.
544558
* `callbacks::Callbacks=Callbacks()`: user provided callbacks and payloads.
545559
546-
Equivalent to `git clone [-b <branch>] [--bare] <repo_url> <repo_path>`.
560+
Equivalent to `git clone [-b <branch>] [--bare] [--depth <depth>] <repo_url> <repo_path>`.
547561
548562
# Examples
549563
```julia
@@ -552,12 +566,15 @@ repo1 = LibGit2.clone(repo_url, "test_path")
552566
repo2 = LibGit2.clone(repo_url, "test_path", isbare=true)
553567
julia_url = "https://github.com/JuliaLang/julia"
554568
julia_repo = LibGit2.clone(julia_url, "julia_path", branch="release-0.6")
569+
# Shallow clone with only the most recent commit
570+
shallow_repo = LibGit2.clone(repo_url, "shallow_path", depth=1)
555571
```
556572
"""
557573
function clone(repo_url::AbstractString, repo_path::AbstractString;
558574
branch::AbstractString="",
559575
isbare::Bool = false,
560576
remote_cb::Ptr{Cvoid} = C_NULL,
577+
depth::Integer = 0,
561578
credentials::Creds=nothing,
562579
callbacks::Callbacks=Callbacks())
563580
cred_payload = reset!(CredentialPayload(credentials))
@@ -573,7 +590,12 @@ function clone(repo_url::AbstractString, repo_path::AbstractString;
573590
lbranch = Base.cconvert(Cstring, branch)
574591
GC.@preserve lbranch begin
575592
remote_callbacks = RemoteCallbacks(callbacks)
576-
fetch_opts = FetchOptions(callbacks=remote_callbacks)
593+
@static if LibGit2.VERSION >= v"1.7.0"
594+
fetch_opts = FetchOptions(callbacks=remote_callbacks, depth=Cuint(depth))
595+
else
596+
depth != 0 && throw(ArgumentError("Shallow clone (depth parameter) requires libgit2 >= 1.7.0"))
597+
fetch_opts = FetchOptions(callbacks=remote_callbacks)
598+
end
577599
clone_opts = CloneOptions(
578600
bare = Cint(isbare),
579601
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)