Skip to content

Instantly share code, notes, and snippets.

@zkamvar
Last active December 5, 2015 01:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zkamvar/5950afa29f65bf1b961e to your computer and use it in GitHub Desktop.
Save zkamvar/5950afa29f65bf1b961e to your computer and use it in GitHub Desktop.
Updating forks with git2r

Motivation

I am a contributor to NESCent's Population Genetics in R repository. The idea behind this repository is that people would be able to construct short vignettes for genetic analysis in R that can be displayed on the Population Genetics Info Website. Of course, the submissions would need to be pull requests from other users that would have forked the repository. For beginners, updating a fork is not a simple task. It requires that you fetch the upstream branch and then merge that branch into your head.

One problem: neither the OSX nor Windows GUIs have the ability to synch a fork from upstream, meaning that the contributors would have to know some command line options. This isn't a terrible thing all in all, because OSX has a Terminal app and users can access the shell from the Windows GUI. I recently attempted to test things on a windows machine that had some problems with the .NET framework necessary for the GitHub GUI to work. Basically, I was without a way to do anything git-wise until I realized that git2r existed. This document shows how to sync a fork without the use of the command line or the gui (I'm writing this on a mac, but I know this works on Windows as well).

Process

First, install git2r:

install.packages("git2r", repos = "http://cran.rstudio.org")

For the sake of example, I will use my own fork, but this can be applied to anyone's fork. In this first part, I am simply creating a temporary directory in which to store my repository. It will be clobbered after my R session closes.

library("git2r")
tmp <- tempfile(pattern = "popgenInfo")
dir.create(tmp)
(repo <- git2r::clone("https://github.com/zkamvar/popgenInfo.git", tmp))
## cloning into '/var/folders/qd/dpdhfsz12wb3c7wz0xdm6dbm0000gn/T//Rtmp2GfKvA/popgenInfo4c7e2c1d9f87'...
## Receiving objects:   1% (13/1236),   10 kb
## Receiving objects:  11% (136/1236),   35 kb
## Receiving objects:  21% (260/1236),   50 kb
## Receiving objects:  31% (384/1236), 1260 kb
## Receiving objects:  41% (507/1236), 2772 kb
## Receiving objects:  51% (631/1236), 3717 kb
## Receiving objects:  61% (754/1236), 3741 kb
## Receiving objects:  71% (878/1236), 3925 kb
## Receiving objects:  81% (1002/1236), 3933 kb
## Receiving objects:  91% (1125/1236), 3941 kb
## Receiving objects: 100% (1236/1236), 5128 kb, done.

## Remote:   @ origin (https://github.com/zkamvar/popgenInfo.git)
## Local:    master /private/var/folders/qd/dpdhfsz12wb3c7wz0xdm6dbm0000gn/T/Rtmp2GfKvA/popgenInfo4c7e2c1d9f87/
## Head:     [739a0b5] 2015-05-18: Merge pull request #56 from zkamvar/developer-basic

Now that we have our repository, we need to set our configurations and the upstream repository, which is NESCent. To make things easier to understand, I will name the upstream repository "NESCent" instead of the conventional "upstream".

config(repo, user.name = "Zhian Kamvar", user.email = "kamvarz@science.oregonstate.edu")
## global:
##         alias.pupdate=!make update && git add . && git commit --amend --no-edit
##         color.ui=true
##         core.editor=/usr/bin/vim
##         filter.hawser.clean=git hawser clean %f
##         filter.hawser.required=true
##         filter.hawser.smudge=git hawser smudge %f
##         filter.lfs.clean=git lfs clean %f
##         filter.lfs.required=true
##         filter.lfs.smudge=git lfs smudge %f
##         filter.media.clean=git media clean %f
##         filter.media.required=true
##         filter.media.smudge=git media smudge %f
##         user.email=kamvarz@science.oregonstate.edu
##         user.name=Zhian Kamvar
## local:
##         branch.master.merge=refs/heads/master
##         branch.master.remote=origin
##         core.bare=false
##         core.filemode=true
##         core.ignorecase=true
##         core.logallrefupdates=true
##         core.precomposeunicode=true
##         core.repositoryformatversion=0
##         remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
##         remote.origin.url=https://github.com/zkamvar/popgenInfo.git
##         user.email=kamvarz@science.oregonstate.edu
##         user.name=Zhian Kamvar
git2r::remotes(repo) # We only have origin == repo at github.com/zkamvar
## [1] "origin"
git2r::remote_add(repo, "NESCent", "https://github.com/NESCent/popgenInfo.git")
git2r::remotes(repo) # Now we have the upstream/NESCent branch
## [1] "NESCent" "origin"

