This tutorial skips over some details as it is intended to accompany classroom discussion. However, it does provide more hand-holding than a cheat sheet. This tutorial is a simplified and updated version of Andrew Burgess’ 2009 Tutorial on TutsPlus.

A Note on Syntax: Be sure to exclude the brackets [] in the examples below. Use your custom values instead.

The install section of the Git book provides details for Mac, Windows, and Linux environments.

$ git config --global user.name "Your Name"
$ git config --global user.email "your@email.com" 

Add text coloring to the bash terminal:

$ git config --global color.ui auto

Pro Tip: View Config Settings

$ git config --list

Pro Tip: Where Everything is Stored on Windows

Git’s bash files and folders such as .bash_history, .gitconfig, and .ssh are located in
C:\users\%UserProfile%\
Lists of Windows environment path variable shortcuts

Only done and needed for a new project (top-level folder). Leave out the repository (repo) name so it will default to “master.”

1. Navigate to your new project’s folder:
$ cd C:\wamp\www\python\extreme-moves-app
2. Now create a new git repo for the project:
$ git init 

This creates (initializes) a Git repository in your project folder. The .git folder that’s created and initialized tracks changes to your code and denotes it with a secure hash on each commit.

We always create a new branch (1) before and (2) when we intend to make drastic changes to the branch we are located in!

But, before we tell you how to create branches, this is how you view a project’s branches:

:
$ git branch

Create a New Branch

First, checkout the branch you want to fork from. We call this the “parent” branch! Second, create a branch of that “parent”. Here are the steps:

1. Work on (i.e., checkout) the branch you want to fork:

$ git checkout [branch-name]

2. Create a new branch:

$ git branch [branch-name]

Pro Tip: Branching

You either need to (1) be in the parent branch that you want to fork from or (2) state the parent branch explicitly. If you don’t explicitly state the parent branch, Git will assume the parent is the branch you’re currently in!

Create a new branch and switch to it simultaneously:

$ git checkout -b [branch-name] ([parent-branch-name])

-b tells git to switch to [branch-name] once created

parent-branch-name is optional, hence the parentheses. If excluded, Git defaults it to the branch you’re working in!

Newbie Tip: Ooops, I forgot to Branch

It’s best practice to always checkout a new branch before making major changes! But what if you’ve been coding for hours, saved your changes… and forgot to checkout and work from a new branch? Or even forgot to fire up Git? All is not lost. Just do this:

$ git checkout -b [new-branch-name]
$ git add .
$ git commit -m "rewrote core code. deleted old test files. reorganized folders"

Upshot: As long as you have not committed any files you are free to have the changes stored in any branch without affected your master/parent branches!

The staging area “holds” files and their changes for your next commit:

Per GitHUb, a commit is a permanent snapshot of all the files in your project at a particular point in time.
$ git add .

The . will stage all changed and untracked files. You may also use wild cards and specific file names to stage certain files and types:

$ git add *.css
$ git add hello.py

Pro Tip: Staging Files

Staged and Unstaged files that have never been committed are accessible (read, write, delete) amongst all branches (yes even those you are not working in). However, if you edit and save the file after it’s been committed the first time, Git will not let you switch branches unless the file has been re-committed!

$ git commit -m "descriptive msg as to why code was committed"

Pro Tip: Committing Files

The following will simultaneously stage and commit previously added (i.e., staged) files that have been modified.

$ git commit -am "message, so you know why that code was committed"

Note: This will not auto-stage newly added files. They will not be added and will remain untracked. So, you must manually add new files via $ git add .

Pro Tip: Changing The Commit Message. Fixing Typos on Most Recent

To edit the commit message just type:

git commit --amend

Pro Tip: Change Editor for Verbose Commit Messages

Show default editor:

$ git config --global --get core.editor

Windows users may use Visual Studio Code, like so:

$ git config --global core.editor "code --wait"
$ git config --global format.commitMessageColumns 72

Mac users can use nano:

$ git config --global core.editor "nano"

Pro Tip: Simultaneously Stage and Commit with Verbose Messages using Favorite Editor

$ git commit -av 
NB: Github post on undoing commits

The git status command shows you which files were changed (modified) and new (untracked) since your last commit.

$ git status

This is done after we finish creating and testing a new feature. We merge the child branch into it’s parent branch. Upon a merge, the changes in the child will overwrite the existing files of the parent.

Merge a branch (child) into the branch you’re currently working on (parent) like so (make sure you’re in the branch you want the child branch to be merged into):

$ git merge [branch-name-I-want-to-merge]

Delete branch (child) after merging (into parent):

