Nothing
## git2r, R bindings to the libgit2 library.
## Copyright (C) 2013-2024 The git2r contributors
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License, version 2,
## as published by the Free Software Foundation.
##
## git2r is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
##' Ahead Behind
##'
##' Count the number of unique commits between two commit objects.
##' @param local a git_commit object. Can also be a tag or a branch,
##' and in that case the commit will be the target of the tag or
##' branch.
##' @param upstream a git_commit object. Can also be a tag or a
##' branch, and in that case the commit will be the target of the
##' tag or branch.
##' @return An integer vector of length 2 with number of commits that
##' the upstream commit is ahead and behind the local commit
##' @export
##' @useDynLib git2r git2r_graph_ahead_behind
##' @examples \dontrun{
##' ## Create a directory in tempdir
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##'
##' ## Initialize a repository
##' repo <- init(path)
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##'
##' ## Create a file, add and commit
##' lines <- "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do"
##' writeLines(lines, file.path(path, "test.txt"))
##' add(repo, "test.txt")
##' commit_1 <- commit(repo, "Commit message 1")
##' tag_1 <- tag(repo, "Tagname1", "Tag message 1")
##'
##' # Change file and commit
##' lines <- c(
##' "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do",
##' "eiusmod tempor incididunt ut labore et dolore magna aliqua.")
##' writeLines(lines, file.path(path, "test.txt"))
##' add(repo, "test.txt")
##' commit_2 <- commit(repo, "Commit message 2")
##' tag_2 <- tag(repo, "Tagname2", "Tag message 2")
##'
##' ahead_behind(commit_1, commit_2)
##' ahead_behind(tag_1, tag_2)
##' }
ahead_behind <- function(local = NULL, upstream = NULL) {
.Call(git2r_graph_ahead_behind,
lookup_commit(local),
lookup_commit(upstream))
}
##' Add sessionInfo to message
##'
##' @param message The message.
##' @return message with appended sessionInfo
##' @importFrom utils capture.output
##' @importFrom utils sessionInfo
##' @noRd
add_session_info <- function(message) {
paste0(message, "\n\nsessionInfo:\n",
paste0(utils::capture.output(utils::sessionInfo()),
collapse = "\n"))
}
##' Commit
##'
##' @template repo-param
##' @param message The commit message.
##' @param all Stage modified and deleted files. Files not added to
##' Git are not affected.
##' @param session Add sessionInfo to commit message. Default is
##' FALSE.
##' @param author Signature with author and author time of commit.
##' @param committer Signature with committer and commit time of
##' commit.
##' @return A list of class \code{git_commit} with entries:
##' \describe{
##' \item{sha}{
##' The 40 character hexadecimal string of the SHA-1
##' }
##' \item{author}{
##' An author signature
##' }
##' \item{committer}{
##' The committer signature
##' }
##' \item{summary}{
##' The short "summary" of a git commit message, comprising the first
##' paragraph of the message with whitespace trimmed and squashed.
##' }
##' \item{message}{
##' The message of a commit
##' }
##' \item{repo}{
##' The \code{git_repository} object that contains the commit
##' }
##' }
##' @export
##' @useDynLib git2r git2r_commit
##' @useDynLib git2r git2r_index_remove_bypath
##' @examples
##' \dontrun{
##' ## Initialize a repository
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##' repo <- init(path)
##'
##' ## Config user
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##'
##' ## Write to a file and commit
##' lines <- "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do"
##' writeLines(lines, file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit(repo, "First commit message")
##' }
commit <- function(repo = ".",
message = NULL,
all = FALSE,
session = FALSE,
author = NULL,
committer = NULL) {
repo <- lookup_repository(repo)
if (is.null(author))
author <- default_signature(repo)
if (is.null(committer))
committer <- default_signature(repo)
stopifnot(is.character(message), identical(length(message), 1L))
if (!nchar(message[1]))
stop("Aborting commit due to empty commit message.")
if (isTRUE(all)) {
s <- status(repo,
unstaged = TRUE,
staged = FALSE,
untracked = FALSE,
ignored = FALSE)
## Convert list of lists to character vector
unstaged <- unlist(s$unstaged)
for (i in seq_along(unstaged)) {
if (names(unstaged)[i] == "modified") {
## Stage modified files
add(repo, unstaged[i])
} else if (names(unstaged)[i] == "deleted") {
## Stage deleted files
.Call(git2r_index_remove_bypath, repo, unstaged[i])
}
}
}
if (isTRUE(session))
message <- add_session_info(message)
.Call(git2r_commit, repo, message, author, committer)
}
##' Check limit in number of commits
##' @noRd
get_upper_limit_of_commits <- function(n) {
if (is.null(n)) {
n <- -1L
} else if (is.numeric(n)) {
if (!identical(length(n), 1L))
stop("'n' must be integer")
if (abs(n - round(n)) >= .Machine$double.eps^0.5)
stop("'n' must be integer")
n <- as.integer(n)
} else {
stop("'n' must be integer")
}
n
}
shallow_commits <- function(repo, sha, n) {
## List to hold result
result <- list()
## Get latest commit
x <- lookup(repo, sha)
## Repeat until no more parent commits
repeat {
if (n == 0) {
break
} else if (n > 0) {
n <- n - 1
}
if (is.null(x))
break
result[[length(result) + 1]] <- x
## Get parent to commit
x <- tryCatch(parents(x)[[1]], error = function(e) NULL)
}
result
}
##' Commits
##'
##' @template repo-param
##' @param topological Sort the commits in topological order (parents
##' before children); can be combined with time sorting. Default
##' is TRUE.
##' @param time Sort the commits by commit time; Can be combined with
##' topological sorting. Default is TRUE.
##' @param reverse Sort the commits in reverse order; can be combined
##' with topological and/or time sorting. Default is FALSE.
##' @param n The upper limit of the number of commits to output. The
##' default is NULL for unlimited number of commits.
##' @param ref The name of a reference to list commits from e.g. a tag
##' or a branch. The default is NULL for the current branch.
##' @param path The path to a file. If not NULL, only commits modifying
##' this file will be returned. Note that modifying commits that
##' occurred before the file was given its present name are not
##' returned; that is, the output of \code{git log} with
##' \code{--no-follow} is reproduced.
##' @return list of commits in repository
##' @export
##' @useDynLib git2r git2r_reference_dwim
##' @useDynLib git2r git2r_revwalk_list2
##' @useDynLib git2r git2r_revwalk_list
##' @examples
##' \dontrun{
##' ## Initialize a repository
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##' repo <- init(path)
##'
##' ## Config user
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##'
##' ## Write to a file and commit
##' lines <- "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do"
##' writeLines(lines, file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit(repo, "First commit message")
##'
##' ## Change file and commit
##' lines <- c(
##' "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do",
##' "eiusmod tempor incididunt ut labore et dolore magna aliqua.")
##' writeLines(lines, file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit(repo, "Second commit message")
##'
##' ## Create a tag
##' tag(repo, "Tagname", "Tag message")
##'
##' ## Change file again and commit
##' lines <- c(
##' "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do",
##' "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad",
##' "minim veniam, quis nostrud exercitation ullamco laboris nisi ut")
##' writeLines(lines, file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit(repo, "Third commit message")
##'
##' ## Create a new file containing R code, and commit.
##' writeLines(c("x <- seq(1,100)",
##' "print(mean(x))"),
##' file.path(path, "mean.R"))
##' add(repo, "mean.R")
##' commit(repo, "Fourth commit message")
##'
##' ## List the commits in the repository
##' commits(repo)
##'
##' ## List the commits starting from the tag
##' commits(repo, ref = "Tagname")
##'
##' ## List the commits modifying example.txt and mean.R.
##' commits(repo, path = "example.txt")
##' commits(repo, path = "mean.R")
##'
##' ## Create and checkout 'dev' branch in the repo
##' checkout(repo, "dev", create = TRUE)
##'
##' ## Add changes to the 'dev' branch
##' lines <- c(
##' "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do",
##' "eiusmod tempor incididunt ut labore et dolore magna aliqua.")
##' writeLines(lines, file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit(repo, "Commit message in dev branch")
##'
##' ## Checkout the 'master' branch again and list the commits
##' ## starting from the 'dev' branch.
##' checkout(repo, "master")
##' commits(repo, ref = "dev")
##' }
commits <- function(repo = ".",
topological = TRUE,
time = TRUE,
reverse = FALSE,
n = NULL,
ref = NULL,
path = NULL) {
## Check limit in number of commits
n <- get_upper_limit_of_commits(n)
if (!is.null(path)) {
if (!(is.character(path) && length(path) == 1)) {
stop("path must be a single file")
}
}
repo <- lookup_repository(repo)
if (is_empty(repo))
return(list())
if (is.null(ref)) {
sha <- sha(repository_head(repo))
} else {
sha <- sha(lookup_commit(.Call(git2r_reference_dwim, repo, ref)))
}
if (is_shallow(repo)) {
## FIXME: Remove this if-statement when libgit2 supports
## shallow clones, see #219. Note: This workaround does not
## use the 'topological', 'time' and 'reverse' flags.
return(shallow_commits(repo, sha, n))
}
if (!is.null(path)) {
repo_wd <- normalizePath(workdir(repo), winslash = "/")
path <- sanitize_path(path, repo_wd)
path_revwalk <- .Call(git2r_revwalk_list2, repo, sha, topological,
time, reverse, n, path)
return(path_revwalk[!vapply(path_revwalk, is.null, logical(1))])
}
.Call(git2r_revwalk_list, repo, sha, topological, time, reverse, n)
}
##' Last commit
##'
##' Get last commit in the current branch.
##' @template repo-param
##' @export
##' @examples
##' \dontrun{
##' ## Initialize a repository
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##' repo <- init(path)
##'
##' ## Config user
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##'
##' ## Write to a file and commit
##' lines <- "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do"
##' writeLines(lines, file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit(repo, "First commit message")
##'
##' ## Get last commit
##' last_commit(repo)
##' last_commit(path)
##'
##' ## Coerce the last commit to a data.frame
##' as.data.frame(last_commit(path), "data.frame")
##'
##' ## Summary of last commit in repository
##' summary(last_commit(repo))
##' }
last_commit <- function(repo = ".") {
commits(lookup_repository(repo), n = 1)[[1]]
}
##' Descendant
##'
##' Determine if a commit is the descendant of another commit
##' @param commit a git_commit object. Can also be a tag or a branch,
##' and in that case the commit will be the target of the tag or
##' branch.
##' @param ancestor a git_commit object to check if ancestor to
##' \code{commit}. Can also be a tag or a branch, and in that case
##' the commit will be the target of the tag or branch.
##' @return TRUE if \code{commit} is descendant of \code{ancestor},
##' else FALSE
##' @export
##' @useDynLib git2r git2r_graph_descendant_of
##' @examples
##' \dontrun{
##' ## Create a directory in tempdir
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##'
##' ## Initialize a repository
##' repo <- init(path)
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##'
##' ## Create a file, add and commit
##' lines <- "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do"
##' writeLines(lines, file.path(path, "test.txt"))
##' add(repo, "test.txt")
##' commit_1 <- commit(repo, "Commit message 1")
##' tag_1 <- tag(repo, "Tagname1", "Tag message 1")
##'
##' # Change file and commit
##' lines <- c(
##' "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do",
##' "eiusmod tempor incididunt ut labore et dolore magna aliqua.")
##' writeLines(lines, file.path(path, "test.txt"))
##' add(repo, "test.txt")
##' commit_2 <- commit(repo, "Commit message 2")
##' tag_2 <- tag(repo, "Tagname2", "Tag message 2")
##'
##' descendant_of(commit_1, commit_2)
##' descendant_of(commit_2, commit_1)
##' descendant_of(tag_1, tag_2)
##' descendant_of(tag_2, tag_1)
##' }
descendant_of <- function(commit = NULL, ancestor = NULL) {
.Call(git2r_graph_descendant_of,
lookup_commit(commit),
lookup_commit(ancestor))
}
##' Check if object is a git_commit object
##'
##' @param object Check if object is a git_commit object
##' @return TRUE if object is a git_commit, else FALSE
##' @export
##' @examples
##' \dontrun{
##' ## Initialize a temporary repository
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##' repo <- init(path)
##'
##' ## Create a user
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##'
##' ## Commit a text file
##' writeLines("Hello world!", file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit_1 <- commit(repo, "First commit message")
##'
##' ## Check if commit
##' is_commit(commit_1)
##' }
is_commit <- function(object) {
inherits(object, "git_commit")
}
##' Is merge
##'
##' Determine if a commit is a merge commit, i.e. has more than one
##' parent.
##' @param commit a git_commit object.
##' @return TRUE if commit has more than one parent, else FALSE
##' @export
##' @examples
##' \dontrun{
##' ## Initialize a temporary repository
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##' repo <- init(path)
##'
##' ## Create a user and commit a file
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##' writeLines(c("First line in file 1.", "Second line in file 1."),
##' file.path(path, "example-1.txt"))
##' add(repo, "example-1.txt")
##' commit(repo, "First commit message")
##'
##' ## Create and add one more file
##' writeLines(c("First line in file 2.", "Second line in file 2."),
##' file.path(path, "example-2.txt"))
##' add(repo, "example-2.txt")
##' commit(repo, "Second commit message")
##'
##' ## Create a new branch 'fix'
##' checkout(repo, "fix", create = TRUE)
##'
##' ## Update 'example-1.txt' (swap words in first line) and commit
##' writeLines(c("line First in file 1.", "Second line in file 1."),
##' file.path(path, "example-1.txt"))
##' add(repo, "example-1.txt")
##' commit(repo, "Third commit message")
##'
##' checkout(repo, "master")
##'
##' ## Update 'example-2.txt' (swap words in second line) and commit
##' writeLines(c("First line in file 2.", "line Second in file 2."),
##' file.path(path, "example-2.txt"))
##' add(repo, "example-2.txt")
##' commit(repo, "Fourth commit message")
##'
##' ## Merge 'fix'
##' merge(repo, "fix")
##'
##' ## Display parents of last commit
##' parents(lookup(repo, branch_target(repository_head(repo))))
##'
##' ## Check that last commit is a merge
##' is_merge(lookup(repo, branch_target(repository_head(repo))))
##' }
is_merge <- function(commit = NULL) {
length(parents(commit)) > 1
}
##' Parents
##'
##' Get parents of a commit.
##' @param object a git_commit object.
##' @return list of git_commit objects
##' @export
##' @useDynLib git2r git2r_commit_parent_list
##' @examples
##' \dontrun{
##' ## Initialize a temporary repository
##' path <- tempfile(pattern="git2r-")
##' dir.create(path)
##' repo <- init(path)
##'
##' ## Create a user and commit a file
##' config(repo, user.name = "Alice", user.email = "alice@@example.org")
##' writeLines("First line.",
##' file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit_1 <- commit(repo, "First commit message")
##'
##' ## commit_1 has no parents
##' parents(commit_1)
##'
##' ## Update 'example.txt' and commit
##' writeLines(c("First line.", "Second line."),
##' file.path(path, "example.txt"))
##' add(repo, "example.txt")
##' commit_2 <- commit(repo, "Second commit message")
##'
##' ## commit_2 has commit_1 as parent
##' parents(commit_2)
##' }
parents <- function(object = NULL) {
.Call(git2r_commit_parent_list, object)
}
##' @export
format.git_commit <- function(x, ...) {
sprintf("[%s] %s: %s",
substring(x$sha, 1, 7),
substring(as.character(x$author$when), 1, 10),
x$summary)
}
##' @export
print.git_commit <- function(x, ...) {
cat(format(x, ...), "\n", sep = "")
invisible(x)
}
##' @export
summary.git_commit <- function(object, ...) {
is_merge_commit <- is_merge(object)
po <- parents(object)
cat(sprintf("Commit: %s\n", object$sha))
if (is_merge_commit) {
sha <- vapply(po, "[[", character(1), "sha")
cat(sprintf("Merge: %s\n", sha[1]))
cat(paste0(" ", sha[-1]), sep = "\n")
}
cat(sprintf(paste0("Author: %s <%s>\n",
"When: %s\n\n"),
object$author$name,
object$author$email,
as.character(object$author$when)))
msg <- paste0(" ", readLines(textConnection(object$message)))
cat("", sprintf("%s\n", msg))
if (is_merge_commit) {
cat("\n")
lapply(po, function(parent) {
cat("Commit message: ", parent$sha, "\n")
msg <- paste0(" ",
readLines(textConnection(parent$message)))
cat("", sprintf("%s\n", msg), "\n")
})
}
if (identical(length(po), 1L)) {
df <- diff(tree(po[[1]]), tree(object))
if (length(df) > 0) {
if (length(df) > 1) {
cat(sprintf("%i files changed, ", length(df)))
} else {
cat("1 file changed, ")
}
cat(sprintf(
"%i insertions, %i deletions\n",
sum(vapply(lines_per_file(df), "[[", numeric(1), "add")),
sum(vapply(lines_per_file(df), "[[", numeric(1), "del"))))
plpf <- print_lines_per_file(df)
hpf <- hunks_per_file(df)
hunk_txt <- ifelse(hpf > 1, " hunks",
ifelse(hpf > 0, " hunk",
" hunk (binary file)"))
phpf <- paste0(" in ", format(hpf), hunk_txt)
cat(paste0(plpf, phpf), sep = "\n")
}
cat("\n")
}
invisible(NULL)
}
##' @export
as.data.frame.git_commit <- function(x, ...) {
data.frame(sha = x$sha,
summary = x$summary,
message = x$message,
author = x$author$name,
email = x$author$email,
when = as.POSIXct(x$author$when),
stringsAsFactors = FALSE)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.