Git

git init

# print the hash of a string
echo "Apple Pie" | git hash-object --stdin -w

# print the type a hash points to
git cat-file <SHA1> -t

# print the contents of the object referenced by hash
git cat-file <SHA1> -p

# print a commit referenced by hash
git cat-file -p <SHA1 of commit>

# get the number of objects in the repo
git count-objects

# create an annotated tag
git tag -a mytag -m "I love cheesecake"

Git Objects
- Blobs
- Trees
- Commits
- Tags

A branch is a reference to a commit.

HEAD is a reference to a branch, but...

A detached HEAD points directly to a commit.

A merge is a commit with 2 (or more) parents.

1. The current branch tracks new commits
2. When you move to another commit, Git updates your working directory
3. Unreachable objects are garbage collected

Merges preserve history.

Rebases refactor history.

When in doubt, merge.

A tag is like a branch that doesn't move.

Like a local branch, a remote branch is a reference to a commit.

Never rebase shared commits.

The Four Areas
- Working Area
- Index (Staging Area)
- Repository
- Stash

The Two Questions
- How does this command move information across the Four Areas?
- How does this command change the Repository?

# compare Working Area to Staging Area (unusual)
git diff

# compare Staging Area to Repository
git diff --cached

# compare branches
git diff lisa master

# move HEAD to a different branch and copy data from the Repository to the Working Area
git checkout lisa

# remove file from Staging Area
git rm --cached COPYRIGHT

git rm is NOT the opposite of git add

Git automatically finds out when you're renaming or moving files.

# move/rename file
git mv menu.md menu.txt

add copies data from the Working Area to the Staging Area

commit copies data from the Staging Area to the Repository

checkout copies data from the Repository to the Working Area and the Staging Area

rm deletes files from both the Working Area and the Staging Area

mv moves a file in both the Working Area and the Staging Area

reset moves the current branch, and optionally copies data from the Repository to the other
areas

# revert changes in Staging Area
git reset HEAD

# revert changes in Working Area and Staging Area
git reset --hard HEAD

... BUT

# revert single file in Stating Area
git reset HEAD <file>

# revert single file in Working Area and Staging Area
# (if this looks wierd, that means you were paying attention)
git checkout HEAD <file>

# save off current state and pull from Repository
git stash --include-untracked

# recover stashed files
git stash apply

# clean up stash
git stash list
git stash clear

# inspect object
git show <SHA1>

# show history
git log --graph --decorate --oneline

# inspect commits up to 1 month ago
git show HEAD@@{"1 month ago"}

# show history of who changed lines
git blame <file>

# show delta between commits
git diff HEAD HEAD~2

# show changes that contain specific words
git log --grep apples --oneline

# show commits that added or removed specific words
git log -Gapples --patch

# show range of commits
git log HEAD~5..HEAD^ --oneline

# show all the commits between branches 
git log nogood..master --oneline

# sets up Git with your name
git config --global user.name "<Your-Full-Name>"

# change the current commit
git commit --amend

# manually edit history
git rebase -i

# look at reference log
git reflog

# automatically create a reversing commit
git revert <SHA1>

Be careful when you revert merge commits.

"revert" doesn't mean "undo"

Distribution Models
- Peer-to-Peer
- Centralized
- Pull Request
- Dictator and Lieutenants

# sets up Git with your email
git config --global user.email "<your-email-address>"

# makes sure that Git output is colored
git config --global color.ui auto

# displays the original state in a conflict
git config --global merge.conflictstyle diff3

# editor defaults to vim
git config --global core.editor ("vim"|"code --wait")

git config --list

git init

git clone <URL> [target-name]

git status

git log [--oneline|--stat|-p] [SHA]

# show log of all branches
git log --oneline --graph --all

# show various types of objects
git show <SHA>

git add (.|<file>)

git rm --cached <file>

git commit [-m "<message>"]

git diff

The .gitignore file is used to tell Git about the files that Git should not track.

git tag -a <tag> [<SHA>]

# list branches
git branch

# create branch
git branch <branch>

# delete branch
git branch <branch> (-d|-D)

git checkout <branch>

# create and checkout branch
git checkout -b <branch>

# ☞ back out pending changes to a specific file (`revert' in most other repos)
git checkout <path/to/file>

git merge <name-of-branch-to-merge-in>

A Fast-forward merge will just move the currently checked out branch forward until it points to
the same commit that the other branch is pointing to.

# alter the most recent commit
git commit --amend

git revert <SHA-of-commit-to-revert>

Here's how we can refer to previous commits:
the parent commit – the following indicate the parent commit of the current commit
HEAD^
HEAD~
HEAD~1
the grandparent commit – the following indicate the grandparent commit of the current commit
HEAD^^
HEAD~2 
the great-grandparent commit – the following indicate the great-grandparent commit of the
current commit
HEAD^^^
HEAD~3

# delete a commit
git reset <reference-to-commit>

# show full path to the remote repository
git remote -v

# add a connection to a new remote repository
git remote add origin https://github.com/PaulNWms/<repo-name>.git

git push origin master

# fetch and merge
git pull origin master

# fetch without merging
git fetch origin master

git merge origin/master

Forking a repository creates an identical copy of a repository and moves this copy to your
GitHub account.

# show contributors
git shortlog

# sort by activity
git shortlog -s -n

# show commits by author
git log --author="<name>"

git log --grep="<regex>"

CONTRIBUTING.md

# add a connection to a project's main repository (not your fork)
git remote add upstream https://github.com/

# in case you don't like working with 'origin' and 'upstream'
git remote rename <name> <new-name>

# bring project's main repository changes into our local branch
git fetch upstream master

To get commits from a source repository into your forked repository on GitHub you need to:
- get the cloneable URL of the source repository
- create a new remote with the git remote add command 
-- use the shortname upstream to point to the source repository
-- provide the URL of the source repository
- fetch the new upstream remote
- merge the upstream's branch into a local branch
- push the newly updated local branch to your origin repo

# squash 3 commits together
# create a backup branch before git rebase
git rebase -i HEAD~3

# then the change will have to be force pushed to your fork
git push -f origin <branch>

# apply changes to repo after updating .gitignore
git rm -r --cached .
git add .

References