diff --git a/_bookdown.yml b/_bookdown.yml index a316d029..6a9c5cc5 100644 --- a/_bookdown.yml +++ b/_bookdown.yml @@ -20,9 +20,9 @@ rmd_files: [ "install-git-client.Rmd", "connect-intro.Rmd", - "connect-git-github.Rmd", - "connect-credential-caching.Rmd", + "connect-https-pat.Rmd", "connect-ssh-keys.Rmd", + "connect-git-github.Rmd", "connect-rstudio-git-github.Rmd", "connect-can-rstudio-use-git.Rmd", "connect-troubleshooting.Rmd", @@ -67,7 +67,6 @@ rmd_files: [ "appendix.Rmd", "shell.Rmd", - "github-api-tokens.Rmd", "comic-relief.Rmd", "references.Rmd" diff --git a/connect-can-rstudio-use-git.Rmd b/connect-can-rstudio-use-git.Rmd index 821a148a..f1a56a37 100644 --- a/connect-can-rstudio-use-git.Rmd +++ b/connect-can-rstudio-use-git.Rmd @@ -12,9 +12,6 @@ Let's check if RStudio can find the Git executable. * *File > New Project...* Do you see an option to create from Version Control? If yes, good. * Select *New Directory* > *Empty Project*. Do you see a checkbox "Create a git repository"? If yes, good, CHECK IT. - * Give this disposable test project a name and click *Create Project*. Do you see a "Git" tab in the upper right pane, the same one that has "Environment" and "History"? If yes, good. - -If all looks good, you can delete this project. Looks like RStudio and Git are talking to each other. Keep reading if things don't go so well or you want to know more. @@ -22,7 +19,8 @@ Keep reading if things don't go so well or you want to know more. RStudio can only act as a GUI front-end for Git if Git has been successfully installed (chapter \@ref(install-git)) **AND RStudio can find it**. -A basic test for successful installation of Git is to simply enter `git` in the shell (Appendix \@ref(shell)). If you get a complaint about Git not being found, it means installation was unsuccessful or that it is not being found, i.e. it is not on your `PATH`. +A basic test for successful installation of Git is to simply enter `git` in the shell (Appendix \@ref(shell)). +If you get a complaint about Git not being found, it means installation was unsuccessful or that it is not being found, i.e. it is not on your `PATH`. If you are not sure where the Git executable lives, try this in a shell: @@ -32,17 +30,21 @@ If you are not sure where the Git executable lives, try this in a shell: ## Tell RStudio where to find Git -If Git appears to be installed and findable, launch RStudio. Quit and re-launch RStudio if there's __any doubt in your mind__ about whether you opened RStudio before or after installing Git. Don't make me stop this car and restart RStudio for you in office hours. DO IT. +If Git appears to be installed and findable, launch RStudio. +Quit and re-launch RStudio if there's **any doubt in your mind** about whether you opened RStudio before or after installing Git. +Don't make me stop this car and restart RStudio for you in office hours. +DO IT. From RStudio, go to *Tools > Global Options > Git/SVN* and make sure that the box *Git executable* points to your Git executable. On macOS and Linux, the path usually looks something like this: -``` bash +```console /usr/bin/git ``` -If you need to set this on macOS, it can sometimes be hard to navigate to the necessary directory, once you've clicked "Browse" and are working with a Finder-type window. The keyboard shortcut "command + shift + g" will summon "Go To Folder", where you will be able to type or paste any path you want. +If you need to set this on macOS, it can sometimes be hard to navigate to the necessary directory, once you've clicked "Browse" and are working with a Finder-type window. +The keyboard shortcut "command + shift + g" will summon "Go To Folder", where you will be able to type or paste any path you want. On Windows, this path should look something like this: @@ -52,15 +54,23 @@ C:/Program Files/Git/bin/git.exe and here is a screenshot on Windows: -![RStudio screenshot showing path to Git executable](img/windows-rstudio-git-executable-screenshot.png) +```{r} +#| echo = FALSE, fig.align = "center", out.width = "100%", +#| fig.alt = "RStudio screenshot showing path to the Git executable" +knitr::include_graphics("img/windows-rstudio-git-executable-screenshot.png") +``` -**WARNING**: On Windows, do __NOT__ use `C:/Program Files/Git/cmd/git.exe`. `bin` in the path is GOOD YES! `cmd` in the path is BAD NO! +**WARNING**: On Windows, do __NOT__ use `C:/Program Files/Git/cmd/git.exe`. `bin` in the path is GOOD YES! +`cmd` in the path is BAD NO! -**WARNING**: On Windows, do __NOT__ set this to `git-bash.exe`. Something that ends in `git.exe` is GOOD YES! `git-bash.exe` is BAD NO! +**WARNING**: On Windows, do __NOT__ set this to `git-bash.exe`. +Something that ends in `git.exe` is GOOD YES! `git-bash.exe` is BAD NO! -**Restart RStudio if you make any changes.** Don't make me stop this car again and restart RStudio for you in office hours. DO IT. +**Restart RStudio if you make any changes here.** +Don't make me stop this car again and restart RStudio for you in office hours. +DO IT. -Do the steps at the top of the page to see if RStudio and Git are communicating now. +Re-do the steps at the top of the page to see if RStudio and Git are communicating now. No joy? diff --git a/connect-credential-caching.Rmd b/connect-credential-caching.Rmd deleted file mode 100644 index 487551e9..00000000 --- a/connect-credential-caching.Rmd +++ /dev/null @@ -1,285 +0,0 @@ -# Cache credentials for HTTPS {#credential-caching} - -If you plan to push/pull using HTTPS, you want to cache your credentials (e.g. password), so you don't need to enter them over and over again. -Alternatively, you could set up SSH keys (chapter \@ref(ssh-keys)). -I suggest you set up one of these methods of authentication on each computer you want to connect to GitHub from. - -I find HTTPS easier to get working quickly and **strongly recommend** it when you first start working with Git/GitHub. -[HTTPS is what GitHub recommends](https://stackoverflow.com/a/11041782/2825349), presumably for exactly the same reasons. -I started with HTTPS, preferred SSH for a while, and have returned to HTTPS. -Either is fine, you can change your mind later, and you can use HTTPS on one machine and SSH on another. - -Remember: the transport protocol is controlled by the URL you use for remote repo access. - -HTTPS remotes look like `https://github.com//.git`. -SSH remotes look like `git@github.com:/.git`. - -## You should get a personal access token (PAT) {#get-a-pat} - -### Why a PAT? - -Password-based authentication for Git is deprecated, i.e. you really should _not_ be sending your username and password every time you push or pull. -Here, I'm referring to the username and password you would use to login to GitHub in the browser. - -What should you do instead? - -Get a **personal access token** (PAT) and use that as your credential for HTTPS operations. -(The PAT will actually be sent as the password and the username is somewhat artificial, consulted only for credential lookup.) - -If you turn on [two-factor authentication](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/about-two-factor-authentication) (a.k.a. "2FA") for GitHub and you use HTTPS, you absolutely **must** send a personal access token. -And, really, it's a good idea for everyone to turn on 2FA and for everyone who uses HTTPS to use a PAT. - -The final selling point is that once you configure a PAT, several R packages, including usethis and gh, will be able to work with the GitHub API on your behalf, automagically. -Therefore, a properly configured PAT means all of this will work seamlessly: - - * Remote HTTPS operations via command line Git and, therefore, via RStudio - * Remote HTTPS operations via the gert R package and, therefore, usethis - * GitHub API operations via the gh R package and, therefore, usethis - -### How to get a PAT? - -GitHub offers instructions for [creating a personal access token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token). - -The usethis package has a helper function that takes you to the web form to create a PAT, with the added benefit that it pre-selects the recommended scopes: - -```{r eval = FALSE} -usethis::create_github_token() -``` - -Once you are happy with the selected scopes, click "Generate token". -As the page says, you must **store this token somewhere**, because you'll never be able to see it again, once you leave that page or close the window. - -### How to manage a PAT? - -Treat this PAT like a password! -If you use a password management app, such as 1Password or LastPass (which you should), it is highly recommended to add this PAT to your entry for GitHub. -Below, we will add your PAT to the Git credential store as a semi-persistent convenience, sort of like "remember me" on a website. -But, just like logging into websites, it is entirely possible that your PAT will somehow be forgotten from the credential store and you will need to re-enter it. - -If you goof this up, i.e. generate a PAT but fail to capture it on your system, -you'll have to generate another one. -This is not the end of the world, but you should delete the "lost" PAT on GitHub. -If you aren’t disciplined about labelling PATs and deleting lost PATs, you will find yourself in an unsettling situation where you can’t be sure which PAT(s) are in use. -When logged into your GitHub account, you can manage your PATs here: - - - -Do not ever hard-wire your PAT into your code! -A PAT should always be retrieved implicitly, for example, from the Git credential store or from an environment variable. - -At this point, I assume you've generated a PAT and have it available, either: - - * In a secure, long-term system for storing secrets, like 1Password or LastPass (recommended) - * For the next few minutes, e.g. in a browser window or on the clipboard - -## Store your credential - -There are many ways to get your credential into the Git store. -You need to trigger a prompt for your credential and usually it will be stored for next time. - -If your credential doesn't seem to be stored and re-discovered, see the last section. - -If *something* has been stored and is being re-discovered, but you're not 100% sure it's what you want (e.g. username and password vs. PAT), we give some pointers below. - -Ways to access the credential store, in order of relevance: - - * Call an R function to store (or update) your credentials - * Organic Git use, e.g. via the command line or even RStudio (clunky) - * Make an explicit call to the Git credential manager (for keeners only) - * Go into your OS-level credential store (for keeners only) - -### Call an R function to store your credentials - -As of November 2020, there are two R packages for accessing the Git credential store: - - * [gitcreds](https://r-lib.github.io/gitcreds/) - * [credentials](https://docs.ropensci.org/credentials/) - -It is likely that these packages will eventually combine into one and, even now, they are largely interoperable. -You don't need to follow the instructions for both packages -- pick one! - -#### gitcreds package - -If you don't have gitcreds installed, install via `install.packages("gitcreds")`. - -Then call `gitcreds_set()`: - -```{r eval = FALSE} -library(gitcreds) - -gitcreds_set() -``` - -`gitcreds::gitcreds_set()` is a very handy function, since it reports any current credential, allows you to see it, allows you to keep or replace an existing credential, and can also store a credential for the first time. - -Respond to the prompt with your personal access token (PAT). - -You can check that you've stored a credential with `gitcreds_get()`: - -```{r eval = FALSE} -gitcreds_get() -#> -#> protocol: https -#> host : github.com -#> username: PersonalAccessToken -#> password: <-- hidden --> -``` - -#### credentials package - -If you don't have credentials installed, install via `install.packages("credentials")`. - -Then call `set_github_pat()`: - -```{r eval = FALSE} -library(credentials) - -set_github_pat() -``` - -Respond to the prompt with your personal access token (PAT). - -If successful, your initial (and subsequent) calls will look like this: - -```{r eval = FALSE} -set_github_pat() -#> If prompted for GitHub credentials, enter your PAT in the password field -#> Using GITHUB_PAT from Jennifer (Jenny) Bryan (credential helper: osxkeychain) -``` - -Other functions are available if you need more control, such as `credentials::git_credential_forget()` for clearing a credential. - -### Store credentials through organic Git use - -*Before gitcreds and credentials existed (see above), we had to store the PAT through organic Git use. -We still show this method, but we now recommend using the approaches above, because they are much more direct.* - -Pre-requisite: You need a functioning test Git repository. -One that exists locally and remotely on GitHub, with the local repo tracking the remote. - -If you have just verified that you can interact with GitHub (chapter \@ref(push-pull-github)) from your local computer, that test repo will be perfect. - -If you have just verified that you can work with GitHub from RStudio (chapter \@ref(rstudio-git-github)), that test repo will also be perfect. - -You may proceed when - - * You have a test repo. - * You know where it lives on your local computer. Example: - - `/home/jenny/tmp/myrepo` - * You know where it lives on GitHub. Example: - - `https://github.com/jennybc/myrepo` - * You know the GitHub repo is setup as a remote. In a shell (Appendix \@ref(shell)) working directory set to the local Git repo, enter: - - git remote -v - - Output like this confirms that fetch and push are set to remote URLs that point to your GitHub repo: - - origin https://github.com/jennybc/myrepo (fetch) - origin https://github.com/jennybc/myrepo (push) - - Now enter: - - git branch -vv - - Here we confirm that the local `master` branch is tracking your GitHub master branch (`origin/master`). Gibberish? Just check that your output looks similar to mine: - - master b8e03e3 [origin/master] line added locally - -Trigger a username / password challenge - -Change a file in your local repo and commit it. -Do that however you wish. Here are shell commands that will work: - - echo "adding a line" >> README.md - git add -A - git commit -m "A commit from my local computer" - -Now push! - - git push -u origin master - -You should be asked for your username and password. -If you've taken our advice to get a PAT, **provide your PAT as the password**. -Hopefully, this credential will be stored. - -Now push AGAIN. - - git push - -You should NOT be asked for your username and password, instead you should see `Everything up-to-date`. - -Rejoice and close the shell. - -### Access the Git credential manager directly - -This is not a recommended interface for regular Git users. -It is what the gitcreds and credentials packages and command line Git do on your behalf, when they need a credential. - -But for completeness, let it be known that, behind the scenes, there is the [`git credential `](https://git-scm.com/docs/git-credential) command. -For keeners, that documentation can shed some light on how credentials are stored and looked up. - -### Access the OS-level keychain or wallet - -On Windows, your Git credentials are probably being stored via Credential Manager. - -On macOS, your Git credentials are probably being stored in the Keychain. - -So if you really want to poke around directly to explore or clean out your GitHub credentials, launch Credential Manager (Windows) or Keychain Access (macOS) and search for "github.com". - -## Activating a Git credential helper - -### You might not need to do anything! - -As of October 2020, if you install Git using the [methods recommended here in Happy Git](#install-git), it is likely that Git is already configured to use a credential helper, backed by a proper credential store provided by your operating system. -Of course, you will have to provide your credential at least once, but most users do not need to do anything special to arrange for their credentials to be stored and retrieved later. - -Specifically, if you are on macOS or Windows, don't do anything described here until you have actual proof that it's necessary, i.e. until you have experienced repeated challenges for your credentials when using HTTPS. - -### Windows - -In my most recent experiments, Git for Windows is configured to store credentials via the Credential Manager. - -Here’s a command to reveal the configuration and the output I see in a fresh installation of Git for Windows: - -``` bash -$ git config --show-origin --get credential.helper -file:C:/Program Files/Git/mingw64/etc/gitconfig manager -``` - -In the unlikely event that you need to activate a credential helper, GitHub's instructions are the best bet, in terms of being current: - -[Caching your GitHub credentials in Git](https://docs.github.com/en/free-pro-team@latest/github/using-git/caching-your-github-credentials-in-git) - -### macOS - -I have not needed to explicitly activate a credential helper on macOS in a long while. - -Here’s a command to reveal the current credential helper and the output I see (October 2020, macOS 10.15.6, Git 2.24.3): - -``` bash -$ git config --show-origin --get credential.helper -file:/Users/jenny/.gitconfig osxkeychain -``` - -I expect most users to see the `osxkeychain` helper, configured either at the system or user level. - -In the unlikely event that you need to activate a credential helper, GitHub's instructions are the best bet, in terms of being current: - -[Caching your GitHub credentials in Git](https://docs.github.com/en/free-pro-team@latest/github/using-git/caching-your-github-credentials-in-git) - -### Linux - -As opposed to Windows and macOS, Linux users are the ones for whom credential storage may not "just work" out of the box. -The easiest thing to do is to configure Git to "cache" your credentials (vs "store"), which is more time-limited. -Then set the cache timeout to some suitably long period of time. -You can expect to re-enter your PAT more often than Windows and macOS users. - -We paraphrase the Linux instructions from GitHub's documentation [Caching your GitHub credentials in Git](https://docs.github.com/en/free-pro-team@latest/github/using-git/caching-your-github-credentials-in-git), which should be regarded the best and most current source. - -In the shell, turn on the "cache" credential helper and set its timeout: - -``` bash -git config --global credential.helper 'cache --timeout=10000000' -``` - -Above, we set the timeout to ten million seconds or around 16 weeks, enough for a semester. diff --git a/connect-git-github.Rmd b/connect-git-github.Rmd index 4f3df604..e346dd78 100644 --- a/connect-git-github.Rmd +++ b/connect-git-github.Rmd @@ -2,53 +2,73 @@ Objective: make sure that you can pull from and push to GitHub from your computer. -I do not explain all the shell (Appendix \@ref(shell)) and Git commands in detail. This is a black box diagnostic / configuration exercise. In later chapters and in live workshops, we revisit these operations with much more narrative. +I do not explain all the shell (Appendix \@ref(shell)) and Git commands in detail. +This is a black box diagnostic / configuration exercise. +In later chapters and in live workshops, we revisit these operations with much more narrative. + +I assume you've decided whether to use HTTPS (see chapter \@ref(https-pat) or SSH (see chapter \@ref(ssh-keys)) and you've prepared your credential. ## Make a repo on GitHub Go to and make sure you are logged in. -Click green "New repository" button. Or, if you are on your own profile page, click on "Repositories", then click the green "New" button. +Near "Repositories", click the big green "New" button. +Or, if you are on your own profile page, click on "Repositories", then click the big green "New" button. How to fill this in: - * Repository name: `myrepo` (or whatever you wish, we'll delete this soon anyway). - * Description: "testing my setup" (or whatever, but some text is good for the README). - * Public. - * YES Initialize this repository with a README. +* Repository template: No template. +* Repository name: `myrepo` (or whatever you wish, we'll delete this soon anyway). +* Description: "testing my setup" (or whatever, but some text is good for the README). +* Public. +* Initialize this repository with: Add a README file. -For everything else, just accept the default. - -Click big green button "Create repository." +Click the big green button that says "Create repository". + +Now click the big green button that says "<> Code". -Copy the HTTPS clone URL to your clipboard via the green "Clone or Download" button. +Copy a clone URL to your clipboard. +If you're taking our default advice, copy the HTTPS URL. +But if you're opting for SSH, then make sure to copy the SSH URL. ## Clone the repo to your local computer +We have a few ways to do this: with command line Git or via RStudio. + +### Clone with command line Git + Go to the shell (Appendix \@ref(shell)). -Take charge of -- or at least notice! -- what directory you're in. `pwd` displays the working directory. `cd` is the command to change directory. Personally, I would do this sort of thing in `~/tmp`. +Take charge of -- or at least notice! -- what directory you're in. +`pwd` displays the working directory. +`cd` is the command to change directory. +Personally, I would do this sort of thing in `~/tmp`. -Clone `myrepo` from GitHub to your computer. This URL should have **your GitHub username** and the name of **your practice repo**. If your shell (Appendix \@ref(shell)) cooperates, you should be able to paste the whole `https://....` bit that we copied above. But some shells are not (immediately) clipboard aware. In that sad case, you must type it. **Accurately.** +Clone `myrepo` from GitHub to your computer. +Use the URL we just copied from GitHub. +This URL should have **your GitHub username** and the name of **your practice repo**. +If your shell (Appendix \@ref(shell)) cooperates, you should be able to paste the whole `https://....` bit that we copied above. +But some shells are not (immediately) clipboard aware. +In that sad case, you must type it. **Accurately.** -``` bash +```console git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git ``` This should look something like this: -``` bash -jenny@2015-mbp tmp $ git clone https://github.com/jennybc/myrepo.git +```console +~/tmp % git clone https://github.com/jennybc/myrepo.git Cloning into 'myrepo'... -remote: Counting objects: 3, done. +remote: Enumerating objects: 3, done. +remote: Counting objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 -Unpacking objects: 100% (3/3), done. -Checking connectivity... done. +Receiving objects: 100% (3/3), done. ``` Make this new repo your working directory, list its files, display the README, and get some information on its connection to GitHub: -``` bash +```console cd myrepo ls head README.md @@ -58,104 +78,130 @@ git remote show origin This should look something like this: ``` bash -jenny@2015-mbp ~ $ cd myrepo +~/tmp % cd myrepo -jenny@2015-mbp myrepo $ ls +~/tmp/myrepo % ls README.md -jenny@2015-mbp myrepo $ head README.md +~/tmp/myrepo % head README.md # myrepo -tutorial development +checking stuff for Happy Git -jenny@2015-mbp myrepo $ git remote show origin +~/tmp/myrepo % git remote show origin * remote origin Fetch URL: https://github.com/jennybc/myrepo.git Push URL: https://github.com/jennybc/myrepo.git - HEAD branch: master + HEAD branch: main Remote branch: - master tracked + main tracked Local branch configured for 'git pull': - master merges with remote master + main merges with remote main Local ref configured for 'git push': - master pushes to master (up to date) + main pushes to main (up to date) ``` ## Make a local change, commit, and push Add a line to README and verify that Git notices the change: -``` bash -echo "A line I wrote on my local computer" >> README.md +```console +echo "A line I wrote on my local computer " >> README.md git status ``` This should look something like this: -``` bash -jenny@2015-mbp myrepo $ echo "A line I wrote on my local computer" >> README.md -jenny@2015-mbp myrepo $ git status -On branch master -Your branch is up-to-date with 'origin/master'. +```console +~/tmp/myrepo % echo "A line I wrote on my local computer" >> README.md + +~/tmp/myrepo % git status +On branch main +Your branch is up to date with 'origin/main'. + Changes not staged for commit: (use "git add ..." to update what will be committed) - (use "git checkout -- ..." to discard changes in working directory) - - modified: README.md + (use "git restore ..." to discard changes in working directory) + modified: README.md no changes added to commit (use "git add" and/or "git commit -a") ``` -Stage ("add") and commit this change and push to your remote repo on GitHub. If you're a new GitHub user, you will be challenged for your GitHub username and password. Provide them! +Stage ("add") and commit this change and push to your remote repo on GitHub. -``` bash -git add -A +If you're a new GitHub user and using HTTPS, you might be challenged for your username and password. +Even though GitHub no longer allows username/password authentication, many general Git tools still frame the authentication task with this vocabulary. +By all means, provide your GitHub username when prompted. +However, the most critical piece is to **provide your PAT as the password**. +Do not enter your web password. +Enter your PAT. +If you already stored your PAT with `gitcreds::gitcreds_set()`, it should be discovered automatically and you will not see a credential challenge. + +```console +git add README.md git commit -m "A commit from my local computer" git push ``` -The `-m "blah blah blah"` piece is very important! Git requires a commit message for every commit, so if you forget the `-m` flag, Git will prompt you for a commit message anyway. And you might not like [the editor that Git chooses](#git-editor). It is good practice to write meaningful commit messages, so that, in the future, potential collaborators (and your future self) will understand the progression of a project. - This should look something like this: -``` bash -jenny@2015-mbp myrepo $ git add -A +```console +~/tmp/myrepo % git add README.md -jenny@2015-mbp myrepo $ git commit -m "A commit from my local computer" -[master de669ba] A commit from my local computer +~/tmp/myrepo % git commit -m "A commit from my local computer" +[main e92528c] A commit from my local computer 1 file changed, 1 insertion(+) -jenny@2015-mbp myrepo $ git push -Counting objects: 3, done. -Delta compression using up to 8 threads. +~/tmp/myrepo % git push +Enumerating objects: 5, done. +Counting objects: 100% (5/5), done. +Delta compression using up to 12 threads Compressing objects: 100% (2/2), done. -Writing objects: 100% (3/3), 311 bytes | 0 bytes/s, done. -Total 3 (delta 0), reused 0 (delta 0) +Writing objects: 100% (3/3), 327 bytes | 327.00 KiB/s, done. +Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 To https://github.com/jennybc/myrepo.git - b4112c5..de669ba master -> master + 31dcaef..e92528c main -> main ``` +Do you see an error like this? + +```console +~/tmp/myrepo % git push +remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead. +remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information. +fatal: Authentication failed for 'https://github.com/jennybc/myrepo.git/' +``` + +This means you have provided your GitHub _web password_, instead of your _personal access token_ (PAT). +Go back to chapter \@ref(https-pat) to get a PAT. +Try `git push` again and hopefully you'll get another prompt, allowing you to correct things and provide your PAT. + +If you ever feel you need to overwrite a bad credential with a new one, the easiest way to do this is to call `gitcreds::gitcreds:set()` from R. + ### Windows and line endings -On Windows, you might see a message about `LF will be replaced by CRLF`. This is normal and does not require any action on your part. Windows handles line endings differently from other operating systems, but the default setup for Git for Windows is appropriate for most people and situations. +On Windows, you might see a message about `LF will be replaced by CRLF`. This is normal and does not require any action on your part. +Windows handles line endings differently from other operating systems, but the default setup for Git for Windows is appropriate for most people and situations. Here's a command to reveal the current line ending configuration and some typical output **on Windows**: -``` bash +```console $ git config --show-origin --get core.autocrlf file:"C:\\ProgramData/Git/config" true ``` If your value shows as `false`, you can set it to `true` with this command: -``` bash +```console $ git config --global core.autocrlf true ``` -`true` is the current default setting for `core.autocrlf` for [Git for Windows](#install-git-windows), our recommended method for installing Git on Windows. The need to set this explicitly in your global user config suggests you should consider reinstalling or updating Git for Windows. +`true` is the current default setting for `core.autocrlf` for [Git for Windows](#install-git-windows), our recommended method for installing Git on Windows. +The need to set this explicitly in your global user config suggests you should consider reinstalling or updating Git for Windows. ## Confirm the local change propagated to the GitHub remote -Go back to the browser. I assume we're still viewing your new GitHub repo. +Go back to the browser. +I assume we're still viewing your new GitHub repo. Refresh. @@ -163,34 +209,22 @@ You should see the new "A line I wrote on my local computer" in the README. If you click on "commits," you should see one with the message "A commit from my local computer." -If you have made it this far, you are ready to graduate to using Git and GitHub with RStudio (chapter \@ref(rstudio-git-github)). But first ... - -## Am I really going to type GitHub username and password on each push? - -It is likely that your first push, above, leads to a challenge for your GitHub username and password. This will drive you crazy in the long-run and make you reluctant to push. You want to eliminate this annoyance. - -Luckily, if you've installed Git one of the ways recommended by Happy Git, it is likely that Git is already using a credential helper provided by your operating system! If so, your GitHub credentials were cached when you successfully pushed above. This setup applies across repos, i.e. it's not limited to our current test repo. - -I suggest you make another local change to README.md, stage (i.e. "add") it, commit it, and push, using the commands shown above. If this "just works" and shows up on GitHub, rejoice. You are ready to work with GitHub via HTTPS without constantly re-entering your credentials. You are ready to delete this toy repo. - -If you are challenged for your username and password *again*, do one of the following: - - * Cache credentials for HTTPS access, chapter \@ref(credential-caching). - * Set up SSH keys, chapter \@ref(ssh-keys). - -Now is the perfect time to do this, since you have a functioning test repo. +If you have made it this far, you and your test repo are ready to graduate to using Git and GitHub with RStudio (chapter \@ref(rstudio-git-github)). ## Clean up +If you're ready to conclude this test of your Git installation and GitHub configuration, we can clean up the test repository now. + **Local** When you're ready to clean up, you can delete the local repo any way you like. It's just a regular directory on your computer. Here's how to do that in the shell, if current working directory is `myrepo`: -``` bash +```console cd .. rm -rf myrepo/ ``` -**GitHub** In the browser, go to your repo's landing page on GitHub. Click on "Settings". +**GitHub** In the browser, go to your repo's landing page on GitHub. +Click on "Settings". Scroll down, click on "delete repository," and do as it asks. diff --git a/connect-https-pat.Rmd b/connect-https-pat.Rmd new file mode 100644 index 00000000..bfd00e26 --- /dev/null +++ b/connect-https-pat.Rmd @@ -0,0 +1,453 @@ +# Personal access token for HTTPS {#https-pat} + +When we interact with a remote Git server, such as GitHub, we have to include credentials in the request. +This proves we are a specific GitHub user, who's allowed to do whatever we're asking to do. + +Git can communicate with a remote server using one of two protocols, HTTPS or SSH, and the different protocols use different credentials. + +Here we describe the credential setup for the HTTPS protocol, which is what we recommend if you have no burning reason to pick SSH. +With HTTPS, we will use a **personal access token (PAT)**. +Head over to chapter \@ref(ssh-keys) if you really want to set up SSH keys. + +Let it be known that the password that you use to login to GitHub's website is NOT an acceptable credential when talking to GitHub as a Git server. +This was possible in the past (and may yet be true for other Git servers), but those days are over at GitHub. +You can learn more in their blog post [Token authentication requirements for Git operations](https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/). + +Here's the error you'll see if you try to do that now: + +```console +remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead. +remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information. +fatal: Authentication failed for 'https://github.com/OWNER/REPO.git/' +``` + +The recommendation to use a personal access token (PAT) is exactly what we cover in this chapter. + +## TL;DR + +This is a very minimal account of getting and storing a PAT. +This might be all you need when you're first getting yourself set up. +You can always come back later and read other parts of this chapter. + +Go to and click "Generate token". + +Or, from R, do: + +```{r eval = FALSE} +usethis::create_github_token() +``` + +Look over the scopes; I highly recommend selecting "repo", "user", and "workflow". +Recommended scopes will be pre-selected if you used `create_github_token()`. + +Click "Generate token". + +Copy the generated PAT to your clipboard. +Or leave that browser window open and available for a little while, so you can come back to copy the PAT. + +Provide this PAT next time a Git operation asks for your password[^pat-not-password]. + +[^pat-not-password]: Yes, it's confusing that you might be prompted for a password, but you should enter your PAT. +GitHub no longer allows passwords in this context, but most basic Git tools still frame the authentication task with this language. + +You could even get out ahead of this and store the PAT explicitly right now. +In R, call `gitcreds::gitcreds_set()` to get a prompt where you can paste your PAT: + +```{sh eval = FALSE} +> gitcreds::gitcreds_set() + +? Enter password or token: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +-> Adding new credentials... +-> Removing credentials from cache... +-> Done. +``` + +You should be able to work with GitHub now, i.e. push and pull. +If you're still doing your initial setup, now is a great time to move on to [Connect to GitHub](#push-pull-github). + +Read on to learn more about: + +* [How to decide between the HTTPS and SSH protocols](#https-vs-ssh) +* [PAT scopes, names, and expiration](#get-a-pat) +* [PAT storage](#store-pat) +* [Troubleshooting](#pat-troubleshooting) + +## HTTPS versus SSH {#https-vs-ssh} + +I find HTTPS easier to get working quickly and **strongly recommend** it when you first start working with Git/GitHub. +HTTPS is what GitHub recommends, presumably for exactly the same reasons. +The "ease of use" argument in favor of HTTPS is especially true for Windows users. +I started with HTTPS, preferred SSH for a while, and have returned to HTTPS. +The main thing to know is that this is not an all-or-nothing decision and it's a relatively easy decision to revisit later. + +Another advantage of HTTPS is that the PAT we'll set up for that can also be used with GitHub's REST API. +That might not mean anything to you (yet), but there are many R packages that call GitHub's API on your behalf (devtools+usethis, remotes, pak, gh, etc.). +Configuring your PAT kills two birds with one stone: this single credential can be used to authenticate to GitHub as a regular Git server and for its REST API. +If you authenticate via SSH for "regular" Git work, you will still have to set up a PAT for work that uses the REST API. + +```{r} +#| echo = FALSE, fig.align = "center", out.width = "80%", +#| fig.alt = "Diagram showing different ways of interacting with GitHub as a server and the credential needed for each method" +knitr::include_graphics("img/pat-kills-both-birds.jpeg") +``` + +A properly configured PAT means all of this will "just work": + + * Remote HTTPS operations via command line Git and, therefore, via RStudio + * Remote HTTPS operations via the gert R package and, therefore, usethis + * GitHub API operations via the gh R package and, therefore, usethis + +### URL determines the protocol {#url-determines-protocol} + +Even though I'm suggesting that you adopt HTTPS as a lifestyle, it's good to know that you actually have very granular control over the protocol. +It is determined by the URL used to access a remote repo. +Feel free to skip this section if you are new to Git (we mention some concepts and commands that won't make much sense 'til you've used Git a little). + +HTTPS remote URLs look like `https://github.com//.git`. +SSH remote URLs look like `git@github.com:/.git`. + +*TO ADD: screenshot of making this choice in GitHub* + +When you execute a command such as `git push origin my-cool-feature-branch`, Git looks up the URL you've stored for the `origin` remote and uses the protocol implicit in the URL's format. +The protocol is a game time decision. + +This implies that: + +* It's fine to use HTTPS for one remote in a repo and SSH for another. +* It's fine to use HTTPS in one repo and SSH in another. +* It's fine to interact with a GitHub repo via HTTPS from one computer and via SSH from another. +* It's fine to adopt HTTPS for new work, even if some of your pre-existing repos use SSH. + +You just have to be aware that mixed use of HTTPS and SSH means you'll have to configure both sorts of credentials. + +Changing a specific remote from HTTPS to SSH (and back again) is a straightforward operation with `git remote set-url REMOTE_NAME DESIRED_URL`: + +```console +~/rrr/happy-git-with-r % git remote -v +origin https://github.com/jennybc/happy-git-with-r.git (fetch) +origin https://github.com/jennybc/happy-git-with-r.git (push) + +~/rrr/happy-git-with-r % git remote set-url origin git@github.com:jennybc/happy-git-with-r.git + +~/rrr/happy-git-with-r % git remote -v +origin git@github.com:jennybc/happy-git-with-r.git (fetch) +origin git@github.com:jennybc/happy-git-with-r.git (push) + +~/rrr/happy-git-with-r % git remote set-url origin https://github.com/jennybc/happy-git-with-r.git +``` + +We can do the same from R using functions in usethis: + +```{r eval = FALSE} +usethis::git_remotes() +#> $origin +#> [1] "https://github.com/jennybc/happy-git-with-r.git" + +usethis::use_git_remote( + "origin", + "git@github.com:jennybc/happy-git-with-r.git", + overwrite = TRUE +) + +usethis::git_remotes() +#> $origin +#> [1] "git@github.com:jennybc/happy-git-with-r.git" + +usethis::use_git_remote( + "origin", + "https://github.com/jennybc/happy-git-with-r.git", + overwrite = TRUE +) +``` + +## Generate a personal access token (PAT) {#get-a-pat} + +On github.com, assuming you're signed in, you can manage your personal access tokens from , also reachable via *Settings > Developer settings > Personal access tokens*. +You could click on "Generate new token" here or, perhaps even better, you could call `usethis::create_github_token()` from R: + +```{r eval = FALSE} +usethis::create_github_token() +``` + +The usethis approach takes you to a pre-filled form where we have pre-selected some recommended scopes, which you can look over and adjust before clicking "Generate token". +At the time of writing, the usethis-recommended scopes are "repo", "user", "gist", and "workflow". + +```{r} +#| echo = FALSE, fig.align='center', out.width="100%", +#| fig.alt = "Screenshot: Getting a new personal access token on GitHub" +knitr::include_graphics("img/new-personal-access-token-screenshot.png") +``` + +It is a very good idea to describe the token's purpose in the *Note* field, because one day you might have multiple PATs. +We recommend naming each token after its use case, such as the computer or project you are using it for, e.g. "personal-macbook-air" or "vm-for-project-xyz". +In the future, you will find yourself staring at this list of tokens, because inevitably you'll need to re-generate or delete one of them. +Make it easy to figure out which token you've come here to fiddle with. + +GitHub encourages the use of perishable tokens, with a default *Expiration* period of 30 days. +Unless you have a specific reason to fight this, I recommend accepting this default. +I assume that GitHub's security folks have good reasons for their recommendation. +But, of course, you can adjust the *Expiration* behaviour as you see fit, including "No expiration". + +Once you're happy with the token's *Note*, *Expiration*, and *Scopes*, click "Generate token". + +You won't be able to see this token again, so don't close or navigate away from this browser window until you store the PAT locally. +Copy the PAT to the clipboard, anticipating what we'll do next: trigger a prompt that lets us store the PAT in the Git credential store. + +Treat this PAT like a password! +Do not ever hard-wire your PAT into your code! +A PAT should always be retrieved implicitly, for example, from the Git credential store. +We're about to help you store the PAT in a safe place, where command line Git, RStudio, and R packages can discover it. + +If you use a password management app, such as 1Password or LastPass (highly recommended!), you might want to also add this PAT (and its *Note*) to the entry for GitHub, where you're already storing your username and password. +Storing your PAT in the Git credential store is a semi-persistent convenience, sort of like a browser cache or "remember me" on a website[^remember-me-haha] and it's conceivable you will need to re-enter your PAT in the future. +You could decide to embrace the impermanence of your PAT and, if it somehow goes missing, you'll just [re-generate the PAT and re-store it](#regenerate-pat). +If you accept the default 30-day expiration period, this is a workflow you'll be using often anyway. +But if you create long-lasting tokens or want to feel free to play around with the functions for setting or clearing your Git credentials, it can be handy to have your own record of your PAT in a secure place, like 1Password or LastPass. + +[^remember-me-haha]: Haha! We all know how well "remember me" works. + +## Store your PAT {#store-pat} + +At this point, I assume you've generated a PAT and have it available, in one or both of these ways: + + * In a secure, long-term system for storing secrets, like 1Password or LastPass + * For the next few minutes, in a browser window or on the clipboard + +There are a couple ways to get your PAT into the Git credential store: + + * Call an R function to explicitly store (or update) your credentials. + * Do something in command line Git or RStudio that triggers a credential + challenge. + +### Call an R function to store your credentials + +There are two R packages for accessing the Git credential store: + + * [gitcreds](https://r-lib.github.io/gitcreds/) + * [credentials](https://docs.ropensci.org/credentials/) + +It is likely that these packages will eventually combine into one and, even now, they are largely interoperable. +You don't need to follow the instructions for both packages -- pick one! + +#### gitcreds package + +If you don't have gitcreds installed, install via `install.packages("gitcreds")`. +If you've installed usethis, you will already have gitcreds, because usethis uses gh and gh uses gitcreds. + +Call `gitcreds::gitcreds_set()`. +If you don't have a PAT stored already, it will prompt you to enter your PAT. Paste! + +```{sh eval = FALSE} +> gitcreds::gitcreds_set() + +? Enter password or token: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +-> Adding new credentials... +-> Removing credentials from cache... +-> Done. +``` + +If you already have a stored credential, `gitcreds::gitcreds_set()` reveals this and will even let you inspect it. +This helps you decide whether to keep the existing credential or replace it. +When in doubt, embrace a new, known-to-be-good credential over an old one, of dubious origins. + +```{sh eval = FALSE} +> gitcreds::gitcreds_set() + +-> Your current credentials for 'https://github.com': + + protocol: https + host : github.com + username: PersonalAccessToken + password: <-- hidden --> + +-> What would you like to do? + +1: Keep these credentials +2: Replace these credentials +3: See the password / token + +Selection: 2 + +-> Removing current credentials... + +? Enter new password or token: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +-> Adding new credentials... +-> Removing credentials from cache... +-> Done. +``` + +You can check that you've stored a credential with `gitcreds_get()`: + +```{r eval = FALSE} +gitcreds_get() +#> +#> protocol: https +#> host : github.com +#> username: PersonalAccessToken +#> password: <-- hidden --> +``` + +Other functions that can help you feel confident about your PAT setup include: + +```{r eval = FALSE} +usethis::gh_token_help() + +usethis::git_sitrep() + +gh::gh_whoami() +``` + +#### credentials package + +If you don't have credentials installed, install via `install.packages("credentials")`. +If you've installed usethis, you will already have credentials, because usethis uses gert and gert uses credentials. + +Call `set_github_pat()`. +If you don't have a PAT stored already, it will prompt you to enter your PAT. Paste! + +```{r eval = FALSE} +credentials::set_github_pat() +``` + +If successful, your initial (and subsequent) calls will look like this: + +```{r eval = FALSE} +credentials::set_github_pat() +#> If prompted for GitHub credentials, enter your PAT in the password field +#> Using GITHUB_PAT from Jennifer (Jenny) Bryan (credential helper: osxkeychain) +``` + +Other functions that can help you feel confident about your PAT setup include: + +```{r eval = FALSE} +usethis::gh_token_help() + +usethis::git_sitrep() + +gh::gh_whoami() +``` + +### Store credentials through organic Git use + +*Before gitcreds and credentials existed (see above), we had to orchestrate a credential challenge by setting up (and then tearing down) a toy repo. +That still occurs naturally in the guided exercise in [Connect to GitHub]. +But I strongly recommend managing your PAT more directly and explicitly with +`gitcreds::gitcreds_set()` and related functions in gitcreds.* + +## HTTPS PAT problems and solutions {#pat-troubleshooting} + +This section is for people who need to know even more about PAT management, because they're in a nonstandard situation or troubleshooting. + +### Valid PAT gets stored, but later told the PAT is invalid + +Let's say you generate a fresh PAT and successfully store it as described above. +Maybe you even use it successfully. +But later, you're told your PAT is invalid! +How can this be? + +Here are some likely explanations: + +1. Your PAT truly is invalid. By default, PATs have an expiration date now. One + day you really will wake up and find the PAT has gone bad overnight and you + need to re-generate and re-store it. +1. You have an invalid PAT stored *somewhere else*, that you've forgotten about, + probably in `.Renviron`. This old, invalid PAT is preventing R packages from + even discovering your new, valid PAT. + +#### PAT has expired {#regenerate-pat} + +You are going to be re-generating and re-storing your PAT on a schedule dictated by its expiration period. +By default, once per month. + +When the PAT expires, return to and click on its *Note*. +(You do label your tokens nicely by use case, right? Right?) +At this point, you can optionally adjust scopes and then click "Regenerate token". +You can optionally modify its *Expiration* and then click "Regenerate token" (again). +As before, copy the PAT to the clipboard, call `gitcreds::gitcreds_set()`, and paste! + +Hopefully it's becoming clear why each token's *Note* is so important. +The actual token may be changing, e.g., once a month, but its use case (and scopes) are much more persistent and stable. + +#### Old `GITHUB_PAT` in `.Renviron` + +These usethis functions will diagnose this problem: + +```{r eval = FALSE} +usethis::gh_token_help() + +usethis::git_sitrep() +``` + +In the past, it was common to store a PAT as the `GITHUB_PAT` environment variable in `.Renviron`. +But now, thanks to gitcreds and credentials, we can store and retrieve a PAT, from R, the same way as command line Git does. + +If you have any doubt about your previous practices, open `.Renviron`, look for a line setting the `GITHUB_PAT` environment variable, and delete it. `usethis::edit_r_environ()` can be helpful for getting `.Renviron` open for editing. +Don't forget to restart R for this change to take effect. + +### PAT doesn't persist on macOS or Windows + +The credential helpers used by Git take advantage of official OS-provided credential stores, where possible, such as macOS Keychain and Windows Credential Manager. + +If you're trying to follow the advice here and your PAT never persists, consider that you may need to update Git to get its more modern credential helpers. +This is absolutely an area of Git that has improved rapidly in recent years and the gitcreds and credentials package work best with recent versions of Git. +I have not needed to explicitly activate a credential helper on macOS or Windows with any recent version of Git. + +Here's a command to reveal the current credential helper and what I see these days. + +macOS + +```console +$ git config --show-origin --get credential.helper +file:/Users/jenny/.gitconfig osxkeychain +``` + +Windows + +```console +$ git config --show-origin --get credential.helper +file:C:/Program Files/Git/mingw64/etc/gitconfig manager +``` + +If you want to know how more about how gitcreds and credentials are managing your PAT, learn about [`git credential `](https://git-scm.com/docs/git-credential). +For keeners, that documentation gives you the gory details on how credentials are stored and retrieved: + +> Git has an internal interface for storing and retrieving credentials from system-specific helpers, as well as prompting the user for usernames and passwords. The `git-credential` command exposes this interface to scripts which may want to retrieve, store, or prompt for credentials in the same manner as Git. + +On Windows, your Git credentials are probably being stored via Credential Manager. + +On macOS, your Git credentials are probably being stored in the Keychain. + +If you really want to poke around directly to explore or clean out your GitHub credentials, launch Credential Manager (Windows) or Keychain Access (macOS) and search for "github.com". + +### PAT doesn't persist on Linux + +The credential helpers used by Git take advantage of official OS-provided +credential stores on macOS and Windows, but sadly there is no exact equivalent on Linux. + +The easiest thing to do is to configure Git to "cache" your credentials (vs "store"), which is more time-limited. +Then set the cache timeout to some suitably long period of time. +Here, we set the timeout to ten million seconds or around 16 weeks, enough for a semester. + +```console +git config --global credential.helper 'cache --timeout=10000000' +``` + +This still may not make your PAT available to R packages. +In this case, you may need to use the older, less secure approach of storing your PAT in `.Renviron`. +`usethis::edit_r_environ()` opens that file for editing. + +```{r, eval = FALSE} +usethis::edit_r_environ() +``` + +Add a line like this, but substitute your PAT: + +```{sh, eval = FALSE} +GITHUB_PAT=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +``` + +Make sure this file ends in a newline! +Lack of a newline can lead to silent failure to load startup files, which can be tricky to debug. +Take care that this file is not accidentally pushed to the cloud, e.g. Google Drive or GitHub. + +Restart R for changes in `.Renviron` to take effect. diff --git a/connect-intro.Rmd b/connect-intro.Rmd index b3f14db1..80732e5a 100644 --- a/connect-intro.Rmd +++ b/connect-intro.Rmd @@ -6,9 +6,11 @@ The next few chapters walk through some basic operations to confirm you have ins This has a lot of overlap with some basic workflows we revisit later, but the second time around (or in a live workshop), we'll spend more time explaining what's happening and why. -In [Connect to GitHub] we use Git in the shell to make sure you can clone a repo from GitHub and establish two-way communications. +Unfortunately, we have to front-load a rather fiddly task, which is to decide whether to communicate with GitHub via HTTPS or SSH and setup some credentials accordingly. +In [Personal access token for HTTPS] we discuss how to choose between HTTPS and SSH and then walk through obtaining a personal access token, which is used with HTTPS. +Or, alternatively, we will help you [Set up keys for SSH]. -In [Cache credentials for HTTPS] and [Set up keys for SSH] we present two approaches for persistently authenticating yourself with GitHub, so you don't need to provide credentials *ad nauseam*. +Once we have our credentials sorted out, in [Connect to GitHub], we use Git in the shell to make sure you can clone a repo from GitHub and establish two-way communications, i.e. pull and push. In [Connect RStudio to Git and GitHub] we confirm that RStudio can work with your Git installation to perform local operations and communicate with GitHub. diff --git a/connect-rstudio-git-github.Rmd b/connect-rstudio-git-github.Rmd index 0280c351..5d095c2f 100644 --- a/connect-rstudio-git-github.Rmd +++ b/connect-rstudio-git-github.Rmd @@ -1,6 +1,7 @@ # Connect RStudio to Git and GitHub {#rstudio-git-github} -Here we verify that RStudio can issue Git commands on your behalf. Assuming that you've gotten local Git to talk to GitHub, this means you'll also be able to pull from and push to GitHub from RStudio. +Here we verify that RStudio can issue Git commands on your behalf. +Assuming that you've gotten local Git to talk to GitHub, this means you'll also be able to pull from and push to GitHub from RStudio. In later chapters and in live workshops, we revisit these operations with much more explanation. @@ -15,27 +16,46 @@ We assume the following: * You've installed Git (chapter \@ref(install-git)). * You've introduced yourself to Git (chapter \@ref(hello-git)). * You've confirmed that you can push to / pull from GitHub from the command line (chapter \@ref(push-pull-github)). + +You will also need a test repository on GitHub. + +If you just completed the previous chapter, [Connect to GitHub], that will be perfect! +However, I encourage you to delete the *local* repository, so you can experience how we use RStudio to clone it and get a local copy. +Delete the folder corresponding to the local repo any way you like. +It's just a regular directory on your computer. +Here's how to do that in the shell, if current working directory is `myrepo`: + +```console +cd .. +rm -rf myrepo/ +``` + +If you don't have a suitable test repository on GitHub, follow the instructions in the next section. ## Make a repo on GitHub Go to and make sure you are logged in. -Click the green "New repository" button. Or, if you are on your own profile page, click on "Repositories", then click the green "New" button. +Near "Repositories", click the big green "New" button. +Or, if you are on your own profile page, click on "Repositories", then click the big green "New" button. How to fill this in: - * Repository name: `myrepo` (or whatever you wish, we'll delete this soon anyway). - * Description: "testing my setup" (or whatever, but some text is good for the README). - * Public. - * YES Initialize this repository with a README. +* Repository template: No template. +* Repository name: `myrepo` (or whatever you wish, we'll delete this soon anyway). +* Description: "testing my setup" (or whatever, but some text is good for the README). +* Public. +* Initialize this repository with: Add a README file. -For everything else, just accept the default. - -Click the big green button "Create repository." +Click the big green button that says "Create repository". + +Now click the big green button that says "<> Code". -Copy the HTTPS clone URL to your clipboard via the green "Clone or Download" button. +Copy a clone URL to your clipboard. +If you're taking our default advice, copy the HTTPS URL. +But if you're opting for SSH, then make sure to copy the SSH URL. -## Clone the new GitHub repository to your computer via RStudio +## Clone the test GitHub repository to your computer via RStudio In RStudio, start a new Project: @@ -46,7 +66,9 @@ In RStudio, start a new Project: * I suggest you check "Open in new session", as that's what you'll usually do in real life. * Click "Create Project". -You should find yourself in a new local RStudio Project that represents the new test repo we just created on GitHub. This should download the `README.md` file from GitHub. Look in RStudio's file browser pane for the `README.md` file. +You should find yourself in a new local RStudio Project that represents your test repo on GitHub. +This should download the `README.md` file from GitHub. +Look in RStudio's file browser pane for the `README.md` file. ## Make local changes, save, commit @@ -64,18 +86,16 @@ From RStudio: ## Push your local changes online to GitHub -Click the green "Push" button to send your local changes to GitHub. If you are challenged for username and password, provide them (but see below). You should see some message along these lines. +Click the green "Push" button to send your local changes to GitHub. -``` bash -[master dc671f0] blah - 3 files changed, 22 insertions(+) - create mode 100644 .gitignore - create mode 100644 myrepo.Rproj -``` +You should not experience a credential challenge, since one of the pre-requisites was successfully pushing to GitHub from the command line (chapter \@ref(push-pull-github)). +RStudio's Git pane just exposes a specific subset of command line Git and therefore once your credentials work in the shell, they should work in RStudio. +If you do experience a credential challenge, that suggests you should have a look at the troubleshooting suggestions for your chosen protocol, either [HTTPS](#pat-troubleshooting) or [SSH](#ssh-troubleshooting). ## Confirm the local change propagated to the GitHub remote -Go back to the browser. I assume we're still viewing your new GitHub repo. +Go back to the browser. +I assume we're still viewing your new GitHub repo. Refresh. @@ -83,25 +103,24 @@ You should see the new "This is a line from RStudio" in the README. If you click on "commits", you should see one with the message "Commit from RStudio". -If you have made it this far, you are DONE with set up. But first ... - -## Were you challenged for GitHub username and password? - -If you somehow haven't done so yet, now is the perfect time to make sure you don't need to keep providing username and password on each push. - -First, make another small change locally and push again, to make sure we've given your system every opportunity to cache your credentials and retrieve them from the cache. It might "just work". +If you have made it this far, you are DONE with set up. +Congratulations! -Are you still challenged? Pick one: +## Clean up - * Credential caching for HTTPS access, chapter \@ref(credential-caching). - * Set up SSH keys, chapter \@ref(ssh-keys). +Quit the RStudio instance that's open to your test Project / Git repo. -Now is the perfect time to do this, since you have a functioning test repo. +Delete the local repo any way you like. +It's just a regular directory on your computer. -## Clean up +Here's how to do that in the shell, if current working directory is `myrepo`: -**Local** When you're ready to clean up, you can delete the local repo any way you like. It's just a regular directory on your computer. +```console +cd .. +rm -rf myrepo/ +``` -**GitHub** In the browser, go to your repo's landing page on GitHub. Click on "Settings". +In the browser, go to your repo's landing page on GitHub. +Click on "Settings". Scroll down, click on "delete repository," and do as it asks. diff --git a/connect-ssh-keys.Rmd b/connect-ssh-keys.Rmd index 0c63992e..8327671c 100644 --- a/connect-ssh-keys.Rmd +++ b/connect-ssh-keys.Rmd @@ -1,6 +1,13 @@ # Set up keys for SSH {#ssh-keys} -If you plan to push/pull using SSH, you need to set up SSH keys. You want to do this (or cache your username and password, chapter \@ref(credential-caching)), so you don't have to authenticate yourself interactively with GitHub over and over again. I suggest you set up one of these methods of authentication on each computer you want to connect to GitHub from. +When we interact with a remote Git server, such as GitHub, we have to include credentials in the request. +This proves we are a specific GitHub user, who's allowed to do whatever we're asking to do. + +Git can communicate with a remote server using one of two protocols, HTTPS or SSH, and the different protocols use different credentials. + +Here we describe the credential setup for the SSH protocol. +If you're not sure whether to use HTTPS or SSH, please read [HTTPS versus SSH](#https-vs-ssh). +From now on, we assume you've made an intentional choice to set up SSH keys. ## SSH keys @@ -18,7 +25,7 @@ High level overview of what must happen: Advice: - * If you are new to programming and the shell, you'll probably find HTTPS easier at first (chapter \@ref(credential-caching)). You can always switch to SSH later. You can use one method from computer A and the other from computer B. + * If you are new to programming and the shell, you'll probably find HTTPS easier at first (chapter \@ref(https-pat)). You can always switch to SSH later. You can use one method from computer A and the other from computer B. * You should swap out your SSH keys periodically. Something like once a year. * It's best practice to protect your private key with a passphrase. This can make setup and usage harder, so if you're not up for that (yet), either don't use a passphrase or seriously consider using HTTPS instead. * Don't do weird gymnastics in order to have only one key pair, re-used over multiple computers. You should probably have one key per computer (I do this). Some people even have one key per computer, per service (I do not do this). @@ -32,7 +39,14 @@ Global advice: if you do have existing keys, but have no clue where they came fr ### From RStudio -Go to *Tools > Global Options...> Git/SVN*. If you see something like `~/.ssh/id_rsa` in the SSH RSA Key box, you definitely have existing keys. Caveat: RStudio only looks for a key pair named `id_rsa` and `id_rsa.pub`. This makes sense, because it's the default and very common. But SSH keys *can* have other names. If you want to be completely certain, you should also check in the shell. +Go to *Tools > Global Options...> Git/SVN*. If you see something like `~/.ssh/id_rsa` in the SSH RSA Key box, you definitely have existing keys. + +Caveat: RStudio only looks for a key pair named `id_rsa` and `id_rsa.pub`. +This makes sense, because historically that has been the most common. + +However, these days both GitHub and GitLab are encouraging users to generate SSH keys with the Ed25519 algorithm, which results in a key pair named `id_ed25519` and `id_ed25519.pub`. +At the time of writing, RStudio will not display such a key pair, which can be confusing. +Therefore, it's probably a good idea to also check for existing keys in the shell. ### From the shell @@ -40,13 +54,15 @@ Go to the shell (appendix \@ref(shell)). List existing keys: -``` bash +```console ls -al ~/.ssh/ ``` If you are told `~/.ssh/` doesn't exist, you don't have SSH keys! -If you see a pair of files like `id_rsa.pub` and `id_rsa`, you have a key pair already. The typical pattern is `id_FOO.pub` (the public key) and `id_FOO` (the private key). If you're happy to stick with your existing keys, skip to the sections about adding a key to the ssh-agent and GitHub. +If you see a pair of files like `id_rsa.pub` and `id_rsa` or `id_ed25519` and `id_ed25519.pub`, you have a key pair already. +The typical pattern is `id_FOO.pub` (the public key) and `id_FOO` (the private key), where `FOO` reflects the key type. +If you're happy to stick with your existing keys, skip to the sections about adding a key to the ssh-agent and GitHub. ## Create an SSH key pair @@ -54,53 +70,71 @@ If you see a pair of files like `id_rsa.pub` and `id_rsa`, you have a key pair a Go to *Tools > Global Options...> Git/SVN > Create RSA Key...*. -RStudio prompts you for a passphrase. It is optional, but also a best practice. Configuring your system for smooth operation with a passphrase-protected key introduces more moving parts. If you're completely new at all this, skip the passphrase (or use HTTPS!) and implement it next time, when you are more comfortable with system configuration. I did not use a passphrase at first, but I do now, and record it in a password manager. +RStudio prompts you for a passphrase. It is optional, but also a best practice. Configuring your system for smooth operation with a passphrase-protected key introduces more moving parts. +If you're completely new at all this, skip the passphrase (or use HTTPS!) and implement it next time, when you are more comfortable with system configuration. +I did not use a passphrase at first, but I do now, and record it in a password manager. Click "Create" and RStudio will generate an SSH key pair, stored in the files `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub`. +Note that RStudio currently only generates RSA keys, whereas the standard recommendation by GitHub and GitLab is to use Ed25519 keys. +If you want to comply with that advice, generate your keys in the shell for now. + ### Option 2: Set up from the shell -Create the key pair like so, but substitute a comment that means something to you, especially if you'll have multiple SSH keys in your life. Consider the email associated with your GitHub account or the name of your computer, e.g. `you@example.com` or `2018-mbp`. +Create the key pair like so, but substitute a comment that means something to you, especially if you'll have multiple SSH keys in your life. +Consider the email associated with your GitHub account or the name of your computer or some combination, e.g. `your_email@example.com` or `macbook-pro` or `jane-2020-macbook-pro`. + +```console +ssh-keygen -t ed25519 -C "DESCRIPTIVE-COMMENT" +``` + +If it appears that your system is too old to support the Ed25519 algorithm, do this instead: -``` bash -$ ssh-keygen -t rsa -b 4096 -C "USEFUL-COMMENT" +```console +ssh-keygen -t rsa -b 4096 -C "DESCRIPTIVE-COMMENT" ``` -Accept the proposal to save the key in the default location. Just press Enter here: +Accept the proposal to save the key in the default location. +Just press Enter here: -``` bash -Enter file in which to save the key (/Users/jenny/.ssh/id_rsa): +```console +Enter file in which to save the key (/Users/jenny/.ssh/id_ed25519): ``` -You have the option to protect the key with a passphrase. It is optional, but also a best practice. Configuring your system for smooth operation with a passphrase-protected key introduces more moving parts. If you're completely new at all this, skip the passphrase and implement it next time, when you are more comfortable with system configuration. I did not use a passphrase at first, but I do now, and record it in a password manager. +You have the option to protect the key with a passphrase. +It is optional, but also a best practice. +Configuring your system for smooth operation with a passphrase-protected key introduces more moving parts. +If you're completely new at all this, skip the passphrase and implement it next time, when you are more comfortable with system configuration. +I did not use a passphrase at first, but I do now, and record it in a password manager. -``` bash +```console Enter passphrase (empty for no passphrase): +Enter same passphrase again: ``` The process should complete now and should have looked like this: -``` bash -jenny@2015-mbp ~ $ ssh-keygen -t rsa -b 4096 -C "USEFUL-COMMENT" -Generating public/private rsa key pair. -Enter file in which to save the key (/Users/jenny/.ssh/id_rsa): +```console +~ % ssh-keygen -t ed25519 -C "jenny-2020-mbp" +Generating public/private ed25519 key pair. +Enter file in which to save the key (/Users/jenny/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again: -Your identification has been saved in /Users/jenny/.ssh/id_rsa. -Your public key has been saved in /Users/jenny/.ssh/id_rsa.pub. +Your identification has been saved in /Users/jenny/.ssh/id_ed25519. +Your public key has been saved in /Users/jenny/.ssh/id_ed25519.pub. The key fingerprint is: -SHA256:ki0TNHm8qIvpH7/c0qQmdv2xxhYHCwlpn3+rVhKVeDo USEFUL-COMMENT +SHA256:XUEaY/elhcQJz3M9jx/SdC0zh10lCA7uNpqgkm5G/R0 jenny-2020-mbp The key's randomart image is: -+---[RSA 4096]----+ -| o+ . . | -| .=.o . + | -| ..= + + | -| .+* E | -| .= So = | -| . +. = + | -| o.. = ..* . | -| o ++=.o =o. | -| ..o.++o.=+. | ++--[ED25519 256]--+ +| . =o==oo*| +| . + =.=+B+| +| . o . @oB| +| . . . oO+| +| . . S . ..o.| +| o o . E . ...| +|+ . . + . .| +|.+ . . | +|o. | +----[SHA256]-----+ ``` @@ -108,80 +142,93 @@ The key's randomart image is: Tell your ssh-agent about the key and, especially, set it up to manage the passphrase, if you chose to set one. -Things get a little OS-specific around here. When in doubt, consult [GitHub's instructions for SSH](https://help.github.com/articles/connecting-to-github-with-ssh/), which is kept current for Mac, Windows, and Linux. +Things get a little OS-specific around here. +When in doubt, consult [GitHub's instructions for SSH](https://docs.github.com/en/authentication/connecting-to-github-with-ssh), which is kept current for Mac, Windows, and Linux. +It also accounts for more unusual situations than I can. #### Mac OS -Make sure ssh-agent is enabled. Here's what success look like: +Make sure ssh-agent is enabled. Here's what success look like (the `pid` will vary): -``` bash -jenny@2020-mbp ~ $ eval "$(ssh-agent -s)" -Agent pid 95727 +```console +~ % eval "$(ssh-agent -s)" +Agent pid 15360 ``` Sometimes this fails like so: -``` bash -jenny@2020-mbp usethis $ eval "$(ssh-agent -s)" +```console +~ % eval "$(ssh-agent -s)" mkdtemp: private socket dir: No such file or directory ``` -A similar failure might be reported as "Permission denied". You should try again, but as the superuser. Don't forget to use `exit` to go back to your normal user account, when you are done! +A similar failure might be reported as "Permission denied". +You should try again, but as the superuser. +Don't forget to use `exit` to go back to your normal user account, when you are done! -``` bash -jenny@2020-mbp ~ $ sudo su +```console +~ % sudo su Password: sh-3.2# eval "$(ssh-agent -s)" -Agent pid 18772 +Agent pid 15385 sh-3.2# exit +exit ``` -Add your key to the ssh agent. If you set a passphrase, you'll be challenged for it here. Give it. The `-K` option stores your passphrase in the keychain. +Add your key to the ssh agent. +If you set a passphrase, you'll be challenged for it here. +Give it. +The `-K` option stores your passphrase in the keychain. -``` bash -jenny@2015-mbp ~ $ ssh-add -K ~/.ssh/id_rsa -Enter passphrase for /Users/jenny/.ssh/id_rsa: -Identity added: /Users/jenny/.ssh/id_rsa (/Users/jenny/.ssh/id_rsa) +```console +~ % ssh-add -K ~/.ssh/id_ed25519 +Enter passphrase for /Users/jenny/.ssh/id_ed25519: +Identity added: /Users/jenny/.ssh/id_ed25519 (jenny-2020-mbp) ``` -If you're using a passphrase AND on macOS Sierra 10.12.2 and higher, you need to do one more thing. Create a file `~/.ssh/config` with these contents: +If you're on macOS Sierra 10.12.2 and higher, you need to do one more thing. +Create a file `~/.ssh/config` with these contents: -``` bash +```bash Host * - AddKeysToAgent yes - UseKeychain yes + AddKeysToAgent yes + UseKeychain yes + IdentityFile ~/.ssh/id_ed25519 ``` -This should store your passphrase *persistently* in the keychain. Otherwise, you will have to enter it every time you log in. Useful StackOverflow thread: [How can I permanently add my SSH private key to Keychain so it is automatically available to ssh?](https://apple.stackexchange.com/questions/48502/how-can-i-permanently-add-my-ssh-private-key-to-keychain-so-it-is-automatically). +You can omit the line about `UseKeychain` if you didn't use a passphrase. +But if you did, this should store your passphrase *persistently* in the keychain. +Otherwise, you will have to enter it every time you log in. +Useful StackOverflow thread: [How can I permanently add my SSH private key to Keychain so it is automatically available to ssh?](https://apple.stackexchange.com/questions/48502/how-can-i-permanently-add-my-ssh-private-key-to-keychain-so-it-is-automatically). #### Windows In a Git Bash shell, make sure ssh-agent is running: -``` bash +```console $ eval $(ssh-agent -s) Agent pid 59566 ``` -Add your key. +Add your key, substituting the correct name for your key. -``` bash -$ ssh-add ~/.ssh/id_rsa +```console +$ ssh-add ~/.ssh/id_ed25519 ``` #### Linux In a shell, make sure ssh-agent is running: -``` bash +```console $ eval "$(ssh-agent -s)" Agent pid 59566 ``` -Add your key. +Add your key, substituting the correct name for your key. -``` bash -ssh-add ~/.ssh/id_rsa +```console +ssh-add ~/.ssh/id_ed25519 ``` ## Provide public key to GitHub @@ -190,70 +237,84 @@ Now we store a copy of your public key on GitHub. ### RStudio to clipboard -Go to *Tools > Global Options...> Git/SVN*. If your key pair has the usual name, `id_rsa.pub` and `id_rsa`, RStudio will see it and offer to "View public key". Do that and accept the offer to copy to your clipboard. If your key pair is named differently, use another method. +Go to *Tools > Global Options...> Git/SVN*. +If your key pair is named like `id_rsa.pub` and `id_rsa`, RStudio will see it and offer to "View public key". +Do that and accept the offer to copy to your clipboard. + +If your key pair is named differently, such as `id_ed25519.pub` and `id_ed25519`, you'll have to copy the public key another way. ### Shell to clipboard -Copy the public key onto your clipboard. For example, open `~/.ssh/id_rsa.pub` in an editor and copy the contents to your clipboard. Or do one of the following at the command line: +Copy the public key onto your clipboard. +For example, open `~/.ssh/id_ed25519.pub` in an editor and copy the contents to your clipboard. +Or do one of the following at the command line: - * Mac OS: `pbcopy < ~/.ssh/id_rsa.pub` - * Windows: `clip < ~/.ssh/id_rsa.pub` - * Linux: `xclip -sel clip < ~/.ssh/id_rsa.pub` + * Mac OS: `pbcopy < ~/.ssh/id_ed25519.pub` + * Windows: `clip < ~/.ssh/id_ed25519.pub` + * Linux: `xclip -sel clip < ~/.ssh/id_ed25519.pub` *Linux: if needed, install via `apt-get` or `yum`. For example, `sudo apt-get install xclip`.* ### On GitHub -Make sure you're signed into GitHub. Click on your profile pic in upper right corner and go *Settings*, then *SSH and GPG keys*. Click "New SSH key". Paste your public key in the "Key" box. Give it an informative title, presumably related to the comment you used above, during key creation. For example, you might use `2018-mbp` to record the year and computer. Click "Add SSH key". +Now we register the public key with GitHub. +Click on your profile pic in upper right corner and go to *Settings > SSH and GPG keys*. +Click "New SSH key". +Paste your public key in the "Key" box. +Give it an informative title, presumably repeating the descriptive comment you used above, during key creation. +Click "Add SSH key". -In theory, we're done! You can use [`ssh -T git@github.com`](https://help.github.com/articles/testing-your-ssh-connection/) to test your connection to GitHub. If you're not sure what to make of the output, see the link for details. Of course, the best test is to work through the realistic usage examples elsewhere in this guide. +In theory, we're done! +You can use [`ssh -T git@github.com`](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection) to test your connection to GitHub. +If you're not sure what to make of the output, see the link for details. +Of course, the best test is to work through the realistic usage examples elsewhere in this guide. ## Troubleshooting {#ssh-troubleshooting} -### HTTPS vs SSH +### HTTPS URL when you meant to use SSH If you think you have SSH set up correctly and yet you are still challenged for credentials, consider this: for the repo in question, have you possibly set up GitHub, probably called `origin`, as an HTTPS remote, instead of SSH? How to see the remote URL(s) associated with the current repo in the shell: -``` bash +```console git remote -v ``` An SSH remote will look like this: -``` +```console git@github.com:USERNAME/REPOSITORY.git ``` whereas an HTTPS remote will look like this: -``` +```console https://github.com/USERNAME/REPOSITORY.git ``` -You can toggle between these with `git remote set-url`: - - * +You can fix this with `git remote set-url`, which is demonstrated in [URL determines the protocol](#url-determines-protocol). ### git2r -- or some other tool -- can't find SSH keys on Windows Have you seen this error message? -``` +```console Error in .local(object, ...) : Error in 'git2r_push': error authenticating: failed connecting agent ``` -We've seen it when working with Git/GitHub from R via the [git2r](https://cran.r-project.org/web/packages/git2r/index.html) package, which is used under the hood by many R packages, such as devtools, ghit, and usethis. - -git2r uses the libgit2 library, not the Git you installed. This means you can have SSH keys configured properly for Git work in a Git Bash shell and from RStudio and still have problems with git2r! Ugh. +We've seen it when working with Git/GitHub from R via the [git2r](https://cran.r-project.org/web/packages/git2r/index.html) package. -The root cause is confusion about the location of `.ssh/` on Windows. R's idea of your home directory on Windows often differs from the default location of config files for Git and ssh, such as `.ssh/`. On *nix systems, these generally coincide and there's no problem. +The root cause is confusion about the location of `.ssh/` on Windows. +R's idea of your home directory on Windows often differs from the default location of config files for Git and ssh, such as `.ssh/`. +On *nix systems, these generally coincide and there's no problem. -Two important directories on Windows are the user's HOME and USERPROFILE. R usually associates `~` with HOME, but Git and ssh often consult USERPROFILE for their config files. On my Windows 10 VM, I see: +Two important directories on Windows are the user's HOME and USERPROFILE. +R usually associates `~` with HOME, but Git and ssh often consult USERPROFILE for their config files. +On my Windows 10 VM, I see: -``` r +```{r eval = FALSE} normalizePath("~") #> [1] "C:\\Users\\JennyVM\\Documents" @@ -277,30 +338,31 @@ list.files( Two workarounds: - * Tell git2r explicitly where to find your public and private key. Example using `usethis::use_github()`: + * Tell git2r explicitly where to find your public and private key and pass the resulting `cred` object to your git2r calls. - ``` r + ```{r eval = FALSE} cred <- git2r::cred_ssh_key( publickey = "~/../.ssh/id_rsa.pub", privatekey = "~/../.ssh/id_rsa" ) - use_github(credentials = cred) ``` * [Create a symbolic link](https://www.howtogeek.com/howto/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/) so that `.ssh/` in R's home directory points to your actual `.ssh/` directory. Example contributed by Ian Lyttle on Windows 7 using Command Prompt: - ``` bash + ```console MKLINK /D "C:\Users\username\Documents\.ssh" "C:\Users\username\.ssh" ``` Finally, if git2r seems unable to get your SSH passphrase from ssh-agent, install the getPass package: -``` r +```{r eval = FALSE} install.packages("getPass") ``` -and git2r should launch a popup where you can enter your passphrase. Thanks to Ian Lyttle for this tip. +and git2r should launch a popup where you can enter your passphrase. +Thanks to Ian Lyttle for this tip. -This link provides a great explanation of the uncertainty about where `.ssh/` and user's `.gitconfig` are located on Windows: [git on Windows - location of configuration files](https://www.onwebsecurity.com/configuration/git-on-windows-location-of-global-configuration-file.html). Bottom line: locate where your main tool expects and create symbolic links to help other tools find this stuff. +This link provides a great explanation of the uncertainty about where `.ssh/` and user's `.gitconfig` are located on Windows: [git on Windows - location of configuration files](https://www.onwebsecurity.com/configuration/git-on-windows-location-of-global-configuration-file.html). +Bottom line: place your config and keys where your main tool expects them to be and create symbolic links to help other tools find this stuff. ### Other diff --git a/connect-troubleshooting.Rmd b/connect-troubleshooting.Rmd index 54da1bbd..eae4de59 100644 --- a/connect-troubleshooting.Rmd +++ b/connect-troubleshooting.Rmd @@ -6,7 +6,8 @@ If you experience some new problem and, especially, find the corresponding solut ## I think I have installed Git but damn if I can find it -When you install Git, try to control or record where it is being installed! Make a mental or physical note of these things. +When you install Git, try to control or record where it is being installed! +Make a mental or physical note of these things. You may be able to find Git after the fact with these commands in the shell (Appendix \@ref(shell)): @@ -14,15 +15,18 @@ You may be able to find Git after the fact with these commands in the shell (App * `where git` (Windows, when not in a bash shell) -It is not entirely crazy to just re-install Git, using a method that leaves it in a more conventional location, and to pay very close attention to where it's being installed. Live and learn. +It is not entirely crazy to just re-install Git, using a method that leaves it in a more conventional location, and to pay very close attention to where it's being installed. +Live and learn. ## RStudio Git pane disappears on Mac OS -Sometimes the RStudio Git pane disappears on a system where it was previously working. This usually happens to people who installed Git by installing the Xcode command line tools. It is usually a sign that you need to re-agree to the Xcode license agreement. This is necessary after a Mac OS upgrade, re-installing Xcode, or even quiet Xcode upgrades that happen in normal system maintenance. +Sometimes the RStudio Git pane disappears on a system where it was previously working. +This usually happens to people who installed Git by installing the Xcode command line tools. +It is usually a sign that you need to re-agree to the Xcode license agreement. This is necessary after a Mac OS upgrade, re-installing Xcode, or even quiet Xcode upgrades that sometimes seem to happen without the user's knowledge. In the shell, you could execute `git status` and you might see a message along these lines: -``` bash +```console Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command. ``` @@ -30,13 +34,13 @@ If you get such clear instructions, by all means do what it says, i.e. run `sudo In any case, you need to tickle the Xcode command line tools to prompt you for whatever it needs. Here are other commands that, depending on the situation, might trigger the necessary prompts: -``` bash +```console xcode-select --install ``` or -``` bash +```console git config --global --list ``` @@ -44,97 +48,105 @@ Then **restart RStudio**. ## Dysfunctional PATH -I'm pretty sure that most cases of RStudio *not* automatically detecting the Git executable stem from problems with `PATH`. This is the set of directories where your computer will look for executables, such as Git (today) or `make` (later in this course). Certain methods of Git installation, especially on Windows and/or older OSes, have a higher tendency to put Git in an unconventional location or to fail to add the relevant directory to `PATH`. +Some cases of RStudio *not* automatically detecting the Git executable stem from problems with `PATH`. +This is the set of directories where your computer will look for executables, such as Git (today) or `make`. +Certain methods of Git installation, especially on Windows and/or older OSes, have a higher tendency to put Git in an unconventional location or to fail to add the relevant directory to `PATH`. How to see your `PATH`? In the shell: -``` sh +```console echo $PATH ``` -Take a good hard look at this. See the point above about finding your Git executable or re-installing it while you are **wide awake**. Is the host directory in your `PATH`? No? **Fix that.** +Take a good hard look at this. +See the point above about finding your Git executable or re-installing it while you are **wide awake**. +Is the Git executable's parent directory in your `PATH`? +No? +**Fix that.** -Go [here](http://www.troubleshooters.com/linux/prepostpath.htm) for instructions on what to put in your `.bash_profile` in order to add a directory to `PATH`. +At this point I recommend that you do a Google search to find instructions on how to modify `PATH` on your specific operating system. ## Push/Pull buttons greyed out in RStudio -Are you sure your local repository is associated with a remote repository, e.g. a GitHub repo? In a shell with working directory set to the local Git repo, enter this command: +Are you sure your local repository is associated with a remote repository, e.g. a GitHub repo? +In a shell with working directory set to the local Git repo, enter this command: -``` sh -jenny@2015-mbp myrepo $ git remote -v -origin https://github.com/jennybc/myrepo (fetch) -origin https://github.com/jennybc/myrepo (push) +```console +~/tmp/myrepo % git remote -v +origin git@github.com:jennybc/myrepo.git (fetch) +origin git@github.com:jennybc/myrepo.git (push) ``` -We want to see that fetch and push are set to remote URLs that point to the remote repo. Note also that the GitHub repo is a remote named `origin`, as far as your local repo is concerned. This is typical and, though I think `github` is a vastly superior name, `origin` is such a strong convention that I follow it. +We want to see that fetch and push are set to remote URLs that point to the remote repo. -If you discover you still need to set a remote, get the HTTPS or SSH URL, as appropriate, for your GitHub repo. This is easy to get onto your clipboard from the repo's GitHub page. Do this in the shell: +If you discover you still need to set a remote, get the HTTPS or SSH URL, as appropriate, for your GitHub repo. +This is easy to get onto your clipboard from the repo's GitHub page. +Do this in the shell: -``` sh +```console git remote add origin https://github.com/jennybc/myrepo.git ``` -Download all the files from the online GitHub repository and deal with any conflicts. +Download all the files from the online GitHub repository and deal with any +conflicts (substituting `master` for `main`, if relevant). -``` sh -git pull origin master +```console +git pull origin main ``` -Call `git remote -v` again. Once you can prove that your GitHub remote is set properly, you can move on to the next step. +Call `git remote -v` again. +Once you are satisfied that your GitHub remote is set properly, you can move on to the next step. -Are you sure the current branch is *tracking* a branch on the remote? In that same shell, in your repo, do this: +Are you sure the current branch is *tracking* a branch on the remote? +In that same shell, in your repo, do this: -``` sh -jenny@2015-mbp myrepo $ git branch -vv -* master b8e03e3 [origin/master] line added locally +```console +~/tmp/myrepo % git branch -vv +* main 2899c91 [origin/main] A commit from my local computer ``` -The above shows successful confirmation that the local `master` branch is tracking `origin/master`, i.e. the master branch on GitHub. If you don't see the `[origin/master]` bit, that is a problem. By the way, `git branch -r` is another handy way to examine your remote-tracking branches. (If you're working with a branch other than `master`, adjust everything accordingly.) +The above shows successful confirmation that the local `main` branch is tracking `origin/main`, i.e. the `main` branch on GitHub. +If you don't see the `[origin/main]` bit, that is a problem. +By the way, `git branch -r` and `git remote show origin` are two more commands that are helpful for examining your remote setup. When connecting a local repo to a new GitHub repo, a lot of people remember to add the GitHub remote, but forget to also cement this tracking relationship for any relevant branches. -If you discover your local `master` branch is not yet tracking `master` on GitHub, fix that like so: +If you discover your local `main` branch is not yet tracking `main` on GitHub, fix that like so: -``` sh -git push --set-upstream origin master +```console +git push --set-upstream origin main ``` -This is equivalent to `git push -u origin master` but conveys more about what you are doing. +This is equivalent to `git push -u origin main` but conveys more about what you are doing. -Call `git branch -vv` or `git branch -r` again to confirm that the `master` branch on GitHub is the upstream or tracking branch for the local `master` branch. +Call `git branch -vv` or `git branch -r` or `git remote show origin` again to confirm that the `main` branch on GitHub is the tracking branch for the local `main` branch. ## I have no idea if my local repo and my remote repo are connected. See the above section on "Push/Pull buttons greyed out in RStudio." -## Push fail at the RStudio level - -Do you get this error in RStudio? - -``` -error: unable to read askpass response from 'rpostback-askpass' -``` - -Open the shell: *Tools > Shell*. - -``` shell -git push -u origin master -``` - ## Push rejected, i.e. fail at the Git/GitHub level -You might have changes on the remote AND on your local repo. Just because you don't remember making any edits in the browser doesn't mean you didn't. Humor me. +You might have changes on the remote AND on your local repo. +Just because you don't remember making any edits in the browser doesn't mean you didn't. +Humor me. -Pull first. Resolve any conflicts. Then try your push again. +Pull first. +Resolve any conflicts. +Then try your push again. ## RStudio is not making certain files available for staging/committing -Do you have a space in your directory or file names? [A space in a file name is a space in your soul.](https://twitter.com/aaronquinlan/status/711593127551733761) Get rid of it. +Do you have a space in your directory or file names? [A space in a file name is a space in your soul.](https://twitter.com/aaronquinlan/status/711593127551733761) +Get rid of it. -Is your Git repo / RStudio Project inside a folder that ... eventually rolls up to Google Drive, DropBox, Microsoft OneDrive, or a network drive? If yes, I recommend you move the repo / Project into a plain old directory that lives directly on your computer and that is not managed by, e.g., Google Drive. +Is your Git repo / RStudio Project inside a folder that ... eventually rolls up to Google Drive, DropBox, Microsoft OneDrive, or a network drive? +If yes, I recommend you move the repo / Project into a plain old directory that lives directly on your computer and that is not managed by, e.g., Google Drive. -If you cannot deal with the two root causes identified above, then it is possible that a more powerful Git client (chapter \@ref(git-client)) will be able to cope with these situations. But I make no promises. You should also try Git operations from the command line. +If you cannot deal with the two root causes identified above, then it is possible that a more powerful Git client (chapter \@ref(git-client)) will be able to cope with these situations. +But I make no promises. +You should also try Git operations from the command line. ## I hear you have some Git repo inside your Git repo @@ -142,4 +154,6 @@ Do not create a Git repository inside another Git repository. Just don't. If you have a genuine need for this, which is really rare, the proper way to do it is via [submodules](http://git-scm.com/book/en/v2/Git-Tools-Submodules). -In STAT 545, we certainly do not need to do this and when we've seen it, it's been a mistake. This has resulted in the unexpected and complete loss of the inner Git repository. To be sure, there was more going on here (cough, GitHub Desktop client), but non-standard usage of Git repos makes it much easier to make costly mistakes. +In STAT 545, we certainly do not need to do this and when we've seen it, it's been a mistake. +This has resulted in the unexpected and complete loss of the inner Git repository. +To be sure, there was more going on here (cough, GitHub Desktop client), but non-standard usage of Git repos makes it much easier to make costly mistakes. diff --git a/github-api-tokens.Rmd b/github-api-tokens.Rmd deleted file mode 100644 index 1a28d0af..00000000 --- a/github-api-tokens.Rmd +++ /dev/null @@ -1,7 +0,0 @@ -# GitHub Personal Access Tokens {#github-pat} - -This material is now redundant with instructions given earlier in the book. - -To understand why you might want a GitHub personal access token, how to get one, and how to configure it for use from R, read: - -[Cache credentials for HTTPS](#credential-caching) diff --git a/img/new-personal-access-token-screenshot.png b/img/new-personal-access-token-screenshot.png new file mode 100644 index 00000000..6bcf9294 Binary files /dev/null and b/img/new-personal-access-token-screenshot.png differ diff --git a/img/pat-kills-both-birds.jpeg b/img/pat-kills-both-birds.jpeg new file mode 100644 index 00000000..498c45e7 Binary files /dev/null and b/img/pat-kills-both-birds.jpeg differ diff --git a/workflows-fork-and-clone.Rmd b/workflows-fork-and-clone.Rmd index 4de47bba..1161fd42 100644 --- a/workflows-fork-and-clone.Rmd +++ b/workflows-fork-and-clone.Rmd @@ -25,9 +25,13 @@ We're doing this: ## `usethis::create_from_github("OWNER/REPO")` -The [usethis package](https://usethis.r-lib.org) has a convenience function, [`create_from_github()`](https://usethis.r-lib.org/reference/create_from_github.html), that can do "fork and clone". In fact, it can go even further and [set the `upstream` remote](#upstream-changes). However, `create_from_github()` requires that you have [configured a GitHub personal access token](#github-pat). It hides lots of detail and can feel quite magical. +The [usethis package](https://usethis.r-lib.org) has a convenience function, [`create_from_github()`](https://usethis.r-lib.org/reference/create_from_github.html), that can do "fork and clone". +In fact, it goes even further and [configures the `upstream` remote](#upstream-changes) and sets the upstream tracking branch for `main` (or whatever the default branch is) to `upstream/main`. +Note that `create_from_github()` requires that you have [configured a GitHub personal access token](#https-pat). +It hides lots of detail and can feel quite magical. -Due to these difference, we won't dwell on `create_from_github()` here. But once you get tired of doing all of this "by hand", check it out! +Due to these difference, we won't dwell on `create_from_github()` here. +But once you get tired of doing all of this "by hand", check it out! ## Engage with the new repo diff --git a/workshops.Rmd b/workshops.Rmd index c1e6eefe..d5b6a31d 100644 --- a/workshops.Rmd +++ b/workshops.Rmd @@ -18,9 +18,8 @@ Try this. Best case scenario is about 1 - 2 hours. If you hit a wall, we will he * [Install or update R and RStudio](#install-r-rstudio). * [Install Git](#install-git). * [Introduce yourself to Git](#hello-git). + * [Configure a personal access token](#https-pat) or [set up SSH keys](#ssh-keys). * [Prove local Git can talk to GitHub](#push-pull-github). - * [Cache your username and password](#credential-caching) or [set up SSH keys](#ssh-keys) so you don't need to authenticate yourself to GitHub interactively *ad nauseum*. - * [Create and save a GitHub Personal Access Token (PAT)](#github-pat). * [Prove RStudio can find local Git](#rstudio-git-github) and, therefore, can talk to GitHub. - FYI: this is where our hands-on activities usually start. We walk through a similar activity together, with narrative, and build from there. * Contemplate if you'd like to [install an optional Git client](#git-client), now or in future.