Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export(git_remote_set_url)
export(git_reset_hard)
export(git_reset_mixed)
export(git_reset_soft)
export(git_restore)
export(git_revert)
export(git_rm)
export(git_signature)
Expand Down Expand Up @@ -158,6 +159,7 @@ useDynLib(gert,R_git_repository_open)
useDynLib(gert,R_git_repository_path)
useDynLib(gert,R_git_repository_rm)
useDynLib(gert,R_git_reset)
useDynLib(gert,R_git_restore)
useDynLib(gert,R_git_revert)
useDynLib(gert,R_git_signature_create)
useDynLib(gert,R_git_signature_default)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# gert (development version)

- Add `git_restore()` function (#259)
- Add `git_config_get()`, `git_config_local_get()`, and `git_config_global_get()` to retrieve a single named config option, returning `NULL` if unset (#267).
- `git_clone()` without a `path` argument now clones into a directory named after the
"humanish" part of the URL, so "git@github.com:francisbarton/myrepo.git" gets cloned into `myrepo` (@francisbardon, #192).
Expand Down
17 changes: 1 addition & 16 deletions R/commit.R
Original file line number Diff line number Diff line change
Expand Up @@ -322,22 +322,7 @@ git_revert <- function(
assert_string(ref)
stopifnot(is.logical(commit), length(commit) == 1)

sha <- tryCatch(git_commit_id(ref, repo = repo), error = function(e) {
stop(sprintf(
"Can't find reference/commit '%s' in the current branch history",
ref
))
})

head_sha <- git_commit_id("HEAD", repo = repo)
sha_descends_from_head <- git_commit_descendant_of(
ancestor = sha,
ref = "HEAD",
repo = repo
)
if (sha != head_sha && !sha_descends_from_head) {
stop(sprintf("commit '%s' is not in the current branch history", ref))
}
sha <- check_ref_in_history(ref, repo)

.Call(R_git_revert, repo, sha)

Expand Down
58 changes: 58 additions & 0 deletions R/restore.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#' Restore working tree files
#'
#' Restores specified paths in the working tree from a given ref, equivalent
#' to `git restore --source=<ref> <path>` (or the older
#' `git checkout <ref> -- <path>`). The ref must be reachable from the
#' current HEAD. By default restores from HEAD, discarding any local
#' modifications.
#'
#' @export
#' @name git_restore
#' @rdname git_restore
#' @family git
#' @inheritParams git_open
#' @param path character vector with file paths to restore, relative to the
#' repository root. Use `"."` to restore all tracked files.
#' @param ref revision string with a branch/tag/commit to restore from.
#' Defaults to `"HEAD"`.
#' @return Invisibly, the [git_status()] after restoring.
#' @examplesIf interactive()
#' repo <- file.path(tempdir(), "myrepo")
#' git_init(repo)
#'
#' # Set a user if no default
#' if (!user_is_configured()) {
#' git_config_set("user.name", "Jerry")
#' git_config_set("user.email", "jerry@gmail.com")
#' }
#'
#' writeLines("hello", file.path(repo, "hello.txt"))
#' git_add("hello.txt", repo = repo)
#' git_commit("First commit", repo = repo)
#'
#' # Modify the file, then restore it from HEAD
#' writeLines("oops", file.path(repo, "hello.txt"))
#' git_restore("hello.txt", repo = repo)
#' readLines(file.path(repo, "hello.txt")) # "hello"
#'
#' unlink(repo, recursive = TRUE)
#' @useDynLib gert R_git_restore
git_restore <- function(path, ref = "HEAD", repo = ".") {
repo <- git_open(repo)
path <- check_path_tracked(as.character(path), repo)
ref <- check_ref_in_history(ref, repo)
.Call(R_git_restore, repo, path, ref)
invisible(git_status(repo = repo))
}

check_path_tracked <- function(path, repo) {
if (identical(path, ".")) {
return(character(0))
}
tracked <- git_ls(repo = repo)$path
untracked <- setdiff(path, tracked)
if (length(untracked) > 0) {
stop("Path(s) not tracked by git: ", toString(untracked))
}
path
}
17 changes: 17 additions & 0 deletions R/utils-sha.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
check_ref_in_history <- function(ref, repo) {
sha <- tryCatch(git_commit_id(ref, repo = repo), error = function(e) {
stop(sprintf("Cannot resolve '%s' to a commit", ref))
})

head_sha <- git_commit_id("HEAD", repo = repo)
sha_descends_from_head <- git_commit_descendant_of(
ancestor = sha,
ref = "HEAD",
repo = repo
)
if (sha != head_sha && !sha_descends_from_head) {
stop(sprintf("'%s' is not in the current branch history", ref))
}

sha
}
1 change: 1 addition & 0 deletions man/git_archive.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_branch.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_commit.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_config.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_diff.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_fetch.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_history.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_ignore.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_merge.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_rebase.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_remote.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_repo.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_reset.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 76 additions & 0 deletions man/git_restore.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_revert.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_signature.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_stash.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_tag.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/git_worktree.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions src/files.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,17 @@ SEXP R_git_status_list(SEXP ptr, SEXP show_staged, SEXP path_spec){
UNPROTECT(3);
return out;
}

SEXP R_git_restore(SEXP ptr, SEXP files, SEXP ref){
git_repository *repo = get_git_repository(ptr);
git_object *obj = resolve_refish(ref, repo);
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
git_strarray *paths = files_to_array(files);
opts.paths = *paths;
int err = git_checkout_tree(repo, obj, &opts);
git_strarray_free(paths);
git_object_free(obj);
bail_if(err, "git_checkout_tree");
return R_NilValue;
}
2 changes: 2 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extern SEXP R_git_remote_push(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP R_git_remote_refspecs(SEXP, SEXP);
extern SEXP R_git_remote_remove(SEXP, SEXP);
extern SEXP R_git_remote_set_url(SEXP, SEXP, SEXP);
extern SEXP R_git_restore(SEXP, SEXP, SEXP);
extern SEXP R_git_revert(SEXP, SEXP);
extern SEXP R_git_repository_add(SEXP, SEXP, SEXP);
extern SEXP R_git_repository_clone(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
Expand Down Expand Up @@ -146,6 +147,7 @@ static const R_CallMethodDef CallEntries[] = {
{"R_git_repository_path", (DL_FUNC) &R_git_repository_path, 1},
{"R_git_repository_rm", (DL_FUNC) &R_git_repository_rm, 2},
{"R_git_reset", (DL_FUNC) &R_git_reset, 3},
{"R_git_restore", (DL_FUNC) &R_git_restore, 3},
{"R_git_revert", (DL_FUNC) &R_git_revert, 2},
{"R_git_signature_create", (DL_FUNC) &R_git_signature_create, 4},
{"R_git_signature_default", (DL_FUNC) &R_git_signature_default, 1},
Expand Down
Loading
Loading