$ git branch -d [branch-name]

Delete branch that you never merged:

$ git branch -D [branch-name]

Experiment with the below and learn what they do!

$ git log

$ git log --graph

$ gitk --all  #color gui

Pro Tip: View Commit History and Diffs for Individual Files

To view the history of a particular file:

$ gitk path/to/file

OR

$ git log -p -- path/to/file

OR show full history and diffs along with diffs with associated with file’s prior names:

$ git log --follow -p -- file

The -- option tells Git that it has reached the end of the options and that anything that follows -- should be treated as an argument. For git log this only makes any difference if you have a path name that begins with a dash. –Dan Moulding

Stashing is a power user feature. Here are two use-cases of why and when to use git stash

  1. You started working in “branch a”. After 3 hours of coding you realize your changes would be better off in a new branch, say “upgrades/mega-filter”. Also, your changes were previously committed to this “branch a” during your first hour. So, Git won’t let you switch and commit these changes to a new branch!
    Here’s the solution:
    a. Create a stash:
    $ git stash
    b. Create a new branch from the stash:
    $ git stash branch upgrades/mega-filter

  2. From the Git stash docs: “You’ve been working on part of your project, things are in a messy state and you want to switch branches for a bit to work on something else. The problem is, you don’t want to do a commit of half-done work just so you can get back to this point later.”
    The solution would be to stage your changes and then create a stash:
    a. Stage Changes:
    $ git add .
    b. Stash changes:
    $ git stash

    Warning: Always Stage Before You Stash

    Always stage your changes before you stash! If you do not (1) stage your changes before stashing and (2) then switch to another branch, you will (3) receive a merge conflict error CONFLICT (content): Merge conflict in XYZ when you attempt to recover your stashed files! You do not want this to happen! Always stage before stashing!

    Now, you’re free to checkout any branch you want to work on! And, when you’re ready return to your stash, just do:

    $ git checkout [branch-that-you-stashed]
    $ git stash apply

1. Connecting to GitHub

Generate a new SSH key for GitHub:

$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Pro Tip: Email Address and GitHub

If you plan to connect your local Git environment with GitHub, the email address you use during set-up needs to match that of your GitHub account. By default your commits will contain your name and email address.

GitHub has an article on how to keep your email address private on their site. They mention that you’ll also need to change the email you use in your local Git to their private email alias. Feel free to experiment.

Pro Tip: Reinstalling Your Public Key on GitHub

GitHub periodically deletes saved public keys if you have not used or verified them over a specified time. This will result in a Permission denied (publickey) error when connecting to GitHub through git bash over SSH.

The solutions are to either (1) generate a new public-private key-pair or (2) simply re-paste your pre-existing public back into GitHub. Let’s go with solution 2:

1. Turn on the ssh-agent:
$ ssh-agent -s

# If using MINGW64 (i.e., Windows users) type this instead:
$ eval $(ssh-agent -s)
2. Verify that your private key is loaded into SSH:
$ ssh-add -l
3. If your key hash appears proceed to step 4. However,

  1. If you receive a message stating The agent has no identities, this means your key is no longer loaded into git bash. So, add your SSH private key to the ssh-agent with:
    $ ssh-add ~/.ssh/id_rsa
4. Store your public key on GitHub by following their tutorial.

5. Test the connection (note: v is the verbose ouput indicator)
$ ssh -vT git@github.com

2. Connecting to BitBucket for the First Time

GitHub’s SSH documentation is better than Bitbucket’s. So once you’re set up on GitHub, log into your Bitbucket account, and do the following to connect it to:

  1. Within git bash, copy your SSH public-key:
    $ clip < ~/.ssh/id_rsa.pub
  2. On Bitbucket's website, click the icon in the lower left, then select "Bitbucket Settings" from the menu
  3. On the left side of the resulting page there are 3 columns of list menus. On the third column (a long menu of links), click "SSH Keys" which is under the "Security" header
  4. Click the "Add Key" button and paste your public-key
  5. Within git bash, verify your connection to bitbucket:
    $ ssh -T git@bitbucket.org

Cloning is primarily used to quickly get a local copy of a repository from the source code's owner. Cloning without forking is done when we do not intend to contribute to the original project. Unlike a fork, a clone does not maintain a connection with the original owner's source (i.e., upstream) repository.

When we clone a repo, we save it to our local drive. The process is as follows:

#Using https:
$ git clone https://github.com/your-user-name/project-name

#Using ssh (note the repo name must end in .git):
$  git clone git@github.com:your-user-name/project-name.git
NB: Cloning auto-creates an external pointer to the source repo called "origin" on your local drive

