Skip to content

Instantly share code, notes, and snippets.

@chrisrzhou
Last active August 29, 2015 14:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisrzhou/071f0d7e28626334fd5a to your computer and use it in GitHub Desktop.
Save chrisrzhou/071f0d7e28626334fd5a to your computer and use it in GitHub Desktop.
Git Resources

Git Advanced Resources

Interactive Rebase

  • Enter interactive rebase using git rebase -i
  • Some rebase options include:
    • squash: combine commits
    • edit: split commits (using git reset HEAD^)
    • reword: rename commit
    • pick: run commits in order

Stashing

  • Stashing allows you to store files in a temporary area so you can restore them in a later time without committing them
  • You may run into conflicts with git stash. You will have to rollback with reset HEAD^ and commit
git stash                           # same as git stash save, note this saves both STAGING and UNSTAGED area
git stash save                      # saves ONLY TRACKED changes to a temp place and restores last commit
git stash save --keep-index         # only UNSTAGED files are stashed, STAGED files are NOT stashed
git stash save --include-untracked  # stash UNTRACKED files
git stash list                      # shows stack of stashes
git stash apply                     # rerun changes from top stash of stack i.e. stash@{0}
git stash apply stash@{n}           # apply stash@{n} from stack
git stash drop                      # drop stash@{0} from stack
git stash drop stash@{n}            # drop stash@{n} from stack
git stash pop                       # runs git stash apply then git stash drop
git stash show                      # show details of stash@{0}
git stash show stash@{n}            # show details of stash@{n}
git stash branch <branch> stash@{0} # create branch <branch> and pop stash@{0} from stack to <branch>
git stash clear                     # clear all stashes

Purging History

  • You should AVOID doing this at ALL cost, especially if changes are pushed to remote.
  • You could purge history if you commited huge files or copyright issues.
git filter-branch --tree-filter "<command>"           # <command> is any shell command
git filter-branch --tree-filter "<command>" -- HEAD   # run <command> recursively in all commits in HEAD
git filter-branch --tree-filter "<command>" -- --all  # run <command> recursively in all commits in all branches
git filter-branch --index-filter "<command"           # run <command> only in staging area
git filter-branch -f --prune-empty -- --all           # delete all commits that are empty

Cherry Picking

git cherry-pick <commit>                          # pick a specific <commit> branch
git cherry-pick --no-commit <commit1> <commit2>   # picks two commit branches, not committed yet, commit with git commit
git cherry-pick --signoff <commit>                # tracks signoff person who is cherry picking <commit>

Submodules

  • Submodules are like git repos in git repos!
  • Submodules allow you to share libraries across project, share changes easily
  • Example: Gregg and Jane wants to share /css and /js files but work on different /html.
  • We make changes to a submodule like git repos, but we need to update the main repo containing the submodule by running
    • git add <submodule>
    • git commit -am 'updated submodule'
    • git push
git submodule add <repo>        # add <repo> as a submodule
git submodule init              # initialize submodules in .gitmodules file
git submodule update            # pulls and clones submodules from the internet after git submodule init

Reflog

  • Git never deletes anything
  • Even after deleting a commit with reset --hard HEAD, we can still access it via git reflog.
  • Reflog is only for local repositories, a git clone will start a new reflog.

Git Resources

General

  • Git is a distributed version control system (DVCS) as opposed to a central repository system.
    • A central repository system can be pictured as: ((userA, userB, userC), server)
    • A distributed Repository system can be pictured as ((userA, server), (userB, server), (userC, server))

Setup

  • Configure global settings and add some pretty command line colors :)

    git config --global user.name "<username>"            # set <username>
    git config --global user.email "<email>"              # set <email>
    git config --global color.ui true                     # turn on colors
    git config --list                                     # see configurations

Basic Commands

