class: center, middle, inverse, title-slide # Gert ## A minimal git client for R --- # Initial version on CRAN (as of yesterday) ![cran](cran.png) --- # Based on libgit2 ![libgit2](libgit2.png) --- # Similar to the git2r package ![git2r](git2r.png) --- # Why gert A _minimal_ git client for R: - __Simple__ functions returning lists / dataframes - Full support __SSH/HTTPS__ remotes on all operating systems - Automatic __authentication__ (keys, agent, GITHUB_PAT, etc) - __Fast__ and easy to install - __Clean__ code, no bundled external libs - Share settings and credentials from command line git - Designed for both for interactive and scripted use --- # Installation On Mac and Windows, binaries will be available: ```r install.packages("gert") ``` On Debian / Ubuntu you first need to install libgit2: ```sh sudo apt-get install libgit2-dev ``` And on Fedora: ```sh sudo yum install libgit2-devel ``` A PPA with backports is available if you are using an old version of Ubuntu (Trusty/Xenial): ```sh sudo add-apt-repository ppa:cran/libgit2 sudo apt-get update sudo apt-get install libgit2-dev ``` --- class: inverse, center, middle # Authentication --- # Git auth is complex ![cran2](cran2.png) --- # Credentials package ![credentials](credentials.png) --- # Credentials vignette ![vignette](vignette.png) --- # Authentication steps For HTTPS remotes, Gert will: 1. Try anonymous login 2. Lookup a password in the git credential store (via `credentials` package) 3. If remote is github.com, try using `GITHUB_PAT` 4. Prompt user for password For SSH remotes, Gert will: 1. Check with `ssh-agent` 2. Try user-provided key (read via `credentials` package) 3. Use default user `id_rsa` key --- # Git credential store For HTTPS remotes, we interact with the git credential store. ```r library(credentials) git_credential_ask('https://example.com') ## $protocol ## [1] "https" ## ## $host ## [1] "example.com" ## ## $username ## [1] "jeroen" ## ## $password ## [1] "supersecret" ## ## attr(,"class") ## [1] "git_credential" ``` --- # Git prompts the user for credentials <img class="screenshot" src="wincred.png"> --- # Manage SSH keys <img class="screenshot" src="keygen.png"> --- # The 'askpass' package Both 'gert' and 'credentials' use package 'askpass' for http login / ssh passphrase prompts: ![askpass-cran.png](askpass-cran.png) --- # MacOS askpass ![askpass-mac](askpass-mac.png) --- # RStudio askpass (server, desktop) ![askpass-rs](askpass-rs.png) --- # RGUI / Windows askpass ![askpass-windows](askpass-win.png) --- # Terminal askpass <img class="screenshotnoshadow" src="askpass-term.png"> --- class: inverse, center, middle # Using gert (live demo?) --- # Getting started ```r library(gert) ## Linking to libgit2 v0.28.1, ssh support: YES, https support: YES ## Default user: Jeroen Ooms <jeroenooms@gmail.com> ``` If you want you can check your options: ```r > git_config() ## # A tibble: 15 x 3 ## name value level ## * <chr> <chr> <chr> ## 1 user.email jeroenooms@gmail.com global ## 2 user.name Jeroen Ooms global ## 3 credential.helper osxkeychain global ## 4 core.repositoryformatversion 0 local ## 5 core.filemode true local ## 6 core.bare false local ## 7 core.logallrefupdates true local ## 8 core.ignorecase true local ## 9 core.precomposeunicode true local ... ``` --- # Opening a repository Either start a new repo: ```r dir.create("myrepo") git_init("myrepo") ``` Or clone an existing one: ```r git_clone("https://github.com/jeroen/jsonlite", path = "~/workspace/jsonlite") ## Transferred 5588 of 5588 objects...done! ## Checked out 202 of 202 commits... done! ## <git repository>: /Users/jeroen/workspace/jsonlite[@master] ``` By default `git_clone()` creates the repo in the current working dir --- # Repository argument All functions in `gert` have an argument `repo` which the repository: ```r git_info(repo = "~/workspace/jsonlite") ``` The default `repo` is the current working directory, just like with the git command line tool. Hence it is convenient (but not required) to cd to the repo directory: ```r setwd("~/workspace/jsonlite") git_info() ``` --- # Explore the repo List your git tree: ```r git_ls() ## # A tibble: 202 x 4 ## path filesize modified created ## * <chr> <dbl> <dttm> <dttm> ## 1 .gitattributes 35 2018-11-10 19:34:17 2018-11-10 19:34:17 ## 2 .gitignore 306 2019-03-08 14:41:49 2019-03-08 14:41:49 ## 3 .Rbuildignore 347 2019-03-08 14:41:49 2019-03-08 14:41:49 ## ... ``` Check recent commits: ```r git_log(ref = "HEAD", max = 3) ## # A tibble: 100 x 4 ## commit author time message ## * <chr> <chr> <dttm> <chr> ## 1 57d7891cc2888e06585… Jeroen Ooms <jero… 2019-05-21 20:02:31 "Fix LTO warning\n" ## 2 28ef2377a24529e8b07… Jeroen Ooms <jero… 2019-03-08 14:42:00 "Revert: this only works for Windows\n\nThis … ## 3 0c7e8b4a7ff307dbcb6… Jeroen Ooms <jero… 2019-03-08 14:31:03 "Test if we can use R's implicit statlib rule… ``` --- # Branches List, create, checkout branches: ```r > git_branch_list() ## # A tibble: 3 x 5 ## name local ref upstream commit ## * <chr> <lgl> <chr> <chr> <chr> ## 1 gh-pages TRUE refs/heads/gh-pages refs/remotes/origin/gh-pages f389dd0594734dce915b6656d575f8bf4344a118 ## 2 master TRUE refs/heads/master NA 94b128f16a816c7dbeabfafdb14957b50ee16170 ## 3 origin/gh-pages FALSE refs/remotes/origin/gh-pages NA f389dd0594734dce915b6656d575f8bf4344a118 ``` Create and checkout a branch: ```r # Create a branch git_branch_create('newbranch', ref = 'HEAD', checkout = FALSE) # Switch to the branch git_branch_checkout('newbranch') ``` --- # Remotes List, add, and remove remotes: ```r git_remote_list() ## # A tibble: 1 x 3 ## name url refspecs ## * <chr> <chr> <list> ## 1 origin https://github.com/jeroen/jsonlite <chr [1]> ``` Add a new remote ```r git_remote_add('someone', 'https://github.com/someone/jsonlite') ``` Fetch and push to/from the remote: ```r git_push('someone') git_fetch('someone') ``` Todo: helpers for `refspec` argument. --- # Creating a commit Check which files are modified ```r git_status() ## file status staged ## * <chr> <chr> <lgl> ## 1 index.Rmd modified FALSE ## 2 index.html modified FALSE ``` Stage the files you want to commit: ```r # Stage all dirty files git_add(".") ``` Then create the commit: ```r git_commit("my commit messsage") ``` There is also `git_commit_all()` which implies `git_add(".")`. --- # Other stuff Check the manual pages: ```r help(package = 'gert') ``` For example stashing functions: ```r git_stash_save(message, ...) git_stash_pop(index = 0, ...) git_stash_drop(index = 0, ...) git_stash_list(...) ``` And tagging functions: ```r git_tag_list() git_tag_create() git_tag_delete() git_tag_push() ```