Skip to content

Commit 2b4561e

Browse files
Add depth to git_clone() (#281)
1 parent a407a09 commit 2b4561e

6 files changed

Lines changed: 61 additions & 3 deletions

File tree

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Use `NEWS.md` instead of `NEWS` (@olivroy, #209)
1414
- Add git_revert() function (#206)
1515
- new function `git_branch_switch()`, an alias to `git_branch_checkout()` (#254)
16+
- Add argument `depth` in `git_clone()` (#281, @etiennebacher).
1617

1718
# 2.3.1
1819

R/fetch.R

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ git_push <- function(
183183
#' @param password a string or a callback function to get passwords for authentication
184184
#' or password protected ssh keys. Defaults to [askpass][askpass::askpass()] which
185185
#' checks `getOption('askpass')`.
186+
#' @param depth number of commits to fetch when creating a shallow clone. The
187+
#' default `0` clones the entire history. A positive value truncates the history
188+
#' to the given number of commits from the tip of each branch. Requires
189+
#' libgit2 >= 1.7.0.
186190
#' @param verbose display some progress info while downloading
187191
#' @examples {# Clone a small repository
188192
#' git_dir <- file.path(tempdir(), 'antiword')
@@ -220,6 +224,7 @@ git_clone <- function(
220224
ssh_key = NULL,
221225
bare = FALSE,
222226
mirror = FALSE,
227+
depth = 0,
223228
verbose = interactive()
224229
) {
225230
stopifnot(is.character(url))
@@ -233,6 +238,12 @@ git_clone <- function(
233238
}
234239
stopifnot(is.character(path))
235240
stopifnot(is.null(branch) || is.character(branch))
241+
stopifnot(
242+
"`depth` must be an integer >= 0" = is.numeric(depth) &&
243+
length(depth) == 1 &&
244+
depth >= 0
245+
)
246+
depth <- as.integer(depth)
236247
verbose <- as.logical(verbose)
237248
path <- normalizePath(path.expand(path), mustWork = FALSE)
238249
host <- url_to_host(url)
@@ -247,6 +258,7 @@ git_clone <- function(
247258
cred_cb,
248259
bare,
249260
mirror,
261+
depth,
250262
verbose
251263
)
252264
git_repo_path(repo)

man/git_fetch.Rd

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/clone.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ static int repository_enable_cache(git_repository **out, const char *path, int b
320320
}
321321

322322
SEXP R_git_repository_clone(SEXP url, SEXP path, SEXP branch, SEXP getkey, SEXP getcred,
323-
SEXP bare, SEXP mirror, SEXP verbose){
323+
SEXP bare, SEXP mirror, SEXP depth, SEXP verbose){
324324
git_repository *repo = NULL;
325325
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
326326
clone_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
@@ -331,6 +331,16 @@ SEXP R_git_repository_clone(SEXP url, SEXP path, SEXP branch, SEXP getkey, SEXP
331331

332332
set_verify_handler(&clone_opts.fetch_opts.callbacks);
333333

334+
/* shallow clone: fetch only the last 'depth' commits (libgit2 >= 1.7) */
335+
int clone_depth = Rf_asInteger(depth);
336+
if(clone_depth > 0){
337+
#if AT_LEAST_LIBGIT2(1, 7)
338+
clone_opts.fetch_opts.depth = clone_depth;
339+
#else
340+
Rf_warning("Shallow clone (depth) requires libgit2 >= 1.7.0. Ignoring the depth parameter.");
341+
#endif
342+
}
343+
334344
/* Also enables download progress and user interrupt */
335345
if(Rf_asLogical(verbose)){
336346
clone_opts.checkout_opts.progress_cb = checkout_progress;

src/init.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ extern SEXP R_git_remote_set_url(SEXP, SEXP, SEXP);
5656
extern SEXP R_git_restore(SEXP, SEXP, SEXP);
5757
extern SEXP R_git_revert(SEXP, SEXP);
5858
extern SEXP R_git_repository_add(SEXP, SEXP, SEXP);
59-
extern SEXP R_git_repository_clone(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
59+
extern SEXP R_git_repository_clone(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
6060
extern SEXP R_git_repository_find(SEXP);
6161
extern SEXP R_git_repository_info(SEXP);
6262
extern SEXP R_git_repository_init(SEXP, SEXP);
@@ -140,7 +140,7 @@ static const R_CallMethodDef CallEntries[] = {
140140
{"R_git_remote_remove", (DL_FUNC) &R_git_remote_remove, 2},
141141
{"R_git_remote_set_url", (DL_FUNC) &R_git_remote_set_url, 3},
142142
{"R_git_repository_add", (DL_FUNC) &R_git_repository_add, 3},
143-
{"R_git_repository_clone", (DL_FUNC) &R_git_repository_clone, 8},
143+
{"R_git_repository_clone", (DL_FUNC) &R_git_repository_clone, 9},
144144
{"R_git_repository_find", (DL_FUNC) &R_git_repository_find, 1},
145145
{"R_git_repository_info", (DL_FUNC) &R_git_repository_info, 1},
146146
{"R_git_repository_init", (DL_FUNC) &R_git_repository_init, 2},

tests/testthat/test-clone.R

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,32 @@ test_that("cloning repositories works, no path", {
4545
repo <- git_clone('https://github.com/r-lib/gert.git')
4646
expect_true(file.exists(file.path(path, "gert", 'DESCRIPTION')))
4747
})
48+
49+
test_that("shallow cloning with depth works", {
50+
skip_if_offline('github.com')
51+
skip_if_not(libgit2_config()$version >= "1.7.0")
52+
path <- file.path(tempdir(), 'gert-shallow')
53+
on.exit(unlink(path, recursive = TRUE))
54+
repo <- git_clone('https://github.com/r-lib/gert', path = path, depth = 1)
55+
expect_true(file.exists(file.path(path, 'DESCRIPTION')))
56+
expect_equal(nrow(git_log(repo = repo)), 1L)
57+
})
58+
59+
test_that("git_clone() validates depth argument", {
60+
expect_error(
61+
git_clone('https://github.com/r-lib/gert', depth = -1),
62+
"`depth` must be an integer >= 0"
63+
)
64+
expect_error(
65+
git_clone('https://github.com/r-lib/gert', depth = NA),
66+
"`depth` must be an integer >= 0"
67+
)
68+
expect_error(
69+
git_clone('https://github.com/r-lib/gert', depth = "a"),
70+
"`depth` must be an integer >= 0"
71+
)
72+
expect_error(
73+
git_clone('https://github.com/r-lib/gert', depth = c(1, 2)),
74+
"`depth` must be an integer >= 0"
75+
)
76+
})

0 commit comments

Comments
 (0)