git init                      # Initialize LOCAL (not a remote) repository
git status                    # check changes since last commit
git add <file>                # add <file> to stage
git add --all                 # add all new and modified files to stage
git add docs/*.txt            # add all txt files in docs directory
git rm <file>                 # remove <file> and add changes to stage
git rm --cached <file>        # stop TRACKING <file> but does NOT delete <file>
git commit -m "<message>"     # commit changes from staging area with a <message>
git commit -am "<message>"    # add and commit all TRACKED files with a <message>
git log                       # show history log

Staging and Commits

git diff                            # show UNSTAGED differences since last commit
git diff --staged                   # show STAGED differences since last commit
git reset HEAD <file>               # unstage <file> from stage
git reset --soft HEAD^              # undo last commit and put changes into staging
git reset --hard HEAD^              # undo last commit and all changes
git reset --hard HEAD^^             # undo last two commit and all changes
git checkout -- <file>              # blow all changes for <file> since last commit
git commit --amend -m "<message>"   # add to previous commit with <message>

# Note that HEAD refers to last commit on git history
# Try to only use reset and ammends before pushing to remotes, since it affects commit histories.

Remotes

git remote -v                         # show remote repos
git remote add <remote> <address>     # add new <remote> to url address e.g. <remote> = origin
git remote rm <remote>                # remove <remote>
git push -u <remote> <branch>         # push local <branch> to <remote> e.g. <remote> = origin, <branch> = master
git pull -u <remote> <branch>         # pull changes from <remote> to <local>

# Note that the -u syntax helps cache the <remote> and <branch> of repos to avoid future typing

Local Branches

git clone <remote> <name>         # clone git repo from remote url into folder /<name>
git branch                        # check name of current branch
git branch <branch>               # create branch <branch>
git checkout <branch>             # go to <branch>
git checkout -b <branch>          # create branch <branch> and go to <branch>
git merge <branch>                # merge <branch> into current branch
git branch -d <branch>            # delete branch <branch>

# Note git merge can be fast-forward or recursive.  A fast forward merge is efficient when there
# are only changes in one branch.  A recursive merge is more intensive and is involved when
# there are changes in both branches that are to be merged.

Collaboration

  • Assume two collaborators, Gregg and Jane are working off the same remote.

No merge conflicts

  • Jane git push her changes and Gregg tries to git push later.
  • Gregg will encounter an error since his commit is behind the timeline now.
  • Gregg needs to git pull first before git push. This essentially executes:
    • git fetch which syncs his local repo with the remote repo
      • This does not change any local code, only updating the repo.
      • In Gregg's local repo, there is actually a branch origin/master
    • git merge origin/master which merges the branch origin/master to Gregg's current branch i.e. master
  • Now when Gregg uses git push, origin/master is in the same state as his local repo

Merge conflicts

  • Gregg and Jane are both working on the same file README.md

  • Jane has committed her changes and git push to remote while Gregg has only commited locally.

  • Gregg executes git pull but encounters a merge conflict in README.txt

  • Gregg goes into README.txt with vim and needs to manually fix the issues e.g.

    <<<<<<<< HEAD
    the cake is a lie.                # this is Gregg's local version
    ========
    the cake is telling the truth!    # this is Jane's version
    >>>>>>>>
  • Gregg manually fixes the file and runs git commit -a

  • Now Gregg has fixed the merge conflict and simply needs to run git push to be in sync with the timeline.

Remote Branches

git checkout -b <branch>                    # create local branch <branch>
git checkout -b <branch> <remote>/<branch>  # create local branch from <remote> <branch>
git checkout --track <remote>/<branch>      # shorthand for the above
git push -u <remote> <branch>               # push <branch> to remote repo branch and start tracking it
git branch -r                               # list all remote branches
git checkout <branch>                       # automatically pull remote <branch> into local <branch>
git remote show <remote>                    # show remote and local branches e.g. <remote> = origin
git push <remote> :<branch>                 # deletes ONLY the remote <branch> NOT the local <branch> e.g. <remote> = origin
git branch -D <branch>                      # force deletes local <branch> manually after deleting remote branch
git remote prune <remote>                   # clean up old and stale branches and references that are deleted on <remote>

Tags

git tag                             # list all tags
git checkout <tag>                  # checkout code at commit
git tag -a <tag> -m "<tagname>"     # add a new <tag> called <tagname>
git push --tags                     # push new tags

# A tag is a reference to a commit.  Used mostly for release versioning

Rebase

  • Run git fetch first
  • Switch to branch with git checkout <branch>
  • Then run git rebase:
  • git rebase does a few things different from git fetch and git merge origin/master
    • Move all changes from local master which are not in origin/master to a temporary area, say temp
    • Run all origin/master commits one at a time.
    • Run all commits in temp (i.e. commit diffs) one at a time.
    • Note that there are no merge commits, they are run one at a time!
    • We can potentially run into merge conflicts.
      • At this point git status will show us that we are in the process of a rebase
      • Manually fix conflicts and add files with git add <file>
      • Continue rebase with git rebase --continue
  • Finally run jump back to master branch with git checkout master
  • And merge branch to master git merge <branch>

History and Configuration

History

  git log --pretty=oneline              # displays a pretty one-line
  git log --pretty=format: <format>     # displays pretty format
  git log --oneline                     # see git timeline in single line
  git log --oneline --graph             # see git timeline in graph format
  git diff HEAD                         # same as git diff
  git diff HEAD^^                       # compare current commit against 2nd most recent
  git diff HEAD~5                       # compare against 5 commits ago
  git diff <branch1> <branch2>          # compare diffs between two branches

Alias

git config --global alias.<aliasName> "<command>"     # set alias <aliasName> given a <command>

# Examples
git config --global alias.st "status"
git config --global alias.co "checkout"
git config --global alias.br "br"
git config --global alias.ci "commit"

Other

  • Use .gitignore to ignore files and folders e.g. logs/*.log

Github Resources

Recommended Configurations and Alias

  • Put these in a Github wiki or a dot files folder e.g. .gitconfig
git config --global --push.default simple     # push current branch (not matching branch) this is default in git 2.0+
git config --global --pull.rebase true        # git pull will git fetch then git rebase instead of git merge
git config --global --rerere.enabled true     # resolve similar merge conflicts
git config --global --colors.ui true          # for older versions of git
git config --global alias.s "status -s"       # silent mode git status
git config --global alias.lg "log --oneline --decorate --all --graph"   # super git log decorations

Forking and Cloning

  • Anyone can git clone a repo.
  • You can only git push changes to Github if you are a collaborator.
  • If you are not a collaborator, you need to fork the original repo instead
  • With the forked repo, you can now git clone and git push to your forked repo

Pull Request

  • When you fork a repo and make changes to your local repo and forked repo, you can contribute back to the original source by making a pull request.

  • A pull request is to request for changes on our master branch to be merged back to the original master branch

  • On Github, you can create pull requests with buttons add comments as needed.

  • Pull Request Review Workflow:

    git fetch               # download latest changes and all branches from Github
    git branch -a           # view all branches (including remote tracking branches in red
    git checkout <branch>   # check out a local branch pointing to remote tracking <branch>
    git commit              # after making changes, commit them
    git push                # push changes

Updating Forks

  • To collaborate across forks, we need to pull from various upstreams to get updated commits

  • We should do the following everytime a pull request is accepted into the upstream repo:

    git remote add upstream <repo>        # add upstream (original) repo based on <repo> url path
    git fetch upstream                    # update upstream data and fetch changes
    git merge upstream/master master      # merge upstream master branch to local master branch
    git push origin master                # push your final changes up to your remote

Single Repository Workflow

  • It can become hard to manage Fork-based repository workflow as everyone is working on their forks and have to check for pull requests and upstream to keep updated.
  • A single repository workflow helps solve this where everyone just clones from the single repository.
  • The problem with single repository workflow is that if there are many contributors, then they may run into conflicts.
  • This problem is solved with feature branches.

Feature Branches

  • Everyone is contributing separately on their own branches.

  • Multiple developers can collaborate on each other's branches easily by checking them out

    git fetch         # fetch from remote server
    git branch -a     # show all branches
    git checkout f2   # checkout feature branch f2
  • Developers will merge each others' feature branches.

  • Eventually, they will make a pull request to merge their feature branch back to the remote.

Merging Pull Requests

  • Three key considerations:
    • Interactive rebase

      • Great for simplifying history by pick or squash commits.
      • Be careful not to squash an entire branches, some information is better than none.
      • Squash commits that are no longer neccessary.
    • Rebase

      • Simplifies and linearizes history.
      • This is as simple as
      git checkout feature_branch
      git rebase master
    • Fast-forward or recursive merge

      • Fast forward has less commits as commits on feature branches are placed directly in master branch
      • The downsides of fast-forward is that it is harder to tell what commits are made on various feature branches
      • A recursive merge is recommended.
      • We can do so by explicitly using the --no-ff option in git merge
      git checkcout master
      git merge --no-ff feature_branch

Tags

  • Every time you push to production, you should use a tag
  • Tags are documentation.. Use them to keep track of all production releases.
  • There are three types of tags:
    • Lightweight:
      • Human-readable and simple tag pointing to a commit.
      • no message or tagger.
    • Signed:
      • Requires cryptographic signing.
      • Uses public key to prove identity of tagger.
    • Annotated:
      • Used most frequently.
      • Adds info on who is tagged, when, and why.
  • Best practice to name tag is to use semantic versioning
    • major.minor.patch
    • Use v0.x-pre to specify pre-release versions (where x is a number and pre is either alpha or beta)
    • e.g. v1.5.3, v2.6.2, v0.2-alpha.3, v0.6-beta.9
git tag -a <tag> -m "<message>"         # creates an annotated tag <tag> with message <message>
git push --tags                         # push changes and new tags

Release Branches

  • Generally you only need tags for releases, but you need a release branch if you want to change a production release without affecting master.
  • Release tags point to a single commit while release branches can be updated with new commits.
  • By convention, we write release branches as rbx.y (where x and y are numbers) e.g. rb2.3, rb1.7
  • Note that release branches are usually for major.minor and not major.minor.patch (i.e. tags)
  • Three reasons to use release branches:
    • Manual QA
    • Long running release
    • On demand hot fixes

Releases

  • Key benefits:
    • Host binary downloads without checking into Git.
    • Provide additional documentation and release notes.
    • Allow users to download source code from zip file without cloning the repository.

Issues

  • Go to settings/options to turn on Issues, Wikis etc.
  • Anyone can create issues in a public repo, only collaborators can create issues in private repos.
  • Issues can be labeled (question, bug) etc.

Wikis

  • Start with a README.md but build a wiki if documentation requires scaling.
  • Wikis use Github Flavored Markdown (GFM)
  • Add status badges to inform audience what state the project is in.

Github Pages

  • Add richer docmentation to a project
  • Host a site for user or organization
  • To create a user page:
    • Create a repo called username.github.io
    • Use the auto page generator
    • Write content
    • Pick theme
    • Publish!
  • To create a project page:
    • Create a branch in gh-pages branch of project repo
    • Use the auto page generator
    • Write content
    • Pick theme
    • Publish!
  • Configuring a custom domain
    • Create CNAME file in root of repo
    • This should be same branch as Pages content
    • Configure CNAME with a DNS host

Authentication and Authorization

  • Github/Git heavily relies on user emails for identifying unique contributors.
  • Github/Git does not stop people from configuring global.email and committing as a different person.
  • Github/Git is about trusting your contributors and collaborators.
    • Owners can do anything and everything!
    • Collaborators can do anything except manage settings.
    • You can limit ability to commit using forks
  • You can build Github organizations and teams
    • Organizations are for code owned by groups (e.g. companies, OSS projects etc).
    • Teams allow easier management of permissions
  • HTTPS is favored over SSH when connecting to Github.
  • You want to upgrade to two factor authentication (2FA)
  • You create access tokens to:
    • Login with 2FA
    • Access via build script/API calls etc

Git API

  • https://api.github.com/
  • Key API capabilities:
    • Activitiy
    • Gists
    • Git data
    • Issues
    • Organizations
    • Pull Requests
    • Repositories
    • Search
    • Users

Hub

  • Hub is a CLI way to use Github

  • Install with:

    git clone https://github.com/github/hub.git
    cd hub
    rake install prefix=/usr/local      # make sure ruby is installed
  • We recommend aliasing hub as git i.e. alias git=hub. This will allow you to use and type git clone and git fork

Creating Repo Using Hub

git init new_repo
cd new_repo
vim README.md
git add .
git commit
git create                  # create repo in Github
git push -u origin master
git browse                  # open browser

Creating Pull Request using Hub

git checkout -b new_branch
vim new_code.md
git add .
git commit
git push -u origin new_branch
git pull-request

Cloning a Repo using Hub

git clone repo_name               # clone your repo
git clone username/repo_name      # clone another user's repo

Forking a Repo using Hub

git clone username/repo
cd repo
git fork
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment