git

git is a version control tool allowing for easy collaboration on projects.

$ git clone https://github.com/c4cs/c4cs.github.io.git
$ cd c4cs.github.io
$ echo "Modified File" >> README.md
$ git add README.md
$ git commit -m "Added to README.md"
$ git push origin master

Useful Options / Examples

git init

Initializes the current directory as a git repository

$ git init

git status

git status shows the current state of your git repository. This lists the current branch, all the changes that have been made, and which changes are being tracked.

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   hello.cpp

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   bye.cpp

git log

git log Will display a list of all commits made on this project. For each commit, it will contain the SHA-1 hash of the commit (this is sort of like a commit ID), maybe some action done in that commit (such as the merge below), the author of the commit (so you know who to blame when the project breaks), the date of the commit, and the commit message.

$ git log
commit 09f6ef6fe7b28a3c1a3a296eb6d29d2c41310c83
Merge: e71dec1 d9ea675
Author: Some User <suser@email.com>
Date:   Fri Oct 20 12:32:59 2017 -0400

    Merge branch 'other'

commit d9ea675b182da0f025695b4f311283f3b0d86a99
Author: Some User <suser@email.com>
Date:   Fri Oct 20 12:32:51 2017 -0400

    Add some files

commit e71dec129976601109ce805ed1d07cb684ae015f
Author: Some User <suser@email.com>
Date:   Fri Oct 20 12:31:47 2017 -0400

    Change some files

commit 54682b444b11f0e36f332679102a41329abe4a7f
Author: Some User <suser@email.com>
Date:   Fri Oct 20 12:06:04 2017 -0400

    Initial Commit

git branch

git branch is used to make new branches or list local branches. A branch is like a different copy of your repository. If you think of git as a tree (which you should), git branch branches off of the current branch like so:

                   C other
                  /
    D---E---A'---F master
$ git branch
* master
$ git branch other
$ git branch
* master
  other

git checkout

git checkout allows you to switch to a different branch that you have already made.

$ git branch other
$ git branch
* master
  other
$ git checkout other
$ git branch
  master
* other

.gitignore

A .gitignore file in your git repository will allow you to exclude particular files from being tracked by git. In this example, git will not track the compiled .out file. Notice how it is not listed by git status. This is commonly used to ignore compiled binaries in git repos since git does not (normally) do well with binary files.

$ touch .gitignore
$ echo "*.out" >> .gitignore
$ # Make hello.cpp, a hello world program
$ git status
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	hello.cpp

no changes added to commit (use "git add" and/or "git commit -a")
$ g++ hello.cpp -o hello.out
$ ls
hello.cpp hello.out
$ git status
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	hello.cpp

no changes added to commit (use "git add" and/or "git commit -a")

.gitconfig

This file is the global configuration file for all of your projects on this machine. When you first ran git, it asked you to run git config --global user.name "Example Name". What that command was really doing was writing to this file. Some other things that can be useful:

$ cat ~/.gitconfig
[user]
	name = Pat Pannuto
	email = pat.pannuto@gmail.com

# This will automatically fix simple typos, e.g. `git psuh` will run `git push`
[help]
	autocorrect = 1

# Alias lets you create new git subcommands.
# The first example lets you type `git st` instead of `git status`.
# The rest of the examples augment `git log` to include various summaries of
# changed files, including the last example `git graph` we showed in lecture.
# Try them out!
[alias]
	st = status
	ll = log --stat --abbrev-commit
	gr = log --graph --full-history --all --color
	graph = log --graph --full-history --all --color --pretty=tformat:"%C(red)%h%C(reset)%x09%C(green)%d%C(reset)%C(bold)%s%C(reset)%C(yellow)(%an)%C(reset)"

git add

git add tells git to start tracking one or multiple files. Using the -A flag, you can tell git to track all changes in the git respository. Tracked files go in the staging area.

$ touch hello.cpp
$ touch goodbye.cpp
$ touch c4cs.hpp
$ touch c4cs.cpp
$ git add hello.cpp
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   hello.cpp

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	c4cs.cpp
	c4cs.hpp
	goodbye.cpp

$ git add -A
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   c4cs.cpp
	new file:   c4cs.hpp
	new file:   goodbye.cpp
	new file:   hello.cpp

git commit

git commit will save your added changes to the repository as a commit. The -m flag allows you to add the commit comment inline. Otherwise, you would have to write the comment in a pop up text editor (nano by default).

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   c4cs.cpp
	new file:   c4cs.hpp
	new file:   goodbye.cpp
	new file:   hello.cpp

$ git commit -m "Initial commit"
 4 files changed, 0 insertions(+), 0 deletions(-)

git reset

git reset is a command that undoes changes at several levels. You can un-add a tracked file by using the git reset command. If you have already committed changes that you don’t want to keep, you can use git reset --soft HEAD~1 which undoes the last commit, but keeps the changes in the staging area. You undo the last n commits by changing HEAD~1 to HEAD~n where n is the number of commits you want to undo. If instead you don’t want to keep any of the files in the commit, use git reset --hard HEAD~1. This undoes a commit and removes the files that were committed.

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   c4cs.cpp
	new file:   c4cs.hpp
	new file:   goodbye.cpp
	new file:   hello.cpp

$ git reset hello.cpp
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   c4cs.cpp
	new file:   c4cs.hpp
	new file:   goodbye.cpp

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	hello.cpp

$ git add hello.cpp
$ git commit -m "Commit all files"
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
$ git reset --soft HEAD~1
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   c4cs.cpp
	new file:   c4cs.hpp
	new file:   goodbye.cpp
	new file:   hello.cpp

$ git commit -m "Commit all files again"
$ git reset --hard HEAD~1
HEAD is not at 54682b4 Initial Commit
$ git status
On branch master
nothing to commit, working directory clean
$ ls
$

git push

git push pushes the commited changes on your local repository to a remote repository. remote is the url of the repository you are pushing to. master is the name of the branch you are pushing to the repository.

$ git push origin master

git fetch, git merge, git pull

git fetch retreives the contents of the remote repository origin on branch other without merging it with your current changes. You can checkout the fetched branch, but you will be in a detached head which limits what you can do on the branch. You can merge your current branch with the other branch by using git merge other. This will try to combine the commits in both branches in chronological order. Issues will emerge if there are conflicting changes in the branches. These issues must be resolved manually. Alternatively you can do git fetch origin other to fetch then merge in one command.

$ git fetch origin other
$ git merge other

OR

$ git pull origin other

git rebase

git rebase allows you to replay the changes made on one branch onto another branch. Think of git as a tree. Initially you have this structure where each node is a commit:

          A---B---C other
         /
    D---E---A'---F master

Running git rebase will replay the changes you made on other onto master resulting in:

                   B'---C' other
                  /
    D---E---A'---F master

Notice here that A is skipped. This is because A and A’ were both the same changes on both branches. Rebasing instead of merging should be done when there are merge conflicts in order to maintain a linear commit history.

During a rebase, conflicts may emerge. You have to resolve these manually. When you are done resolving conflicts, execute git rebase --continue to continue with the rebase. If you do not wish to resolve conflicts, execute git rebase --skip. If you want to abort the rebase process, execute git rebase --abort.

$ git rebase master other
First, rewinding head to replay your work on top of it...
Applying: change from branch other
Using index info to reconstruct a base tree...
M	hello.cpp
Falling back to patching base and 3-way merge...
Auto-merging hello.cpp
CONFLICT (content): Merge conglict in hello.cpp
Error: failed to merge in the changes.
$ # Fix merge conflicts manually
$ git rebase --continue
$ # Other merge conflict
$ git rebase --skip
$ # Other merge conflict
$ git rebase --abort

git blame

git blame will provide a line by line break down of who made what change in which commit. This is useful in not only blaming people when a project breaks, but also if you don’t understand what a line of code does, you know who to ask.

$ git blame hello.cpp

git cherry-pick

git cherry-pick allows you to choose particular commit(s) from one branch and apply them on another. This will create new commits on the branch to which you are applying the commits. The command below will apply the 13th to last and 4th to last commits from the branch other onto the branch master.

$ git checkout master
$ git cherry-pick other~12 other~3