Now it's time to fetch and merge. We will:

  1. Fetch the branches from the remote with git2r::fetch()
  2. Gather all of the branches with git2r::branches()
  3. Merge the NESCent/master branch into ours, updating our fork with git2r::merge()
git2r::fetch(repo, "NESCent")
repo_branches <- git2r::branches(repo)
head(repo_branches) # All branches including those in the NESCent repository
## $master
## [739a0b] (Local) (HEAD) master
## 
## $`NESCent/build-documentation`
## [6cbc88] (NESCent @ https://github.com/NESCent/popgenInfo.git) build-documentation
## 
## $`NESCent/gh-pages`
## [116960] (NESCent @ https://github.com/NESCent/popgenInfo.git) gh-pages
## 
## $`NESCent/Manel_new`
## [0d4250] (NESCent @ https://github.com/NESCent/popgenInfo.git) Manel_new
## 
## $`NESCent/Manel_vignette`
## [adc0ab] (NESCent @ https://github.com/NESCent/popgenInfo.git) Manel_vignette
## 
## $`NESCent/master`
## [b7fe85] (NESCent @ https://github.com/NESCent/popgenInfo.git) master

Before I merge the branch, I just want to show the commit I have in my head:

repo
## Remote:   @ NESCent (https://github.com/NESCent/popgenInfo.git)
## Remote:   @ origin (https://github.com/zkamvar/popgenInfo.git)
## Local:    master /private/var/folders/qd/dpdhfsz12wb3c7wz0xdm6dbm0000gn/T/Rtmp2GfKvA/popgenInfo4c7e2c1d9f87/
## Head:     [739a0b5] 2015-05-18: Merge pull request #56 from zkamvar/developer-basic

Now we merge and show the result.

git2r::merge(repo_branches[["NESCent/master"]])
## Merge: Fast-forward
repo # Our master branch is now synched.
## Remote:   @ NESCent (https://github.com/NESCent/popgenInfo.git)
## Remote:   @ origin (https://github.com/zkamvar/popgenInfo.git)
## Local:    master /private/var/folders/qd/dpdhfsz12wb3c7wz0xdm6dbm0000gn/T/Rtmp2GfKvA/popgenInfo4c7e2c1d9f87/
## Head:     [b7fe856] 2015-05-19: fix link to hackathon

At this point, I would use git2r::push() to push my changes. In order to do this, you will need to set up your credentials. Note that using a user/pass combination at this step can be dangerous because these are in plain text and have the potential of being stored in the history. Be very careful at this step.

Conclusions

This is obviously not a comprehensive example of updating a fork. There are obviously many other things to consider if merge conflicts happen among other things, but I hope that this serves as a nice, short introduction.

@zkamvar
Copy link
Author

zkamvar commented Dec 5, 2015

This basically boils down to a few steps:

  • clone the parent repository
  • Do this ONCE:
repo <- git2r::clone("https://github.com/zkamvar/popgenInfo.git", ".") # insert your repo name here
git2r::remotes(repo)
git2r::remote_add(repo, "NESCent", "https://github.com/NESCent/popgenInfo.git")
  • Do this EVERY time before you start working.
git2r::fetch(repo, "NESCent")
git2r::merge(repo, "NESCent/master")
  • Make changes, commit
  • Push to your repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment