Skip to content

Commit 811d767

Browse files
committed
feat: git_restore()
1 parent 3b038ab commit 811d767

26 files changed

Lines changed: 274 additions & 17 deletions

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export(git_remote_set_url)
6060
export(git_reset_hard)
6161
export(git_reset_mixed)
6262
export(git_reset_soft)
63+
export(git_restore)
6364
export(git_revert)
6465
export(git_rm)
6566
export(git_signature)
@@ -153,6 +154,7 @@ useDynLib(gert,R_git_repository_open)
153154
useDynLib(gert,R_git_repository_path)
154155
useDynLib(gert,R_git_repository_rm)
155156
useDynLib(gert,R_git_reset)
157+
useDynLib(gert,R_git_restore)
156158
useDynLib(gert,R_git_revert)
157159
useDynLib(gert,R_git_signature_create)
158160
useDynLib(gert,R_git_signature_default)

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
2.3.1
2+
- Add git_restore() function
23
- Add git_revert() function
34
- git_stat_files() gains a 'max' parameter
45
- Fix function declaration error

R/commit.R

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -307,22 +307,7 @@ git_revert <- function(
307307
assert_string(ref)
308308
stopifnot(is.logical(commit), length(commit) == 1)
309309

310-
sha <- tryCatch(git_commit_id(ref, repo = repo), error = function(e){
311-
stop(sprintf(
312-
"Can't find reference/commit '%s' in the current branch history",
313-
ref
314-
))
315-
})
316-
317-
head_sha <- git_commit_id("HEAD", repo = repo)
318-
sha_descends_from_head <- git_commit_descendant_of(
319-
ancestor = sha,
320-
ref = "HEAD",
321-
repo = repo
322-
)
323-
if (sha != head_sha && !sha_descends_from_head) {
324-
stop(sprintf("commit '%s' is not in the current branch history", ref))
325-
}
310+
sha <- check_ref_in_history(ref, repo)
326311

327312
.Call(R_git_revert, repo, sha)
328313

@@ -331,7 +316,12 @@ git_revert <- function(
331316
}
332317
}
333318

334-
git_revert_commit <- function(sha, message = revert_message(sha, repo), ..., repo){
319+
git_revert_commit <- function(
320+
sha,
321+
message = revert_message(sha, repo),
322+
...,
323+
repo
324+
) {
335325
git_commit(message, ..., repo = repo)
336326
}
337327

R/restore.R

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#' Restore working tree files
2+
#'
3+
#' Restores specified paths in the working tree from a given ref, equivalent
4+
#' to `git restore --source=<ref> <path>` (or the older
5+
#' `git checkout <ref> -- <path>`). The ref must be reachable from the
6+
#' current HEAD. By default restores from HEAD, discarding any local
7+
#' modifications.
8+
#'
9+
#' @export
10+
#' @name git_restore
11+
#' @rdname git_restore
12+
#' @family git
13+
#' @inheritParams git_open
14+
#' @param path character vector with file paths to restore, relative to the
15+
#' repository root. Use `"."` to restore all tracked files.
16+
#' @param ref revision string with a branch/tag/commit to restore from.
17+
#' Defaults to `"HEAD"`.
18+
#' @return Invisibly, the [git_status()] after restoring.
19+
#' @examplesIf interactive()
20+
#' repo <- file.path(tempdir(), "myrepo")
21+
#' git_init(repo)
22+
#'
23+
#' # Set a user if no default
24+
#' if (!user_is_configured()) {
25+
#' git_config_set("user.name", "Jerry")
26+
#' git_config_set("user.email", "jerry@gmail.com")
27+
#' }
28+
#'
29+
#' writeLines("hello", file.path(repo, "hello.txt"))
30+
#' git_add("hello.txt", repo = repo)
31+
#' git_commit("First commit", repo = repo)
32+
#'
33+
#' # Modify the file, then restore it from HEAD
34+
#' writeLines("oops", file.path(repo, "hello.txt"))
35+
#' git_restore("hello.txt", repo = repo)
36+
#' readLines(file.path(repo, "hello.txt")) # "hello"
37+
#'
38+
#' unlink(repo, recursive = TRUE)
39+
#' @useDynLib gert R_git_restore
40+
git_restore <- function(path, ref = "HEAD", repo = ".") {
41+
repo <- git_open(repo)
42+
path <- check_path_tracked(as.character(path), repo)
43+
check_ref_in_history(ref, repo)
44+
.Call(R_git_restore, repo, path, ref)
45+
invisible(git_status(repo = repo))
46+
}
47+
48+
check_path_tracked <- function(path, repo) {
49+
if (identical(path, ".")) {
50+
return(character(0))
51+
}
52+
tracked <- git_ls(repo = repo)$path
53+
untracked <- setdiff(path, tracked)
54+
if (length(untracked) > 0) {
55+
stop("Path(s) not tracked by git: ", toString(untracked))
56+
}
57+
path
58+
}

R/utils-sha.R

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
check_ref_in_history <- function(ref, repo) {
2+
sha <- tryCatch(git_commit_id(ref, repo = repo), error = function(e) {
3+
stop(sprintf("Cannot resolve '%s' to a commit", ref))
4+
})
5+
6+
head_sha <- git_commit_id("HEAD", repo = repo)
7+
sha_descends_from_head <- git_commit_descendant_of(
8+
ancestor = sha,
9+
ref = "HEAD",
10+
repo = repo
11+
)
12+
if (sha != head_sha && !sha_descends_from_head) {
13+
stop(sprintf("'%s' is not in the current branch history", ref))
14+
}
15+
16+
sha
17+
}

man/git_archive.Rd

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

man/git_branch.Rd

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

man/git_commit.Rd

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

man/git_config.Rd

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

man/git_diff.Rd

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

0 commit comments

Comments
 (0)