Skip to content

Git GitHub Processes

Andrew Woods edited this page Dec 26, 2022 · 7 revisions

Todo: Add Images and Diagrams to help clarify the descriptions below

Terminology

  1. Upstream GitHub Repository - The production repository, owned by the VIVO Committers, where all community updates are targeted. This is the repository from which production releases are made.
  2. Personal Fork Repository - The GitHub repository, owned by individual VIVO developers, that is a fork of the "Upstream GitHub Repository".
  3. Clone - A copy of a GitHub Repository to your local system. Usually, the clone is of your "Personal Fork Repository".
  4. Remote - A GitHub repository with which your local clone has a connection. Automatically, your local clone will have a "remote" to the GitHub repository which you cloned. It is also possible to add other "remotes", i.e. connections from your local clone to other GitHub repositories.
  5. Branch - A copy of the code/files, isolated from changes on other branches. Branches can be created from other branches, and destroyed without losing anything other than the changes found within that branch.
  6. Commit - A unit of work that represents an incremental improvement/fix/update to the code. Branches are composed of a series of "commits". "Commits" can be copied between branches.
  7. Pull-request - A submission via GitHub, of changes from a source branch to a target branch. The source branch should be up to date with the target branch, with the addition of one or more commits that represent the submitted changes. Reference.

Git Principles

  1. Never work directly on the 'main' branch
    • It is important that you always have a clean state from which your development branches are based
  2. Development branches are temporary
    • Development branches should be created and used for a single purpose, a single feature
    • Development branches can be deleted after they have been merged into the branch to which they were targeting
  3. Pull-requests and their source branch
    • Pull-requests are created from a source branch which was pushed to GitHub
    • If you add another commit to the local source branch, then push the source branch to GitHub again, the pull-request will be automatically updated to include the new commit
  4. Retaining a clean Git history
    • It is helpful to have commits on the 'main' branch that are complete units of work, as opposed to incremental, in-process commits
    • If a pull-request contains more than one commit, those commits should all be related to a single feature / unit of work
    • It should be expected that all commits in a pull-request will be squashed into a single commit when merged into the 'main' branch

Setup Process

All of the instructions below assume you have a personal GitHub account, or in some situations an organizational account of which you are the owner.

  1. Create "Personal Fork" of an "Upstream Repository"
    • The personal fork is a copy in your personal GitHub account of another GitHub repository.
    • You push changes to your personal fork, and pull changes from the upstream repository into your personal fork.
    • Creating a fork: Reference
  2. Clone your fork
    • Most activities related to changing code/files in your personal fork require having a local copy of your fork.
    • Assuming you have already create a fork, the following command creates a local clone (using "VIVO" as an example repository):
      $ git clone https://github.com/<your-github-id>/VIVO.git
      
    • All subsequent commands assume you are in the directory in which your clone was created:
      $ cd VIVO
      
  3. Add a remote to the upstream repository
    • A "remote" is a connection between your local clone and repositories on GitHub.
    • You should have one remote that was automatically created when the clone was made called "origin"
    • Inspect your remotes:
      $ git remote -v
      
    • You also want to create a connection between your local clone and the upstream repository:
      $ git remote add upstream https://github.com/vivo-project/VIVO.git
      
    • Note: We gave this new remote the name "upstream", but you could name it anything
    • Again, inspect your remotes:
      $ git remote -v
      
  4. Create a branch that tracks the 'main' branch of the upstream repository
    • You will want to have a branch in your clone that is always up to date with the upstream 'main' branch. It is called "tracking" when one of the branches in your clone stays synchronized with a remote branch.
    • Often times, the 'main' branch in your clone and personal repository are used to track the upstream 'main' branch, but you can also use another branch for this purpose.
    • In this example, we will use a branch named 'upstream-main' to track the upstream 'main' branch.
    • First, you must "fetch" all of the metadata from the the upstream remote into your local clone. This command only adds metadata to your clone, no content files are changed.
      $ git fetch upstream
      
    • Now that your clone is aware of all the branches in the upstream repository, you can create a branch that tracks the upstream 'main' branch:
      $ git checkout -b upstream-main --track upstream/main
      
    • You now have a local copy of the upstream 'main' branch. If you want to make code/file changes that will eventually be added to the upstream repository, you use 'upstream-main' as the starting point for your development branches.

Feature development Process

One of the primary reasons for having a fork of a repository is to contribute back to the upstream repository. Below is an example process for maintaining your fork and clone in a way that facilitates contributing to the upstream repository.

  1. Create branch off of target of development
    • The branch that you eventually want your contribution to target should act as the starting point for you development branch(es).
    • However, as noted before, you should never work directly on the branch that is tracking the upstream target branch. Instead, you should create a new feature or development branch off of the branch that is tracking the upstream target branch.
    • In this example, you will want to create a branch off of 'upstream-main'
      $ git checkout -b feature-123 upstream-main
      
  2. Make commits on development branch
    • In this step you make changes, and commit those changes to your development branch ("feature-123")
    • See reference
  3. Push development branch to personal fork repository
    • Once you have finished with the single task for which your development branch was created, and you have committed those changes, it is time to push your development branch up to your personal fork:
      $ git push origin feature-123:feature-123
      
  4. Create a pull-request
    • Once you have pushed your development branch to your fork, GitHub will prompt you to create a pull-request
    • Click the button, "New pull request", and select the base fork and base branch to which you would like to contribute your updates
    • See reference

Maintain currency of branches

  1. Update branch that tracks the upstream 'main' branch
    • Over time, the upstream repository will continue to have additional commits added to it.
    • It is important that your clone stays up to date with the changes in the upstream repository
    • To do that, you simply need to pull the upstream changes into your local branch that was created to track the upstream 'main' branch
      $ git checkout upstream-main
      $ git pull
      
  2. Managing changes from upstream during local development
    • You can simply update your 'upstream-main', then update your development branch while adding your local commits to the end of the upstream commits (this is called "rebasing"):
      $ git checkout feature-123
      $ git rebase upstream-main
      
    • This conceptually replaces the series of commits on which your development branch was created with the updated commits found in 'upstream-main'.

Copying commits between branches

Although this is not an activity that is required in the normal development workflow, sometimes it is helpful to be able to copy one or more commits from one branch in your clone to another. In this example, you want a commit from branch 'feature-xyz' to be copied on to your 'feature-123' branch.

  1. List commits of interested
    • First, you will need to find the commit hash identifier for the commit that will be copied
      $ git log feature-xyz
      
    • This will show the commits on branch, 'feature-xyz'.
    • Make a copy of the commit hash identifier for the commit that will be copied
  2. Establish development branch
    • Checkout your development branch, then "cherry-pick" the commit that you want from 'feature-xyz'
      $ git checkout feature-123
      $ git cherry-pick <commit-hash>