Cloning is also used as an intermediary step to transfer (or duplicate) a repo onto another git provider. If you need to transfer the repo to another provider (e.g., transfer from Github to Bitbucket), first initiate a clone as above, then proceed as follows:

# Step 1: Go to Bitbucket and manually create a new and empty repo with the name of the project you want to clone

# Step 2: On your local drive 'cd' into the project you just cloned in the prior steps
$ cd project-name

# Step 3: change the Github remote from 'origin' to 'upstream'*
$ git remote rename origin upstream

# Step 4: Finally, add the new Bitbucket repo as the 'origin'  
$ git remote add origin git@bitbucket.org:your-user-name/project-name.git

# Step 5: Push all branches to Bitbucket once**:
$ git push -u --all origin
*NB: See What is the difference between origin and upstream on GitHub? for a definition of these terms.

**NB: The above solutions were provided by Christian Specht on Stack Overflow. Refer to this comment on the usage of ‘-u’

The forking process is defined by manually creating a duplicate of a repo on your git provider’s website. Here is a nuance between forking and cloning:

A forked repository differs from a clone in that a connection exists between your fork and the original repository itself. In this way, your fork acts as a bridge between the original repository and your personal copy where you can contribute back to the original project using Pull Requests.

Forking vs Cloning via Github

GitHub has solid documentation on forking, so we’ll punt in this section and refer you to their help doc called Forking a Repo. Here’s summary of the the workflow taken from the above link:

Forks are the first step in either proposing changes to someone else’s project or to use someone else’s project as a starting point for your own idea.

Forks are often used to propose changes for bug fixes. For example, instead of logging an issue for a bug you’ve found, you can:

  1. Fork the repository [make a remote repo] and then clone it to your local machine [make a local repo]
  2. Create a new branch were you plan to make your fixes
  3. Make your fixes (and test them)
  4. Push your fix from your local repo to your remote repo
  5. Submit a pull request to the project owner (Note: Pull requests are done on the Github/Bitbucket websites, not the command line)

Forking a Repo via Github

Once you fork, you’ll also want to:

  1. Synch your local copy to ensure you’re working with the latest version of the original owner’s repo
    $ cd [project home directory]
    $ git remote add upstream git@github.com:ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git 
    $ git fetch upstream
    $ git checkout master
    $ git merge upstream/master
    
  2. After synching your local copy, then push the changes out to your remote fork on Github/Bitbucket to keep it in synch with your local version
    $ git push origin master
    

Brand New Repos that You Created Locally

If you have a brand new local project that you’d like to push out to GitHub, the following is an example workflow:

1. Configure Project’s Push Destination from CLI

$ git remote add [name] [url]

In the example below, the name of push destination [name] is upstream and the URL is git@github.com:codesport/my-awesome-project.git:

$ git remote add upstream git@github.com:codesport/my-awesome-project.git

2. Push Project to the Newly Created Remote Repo for the First Time

Continuing with the example above, to push the current branch and set the remote as upstream do

$ git push --set-upstream upstream master

3. Push Subsequent Updates to Remote Repo

$ git push upstream master

Pre-existing Repos Forked from Others

For pre-existing repos that you have forked and are modding, use the below workflow:

Use git push to send commits made on your local branch to a remote repository.

$ git push origin [your_local_branch_name]

Alternatively, you may use git push -u origin [your_local_branch_name] the first time you push out an update.

Where: -u is shorthand for --set-upstream. This activates branch tracking. And, with tracking on, for subsequent pushes you just type git push.

See these Stack-overflow Q&As for further context

Pro Tip: Pushing to Remotes and Retrieving Names of Your Remote

View remotes associated with a given repo:

$ git remote

Push updates from your local machine to your remote repo (e.g., GitHub or Bitbucket)

$ git push remote_name branch_name

A Pull Request happens when you (1) make changes to a branch (or a fork) and (2) request that the original owner(s) pull your changes into their repository. Hence, the term “pull request”.

Pull requests lie in the domain of social coding platforms such as GitHub and Bitbucket. While git pull is a git command. Yangsu has a good tutorial where you may learn both by doing a simple example! Here are some quotes that sum things up:

Pull requests let you tell others about changes you’ve pushed to a GitHub repository. Once a pull request is sent, interested parties can review the set of changes, discuss potential modifications, and even push follow-up commits if necessary. — GitHub Help: Using Pull Request
git pull does a git fetch followed by a git merge. A git pull is what you would do to bring a local branch up-to-date with its remote version, while also updating your other remote-tracking branches. — Greg Hewgill