Difference between revisions of "Using git and GitHub"

From PioneerWiki
Jump to: navigation, search
(Keeping things tidy)
(Getting other developer's branches)
Line 201: Line 201:
 
== Getting other developer's branches ==
 
== Getting other developer's branches ==
  
  git remote
+
Check which remote repositories you have:
 +
  git remote -v
  
 +
add a new one
 
  git remote add <remote> <url>
 
  git remote add <remote> <url>
  

Revision as of 19:01, 10 October 2014

Developing on pioneer means using the version control tool 'git' and the github website. git especially has a reputation for having a steep learning curve, so here we'll try to give you enough knowledge to be dangerous!

Prerequisites

A working installation of git, a GitHub account, and comfort with using the command line of your chosen operating system.

The GitHub sign-up page is here. Make a note of your user name as you'll need it to make your local pioneer repository.

On Linux, git is available in all distributions using the standard tools such as APT, yum or emerge. Since there is a wide range of file browsers and graphical environments, this tutorial limits itself to the command line interface.

On Windows you have two options, Git for Windows aka msysgit, or Github for Windows which is essentially msysgit but with some extra stuff bundled. Some of which is good (posh git) and some of which is well, not (github's 'friendly' gui). Since both include the same command line tools and cross platform gui tools, either is fine for our purposes here. The github one may be more convenient to install.

On Mac OS X, git will have been installed with XCode as git is built into the XCode IDE. However, usage of git from from within an IDE isn't something I'm familiar with so isn't covered here. If you want to follow along with this document then if you elected to install the XCode command line tools, then the git commands below should work unaltered from a terminal window. If you didn't then you'll need to use xcrun to run the commands in terminal, either by adding xcrun in front of each of the commands or aliasing git and gitk to xcrun git and xcrun gitk in your ~/.profile. Have a look at this guide for details.

A clear and concrete introduction to git can be seen at this Git Guide

Creating your pioneer repositories

Git, as a version control system, stores all source files for Pioneer (or any other project you've chosen to manage with git) along with their histories in repositories (usually shortened to just 'repos'). These are areas of a computer's file system where has git has been told to track and manage changes to the files placed in them.

There are three different repositories that you mainly deal with when developing pioneer.

  • The upstream repo. This is the main Pioneer repository stored on GitHub. This is read-only except to the core team (and even they don't do their development there).
  • The origin repo. This is a public Pioneer repository personal to you, but stored on GitHub under your username, so other people can see the changes put into it. This is read-only to everyone except you.
  • The local repo. This is your personal Pioneer repository on your computer, not accessible by anyone else.

Before you can start developing you need to setup both your Pioneer origin and local repositories.

Your origin repository

Your origin repository you make on GitHub. To do that, make sure that you're logged in there and go to the main GitHub Pioneer page in your web browser, and click the 'Fork' button at the top of that page: ForkPioneer.png


GitHub will clank and whirr as it makes a copy of the main Pioneer repo under your username. Eventually it will finish, and you'll end up on page almost exactly like the main GitHub Pioneer page, but instead of being named pioneerspacesim/pioneer your copy is named <your github user name>/pioneer.

Having made your origin repo, you're now ready to make your local one.

Your local repository

You make your local repository by cloning a copy of your new origin repository to your local machine.

At the command line, navigate to where on your filesystem you want to put your local git repos. For instance on Linux I put mine in ~/repos whilst on Windows I put them in c:\develop\github-repos. You can move the folder at a later time without breaking anything. Once you're there execute the following command replacing your github username with, well, your github username.

git clone git://github.com/your gituhub username/pioneer.git

Just like clicking Fork on the main Pioneer GitHub repo made a clone of it under your GitHub account, this makes a clone of that clone to your local machine. Expect this to take some time, just like before, as it copies all the files and the complete history of the project to your filesystem, only now it's sucking the data from GitHub to your machine, rather than copying things around within GitHub's data centre (so it will probably take even longer; however, a modern coputer does it on the order of minutes).

Eventually this operation will complete, and you'll have a shiny new directory named pioneer which git -- with a little encouragement -- will manage for you, your local repo.

We're almost done with repository setup, but there is one more thing we need to attend to. When you did git clone, it automatically set origin to point to your Pioneer repository on GitHub. However it didn't set upstream to point the main Pioneer Repository. We'll need to do that manually.

We must to be inside the repository to do this, in fact all the git commands from now on, you need to be inside a repository to execute any of the git commands shown. So enter the pioneer repository directory, before doing:

git remote add upstream git://github.com/pioneerspacesim/pioneer.git

...to define upstream as the main Pioneer repository. You'll notice you defined upstream as a remote, origin is also defined as a remote. We'll explain more about remotes later on.

You can now view the result of our commands, i.e. see how we link the origin to your git repo, and upstream to the central pioneer repository.

git remote -v

Basic operations

At this point you might want to consider searching for tutorials. There are many good ones on git out there. If you're familiar with svn look here, and this is a nice visual representation of different commands, which might be helpful. Basic git tutorials on youtube: part 0, part 1.


git branch
git status
git checkout <branch-name>
git branch <branch-name> ; git checkout <branch-name>
git checkout -b <branch-name>
gitk
git add -A ; git commit
git commit -a
git push origin <branch name>

Updating your branches

Makes no changes on your local copy, but reads in what changes there are upstream. A safe command.

git fetch upstream
git merge
git pull --ff-only upstream master

This merges your master branch into your current one

git merge master

To discard all changes on your branch "my-branch" and resync them with the upstream version you have in your hithub

git reset --hard origin/my-branch

Resolving Conflicts

Making a pull request

Make a branch, push it to your Github repository, and you will get a "Compare / Open Pull Request" button when viewing your branch on your Github account if logged in.

Fixing/Updating your pull request

This addresses the case where you have opened a pull request on Github, only to realize (by yourself, or through a reviewer giving feedback) that you need to change something. Conveniently, Github tracks your branch so any change to it will also update the commits in your pull request.

For example, you make some new change to your branch, add and commit them:

git commit -am "this is an additional commit"

Then just push it to your branch:

git push

(Note: this assumes your local branch is set up to track your Github branch)

However, doing it like this is only recommended if the new commit actually adds something new to the branch, where it is logical to have it as a separate commit. If it is a bug fix for a previous commit in the same pull request, there is no need for us to see it in the master branch of pioneer once it is merged. Thus the following two subsections describe how to fix the commit log / history.

Update / change last commit

The first case is the simplest: if you just want to change the last commit (or only commit) in your branch, because you realized some file was missing, or needed an edit. We will use rebase, which is very versatile.

Make your change, then run "git add" on the changed files. Now update the last commit by:

git commit --amend

And push to your Github, but since the last commit has changed, you need to force it

git push -f

Done.


Update / change commit in middle of the branch of the pull request

The second case covers if you need to edit commits further back in the commit history, or change order of commits or any other change.

The example case we use here has a git log looking like so:

git log --oneline
dd34lqe added final feature D
cc5369b added third feature C
bb1ed97 added second feature B
a528f11 added initial feature A

Now you want to fix a bug in your second commit for feature "B". Make your changes in your local branch, add them and commit. Your structure will now look like:

git log --oneline
98a9832 my bugfix for feature B
dd34lqe added final feature D
cc5369b added third feature C
bb1ed97 added second feature B
a528f11 added initial feature A

The bug fix commit is redundant to see in the git log once in master, so we want to merge the bug fix commit with "bb1ed97 my second feature B" commit, so that no one will ever know there was a bug in the first place! You do this by "rebasing" your branch.

git rebase -i a528f11

This opens the rebase dialogue in your default editor for git (usually vim, emacs, or nano). It will show you the git history for all commits after (i.e. excluding) the commit a528f11 ("added initial feature A").

You will see in the editor something like this (don't be confused by the reverse order compared to git log command):

pick bb1ed97 added second feature B 
pick cc5369b added third feature C  
pick dd34lqe added final feature D  
pick 98a9832 my bugfix for feature B

# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Now just move the last line to be just below the commit we want it to fix, and mark it as a "fixup", which will merge it into the commit above it, and use its commit message:

pick bb1ed97 added second feature B 
fixup 98a9832 my bugfix for feature B
pick cc5369b added third feature C  
pick dd34lqe added final feature D  

Save, and quit, and hopefully git will report that the rebase was successful, and your git history will now be clean, but the commit hash (and code) for the "B feature" has changed, thus we need to force push the change to Github.

git log --oneline
dd34lqe added final feature D
cc5369b added third feature C
qq9860d added second feature B
a528f11 added initial feature A
git push -f

(again assuming your local branch is tracking the Github repo)

Getting code from other branches

git checkout <branch-name> -- <file-name>
git merge <branch-name>

Getting other developer's branches

Check which remote repositories you have:

git remote -v

add a new one

git remote add <remote> <url>
git remote update
git checkout -b <branch-name> --track <remote>/<remote-branch-name

Keeping things tidy

If branch is merged into master then it can safely be deleted

git branch -d <branch-name>

If branch is not in master, then a force remove can be made

git branch -D <branch-name>
git push origin :<branch-name>
git clean -n
git clean -f

Reviewing a pull request

Rebasing and cherry picking

Warning: Rebasing and cherry picking, although sometimes useful, can cause problems for other developers if you use them on commits that have already been published to github. Be careful and give sufficient warnings if you find you needing to use them in that situation.

git cherry-pick <commit>
gitk
git rebase <branch-name>
git rebase -i <branch-name>

Pushing to upstream Pioneer Master

For those with push access to https://github.com/pioneerspacesim/pioneer this is one way to push code to master. First make sure you have a resonable setup:

git remote -v
 origin	https://github.com/myusername/pioneer.git (fetch)
 origin	https://github.com/myusername/pioneer.git (push)
 upstream	https://github.com/pioneerspacesim/pioneer.git (fetch)
 upstream	https://github.com/pioneerspacesim/pioneer.git (push)


git checkout master
git merge --no-commit --no-ff feature_branch

Document changes to Changelog.txt, then add it, from the pioneer root folder:

git add Changelog.txt
git commit 

This has now included the Changelog edit into the merge commit. Now do a dry run:

git push upstream master --dry-run

Check that the right commits will be pushed with

git log

And let us do it for real this time:

git push upstream master


Please note: NEVER do a force push to pioneer master!