Git In-depth
Git In-Depth
Introduction
By coding along with us in this workshop you’ll:
通过与我们一起编写代码,您将:
- Learn how git represents commits and branches internally to gain deep insights into how git works under the hood…
 - 了解git如何在内部表示提交和分支,从而深入了解git的底层工作原理……
 - Discover the power of rebasing in git, along with how to avoid common pitfalls. Learn to tell when it’s appropriate to re-write history…
 - 了解在git中重新建立基础的强大功能,以及如何避免常见的陷阱。学会分辨什么时候改写历史是合适的……
 - Discover how git hooks can make your life easier by running analysis on your code before you commit in order to prevent common errors from making their way into your codebase…
 - 了解git钩子是如何让您的工作变得更简单的,在您提交代码之前运行对代码的分析,以防止常见错误进入您的代码库……
 - Discover lesser-known features of git that will save you hours of time when resolving merge conflicts and track down bugs…
 - 发现git不太为人所知的特性,这将为您节省几个小时的时间来解决合并冲突和跟踪bug…
 - Learn how to harness the power of the GitHub API to fetch information about your repositories.
 - 学习如何利用GitHub API的强大功能来获取关于存储库的信息。
 
Requirements
- command line that supports unix style commands
 - git version > 2.0(check with 
git --version) - github.com account
 - clone git.io/advanced-git for slides and exercises
 - (oxs only) install homebrew - https://brew.sh/
 
Course Agenda

Class Overview
- What is Git?
 - Working Area, Staging Area, Repository
 - Staging Area Deep Dive
 - References, Commits, Branches
 - Stashing
 - Merging + Rebasing
 - History + Diffs
 - Fixing Mistakes
 - Rebase
 - Forks, Remote Reponsitories
 - The Danger Zone
 - Advanced Tools
 - Customization - Config, Ignore, Hooks, Templates
 - Social Git: Integrating GitHub with CI Tools
 - Advanced GitHub: Working with the GitHub API
 
Git Foundations
Data Storage
WHAT IS GIT
Distributed Version Control System
HOW DOES GIT STORE INFORMATION
- At its core, git is like a key value store.
 - The Value = Data
 - The Key = Hash of the Data
 - You can use the key to retrieve the content.
 
The Key - SHA1
- Is a cryptographic hash function.
 - 是一个加密哈希函数。
 - Given a piece of data, it produces a 40-digit hexadecimal number.
 - 给定一段数据,它产生一个40位的十六进制数。
 - This value should always be the same if the given input is the same.
 - 如果给定的输入是相同的,那么这个值应该总是相同的。
 
Git Blobs & Trees
The Value - Blob
- git stores the compressed data in a blob, along with metadata in a header:
- the identifier blob
 - the size of the content \0 delimiter
 - content
 
 
UNDER THE HOOD - GIT HASH-OBJECT
Asking Git for the SHA1 of contents:echo 'Hello, World!' | git hash-object --stdin8ab686eafeb1f44702738c8b0f24f2567c36da6d
Generating the SHA1 of the contents, with metadata:echo 'blob 14\0Hello, World!' | openssl sha18ab686eafeb1f44702738c8b0f24f2567c36da6d
It’s a Match!
8ab68…
| blob | 14 | 
|---|---|
| \0 | |
| Hello, World! | 
WHERE DOES GIT STORE ITS DATA
1  | ~/projects/sample  | 
.git directory contains data about our repository
WHERE ARE BLOBS STORED
1  | ❯ echo 'Hello, World!' | git hash-object -w --stdin  | 
1  | ❯ rm -rf .git/hooks  | 
WE NEED SOMETHING ELSE
The blob is missing information!
- filenames
 - directory structures
 
Git stores this information in a tree.
TREE
a tree contains pointers (using SHA1):
- to blobs
 - to other trees
 
and metadata:
- type of pointer (blob or tree)
 - filename or directory name
 - mode (executable file, symbolic link, …)
 
1  | .  | 
4ad20…
| tree | <size> | 
|
|---|---|---|
| \0 | ||
| blob | 8ab68 | hello.txt | 
| tree | a14ca | copies | 

IDENTICAL CONTENT IS ONLY STORED ONCE
在git的存储文件中,tree可以包含了当前文件夹下的blob及相关联的tree,当两个tree指向的blob内容相同时,根据前面提到的,生成的sha1也相同,那么两个不同tree的blob将指向同一个blob。
OTHER OPTIMIZATIONS - PACKFILES, DELTAS
- Git objects are compressed
 - As files change, their contents remain mostly similar.
 - Git optimizes for this by compressing these files together, into a Packfile
 - The Packfile stores the object, and “deltas”, or the differences between one version of the file and the next.
 - Packfiles are generated when:
- you have too many objects, during gc(garbage collection), or during a push to a remote
 
 
Git Commits
COMMIT OBJECT
a commit points to:
- a tree
 
and contains metadata:
- author and committer
 - date
 - message
 - parent commit (one or more)
 
the SHA1 of the commit is the hash of all this information
fae12…
| commit | size | 
|---|---|
| tree | 8ab68 | 
| parent | a14ca | 
| author | Nina | 
| message | “Initial Commit” | 

A COMMIT IS A CODE SNAPSHOT
COMMITS UNDER THE HOOD - MAKE A COMMIT
1  | echo 'Hello World!' > hello.txt  | 
COMMITS UNDER THE HOOD - LOOK IN .GIT/OBJECTS
1  | tree .git/objects  | 
COMMITS UNDER THE HOOD - LOOKING AT OBJECTS
1  | ❯ cat .git/objects/98/0a0d5f19a64b4b30a87d4206aade58726b60e3  | 
oops!
remember, git objects are compressed.
GIT CAT-FILE -T (TYPE) AND -P (PRINT THE CONTENTS)
1  | ❯ git cat-file -t 980a0 # -t print the type  | 
1  | git cat-file -p 980a0 # -p print the contents  | 
1  | ❯ git cat-file -t 581caa  | 
1  | ❯ git cat-file -t adf0e1  | 
WHY CAN’T WE “CHANGE” COMMITS
- If you change any data about the commit, the commit will have a new SHA1 hash.
 - Even if the files don’t change, the created date will.
 
REFERENCES - POINTERS TO COMMITS
- Tags
 - Branches
 - HEAD - a pointer to the current commit
 
REFERENCES - UNDER THE HOOD
1  | ❯ tree .git .git  | 
1  | ❯ git log --oneline  | 
Exercise: Simple Git Commit
- Configure your editor
 - Complete exercise
 - Check out cheat sheet for using less
- git.io/use-less
 
 
Exercise:
- Create a new folder and initialize it as a git repo
 
1  | mkdir ./sample  | 
- Create a file, stage it, and commit it to your new repo
 
1  | echo 'Hello World!' > hello.txt  | 
- Look at your .git folder, using tree if you have it
 
1  | tree .git  | 
- Inspect the objects in your .git/objects folder using git cat-file. See if you can find the tree, blob, and commit objects for your recent commit.
 
1  | git cat-file -t 581caa  | 
- Look at your .git/HEAD and .git/refs/heads/master files and see if you can figure out where these references are pointing to.
 
1  | cat .git/HEAD  | 
Git Areas & Stashing
Working Area, Staging Area, Repository
THREE AREAS WHERE CODE LIVES
- Working Area
 - Staging Area
 - Repository
 
THE WORKING AREA(A.K.A WORKING TREE)
- The files in your working area that are also not in the staging are are not handled by git.
 - Also called untracked files
 
THE STAGING AREA (A.K.A INDEX, CACHE)
- What files are going to be part of the next commit
 - The staging area is how git knows what will change between the current commit and the next commit.
 
THE REPOSITORY
- The files git knows about!
 - Contains all of your commits
 
CLOSER LOOK: THE STAGING AREA
THE STAGING AREA
- The staging area is how git knows what will change between the current commit and the next commit.
 - Tip: a “clean” staging area isn’t empty!
 - Consider the baseline staging area as being an exact copy of the latest commit.
 
1  | ❯ git ls-files -s # The plumbing command ls-files -s will show you what’s in the staging area.  | 
MOVING FILES IN & OUT OF THE STAGING AREA
- add a file to the next commit:
git add <file>
 - delete a file in the next commit:
git rm <file>
 - rename a file in the next commit:
git mv <file>
 
GIT ADD -P
- one of my favorite tools
 - allows you to stage commits in hunks
 - interactively!
 - It’s especially useful if you’ve done too much work for one commit.
 
USING GIT ADD -P
1  | ❯ git add -p  | 
“UNSTAGE” FILES FROM THE STAGING AREA
- Not removing the files.
 - You’re replacing them with a copy that’s currently in the repository.
 
BASICS: HOW CONTENT MOVES IN GIT

Stashing
GIT STASH
- Save un-committed work.
 - The stash is safe from destructive operations.
 
GIT STASH - BASIC USE
- stash changes
git stash
 - list changes
git stash list
 - show the contents
git stash show stash@{0}
 - apply the last stash
git stash apply
 - apply a specific stash
git stash apply stash@{0}
 
ADVANCED STASHING - KEEPING FILES
- Keep untracked files
git stash --include-untracked
 - Keep all files (even ignored ones!)
git stash --all
 
ADVANCED STASHING - OPERATIONS
- Name stashes for easy reference
git stash save "WIP: making progress on foo"
 - Start a new branch from a stash
git stash branch <optional stash name>
 - Grab a single file from a stash
git checkout <stash name> -- <filename>
 
ADVANCED STASHING - CLEANING THE STASH
- Remove the last stash and applying changes:
git stash pop- tip: doesn’t remove if there’s a merge conflict
 
 - Remove the last stash
git stash drop
 - Remove the nth stash
git stash drop stash@{n}
 - Remove all stashes
git stash clear
 
EXAMINING STASH CONTENTS - GIT SHOW
1  | ❯ git stash list  | 
GIT STASH - WHAT I USE
- Keep untracked files
git stash --include-untracked
 - Name stashes for easy reference
git stash save "WIP: making progress on foo"
 
Exercise: Staging & Stashing
1  | git clone git@github.com:nnja/advanced-git-exercises.git  | 
- Use git ls-files -s to view the contents of the staging area.
 
1  | git ls-files -s  | 
- Make a change and try to stage it interactively (
git add -p). 
1  | echo "This is a test of the emergency git-casting system" >> hello.txt  | 
- Use 
git resetto undo the staging of your file. 
1  | git reset hello.txt  | 
- Stash your change with a unique stash message, then unstash and apply it back to the exercise2 branch.
 
1  | git stash save "emergency git-casting"  | 
References, Commits, Branches
References(pointers to commits)
THREE TYPES OF GIT REFERENCES
- Tags & Annotated Tags
 - Branches
 - HEAD
 
WHAT’S A BRANCH
- A branch is just a pointer to a particular commit.
 - The pointer of the current branch changes as new commits are made.
 
WHAT IS HEAD
- HEAD is how git knows what branch you’re currently on, and what the next parent will be.
 - It’s a pointer.
- It usually points at the name of the current branch.
 - But, it can point at a commit too (detached HEAD).
 
 - It moves when:
- You make a commit in the currently active branch
 - When you checkout a new branch
 
 
1  | ❯ git checkout master  | 
SAMPLE REPO - A SIMPLE BLOG
- We’re working on a simple blog.
 - index.txt contains links to our entries, and post titles
 - the posts/ directory contains our blog entries.
 
1  | ❯ mkdir posts  | 
CURRENT REPO STATE
1  | ❯ git init  | 
1  | ❯ git checkout -b tech_posts  | 
1  | ❯ git add posts/python.txt  | 
Tags & Annotated Tags
LIGHTWEIGHT TAGS
- Lightweight tags are just a simple pointer to a commit.
 - When you create a tag with no arguments, it captures the value in HEAD
 
1  | ❯ git checkout master  | 
ANNOTATED TAGS: GIT TAG -A
- Point to a commit, but store additional information.
- Author, message, date.
 
 
1  | ❯ git tag -a v1.0 -m "Version 1.0 of my blog"  | 
WORKING WITH TAGS
- List all the tags in a repo
git tag
 - List all tags, and what commit they’re pointing to
git show-ref --tags
 - List all the tags pointing at a commit
git tag --points-at <commit>
 - Looking at the tag, or tagged contents:
git show <tag-name>
 
TAGS & BRANCHES
- Branch
- The current branch pointer moves with every commit to the repository
 
 - Tag
- The commit that a tag points doesn’t change. It’s a snapshot!
 
 
Detached Head & Dangling Commits
HEAD-LESS / DETACHED HEAD
- Sometimes you need to checkout a specific commit (or tag) instead of a branch.
 - git moves the HEAD pointer to that commit
 - as soon as you checkout a different branch or commit, the value of HEAD will point to the new SHA
 - There is no reference pointing to the commits you made in a detached state.
 
1  | ❯ git checkout cd0b57  | 
1  | ❯ git add posts/second-post.txt  | 
- Save your work:
- Create a new branch that points to the last commit you made in a detached state.
- g
it branch <new-branch-name> <commit> 
 - g
 - Why the last commit?
- Because the other commits point to their parents.
 
 
 - Create a new branch that points to the last commit you made in a detached state.
 
DANGLING COMMITS
- Discard your work:
- If you don’t point a new branch at those commits, they will no longer be referenced in git. (dangling commits)
 - Eventually, they will be garbage collected.
 
 
1  | ❯ git checkout master  | 
Exercise: References
1  | git checkout exercise3  | 
- Check the value of your HEAD variable (hint: look in .git) and confirm you’re pointed at the exercise3 branch.
 
1  | cat .git/HEAD  | 
- Use show-ref to look at your other heads.
 
1  | git show-ref --heads  | 
- Create a lightweight tag and confirm that it’s pointing at the right commit.
 
1  | git tag my-exercise3-tag  | 
- Create an annotated tag, and use 
git showto see more information about it. 
1  | git tag -a "exercise3-annotated-tag" -m "This is my annotated tag for exercise 3"  | 
- Get into a “detached HEAD” state by checking out a specific commit, then confirm that your HEAD is pointing at this commit rather than at a branch.
 
1  | git log --oneline  | 
- Make a new commit, then switch branches to confirm that you’re leaving a commit behind.
 
1  | echo "This is a test file" > dangle.txt  | 
Merging & Rebasing
Merging & Fast Forward
UNDER THE HOOD - MERGE COMMITS ARE JUST COMMITS
1  | ❯ git cat-file -p 649efc8c9  | 
FAST FORWARD
1  | git checkout master  | 
Fast-forward happens when there are no commits on the base branch that occurred after the feature branch was created.
GIT MERGE –NO-FF (NO FAST FORWARD)
- To retain the history of a merge commit, even if there are no changes to the base branch:
- use 
git merge --no-ff 
 - use 
 - This will force a merge commit, even when one isn’t necessary.
 
1  | git checkout master  | 
Merge Conflicts
- Attempt to merge, but files have diverged.
 - Git stops until the conflicts are resolved.
 
1  | git merge feature  | 
GIT RERERE - REUSE RECORDED RESOLUTION
git saves how you resolved a conflict
next conflict: reuse the same resolution
useful for:
- long lived feature branch (like a refactor)
 - rebasing
 
Turn it on:
git config rerere.enabled true- use –global flag to enable for all projects
 
1  | ❯ git config rerere.enabled true  | 
When I commit the conflict resolution, it’s recorded.
- Now: Feature wasn’t ready, I undid the merge.
 - When I try to merge again:
 
1  | ❯ git merge feature  | 
The resolution is automatically reapplied.
Exercise: Merging & ReReRe
1  | git checkout exercise4  | 
- Merge the exercise3 branch into exercise4, and look at the git log.
 
1  | git merge exercise3  | 
- Use git reset –hard to reset your exercise4 branch back one commit, then use the –no-ff option to git merge to merge exercise3 again. Look at the git log, how is it different from the last step?
 
1  | git reset --hard HEAD^  | 
- Make two conflicting changes to hello.txt in two different branches.
 
1  | git branch  | 
- Enable ReReRe, then merge one branch into the other.
 
1  | git config rerere.enabled true  | 
- Backup again with git reset –hard, then attempt the merge again. Notice how ReReRe automatically resolves the conflict for you.
 
1  | git reset --hard HEAD^  | 
History & Diffs
Useful Commit Message
BAD COMMIT MESSAGES

GOOD COMMITS ARE IMPORTANT
- Good commits help preserve the history of a code base.
 - They help with:
- debugging & troubleshooting creating release notes
 - code reviews
 - rolling back
 - associating the code with an issue or ticket
 
 
Commit message is in future tense. ‘Fix’ vs ‘Fixed’
Short subject, followed by a blank line.
1  | git-rebase: don't ignore unexpected command line arguments  | 
A description of the current behavior, a short summary of why the fix is needed. Mention side effects.
The description is broken into 72 char lines.
ANATOMY OF A GOOD COMMIT
- Good commit message
 - Encapsulates one logical idea
 - Doesn’t introduce breaking changes
- i.e. tests pass
 
 
Git Log
git log- the basic command that shows you the history of your repository
1  | ❯ git log  | 
GIT LOG –SINCE
- The site is slow. What changed since yesterday?
git log --since="yesterday"git log --since="2 weeks ago"
 
GIT LOG –FOLLOW
- Log files that have been moved or renamed
git log --name-status --follow -- <file>
 
GIT LOG –GREP
- Search for commit messages that match a regular expression:
git log —grep <regexp>- Can be mixed & matched with other git flags.
 
 - Example:
git log --grep=mail --author=nina --since=2.weeks
 
GIT LOG DIFF-FILTER
- Selectively include or exclude files that have been:
 - (A)dded, (D)eleted, (M)odified & more…
 
1  | > git log --diff-filter=R --stat  | 
GIT LOG: REFERENCING COMMITS
^or^n- no args: ==^1: the first parent commit
 - n: the nth parent commit
 
~or~n- no args: == ~1: the first commit back, following 1st parent
 - n: number of commits back, following only 1st parent
 
note:
^and~can be combined
REFERENCING COMMITS
- Both commit nodes B and C are parents of commit node A.
Parent commits are ordered left-to-right. - A is the latest commit.
 
Git Show & Diffs
GIT SHOW: LOOK AT A COMMIT
- show commit and contents:
git show <commit>
 - show files changed in commit:
git show <commit> --stat
 - look at a file from another commit:
git show <commit>:<file>
 
DIFF
Diff shows you changes:
- between commits
 - between the staging area and the repository
 - what’s in the working area
 
unstaged changes
git diff
staged changes
git diff --staged
“DIFF” BRANCHES
Which branches are merged with master, and can be cleaned up?
git branch --merged master
Which branches aren’t merged with master yet?
git branch --no-merged master
Exercise: History & Diffs
1  | git checkout exercise5  | 
- Practice creating a well-crafted commit - look at the format given on the slides for help.
 
1  | vi hello.txt # Change your `hello.txt` to say [greeting] [noun]!  | 
- Use 
git logto find commits created since yesterday. Rename a file and use the--name-statusand--followoptions togit logto track down when the file was renamed, and what it used to be called. Use--grepto search within commit messages, and –diff-filter to find renamed and modified files fromgit log. 
1  | git log --since="yesterday"  | 
- Use 
git showto get more information about a specific git hash. 
1  | git log --grep=i18n --oneline  | 
- Try the 
--mergedand--no-mergedoptions to git branch to see which branches have been merged into master (or not). 
1  | git branch --merged master  | 
Fixing Mistakes
Git Checkout
Restore working tree files or switch branches
WHAT HAPPENS WHEN YOU GIT CHECKOUT A BRANCH
- Change HEAD to point to the new branch
 - Copy the commit snapshot to the staging area
 - Update the working area with the branch contents
 
WHAT HAPPENS WHEN YOU GIT CHECKOUT - - FILE
Replace the working area copy with the version from the current staging area
Warning: This operation overwrites files in the working directory without warning!
GIT CHECKOUT: OVERWRITE FILES WITH STAGING AREA COPY
- Overwrite the working area file with the staging area version from the last commit
git checkout -- <file_path>
 
Warning: This operation overwrites files in the working directory without warning!
WHAT HAPPENS WHEN YOU GIT CHECKOUT  - - FILE 
- Update the staging area to match the commit
 - Update the working area to match the staging area.
 
Warning: This operation overwrites files in the working directory without warning!
GIT CHECKOUT: FROM A SPECIFIC COMMIT
Checkout a file from a specific commit
- copies to both working area & staging area
 git checkout <commit> -- <file_path>
Restore a deleted file
git checkout <deleting_commit>^ -- <file_path>
Warning: This operation overwrites files in the working directory without warning!
Git Clean & Reset
GIT CLEAN
- Git clean will clear your working area by deleting untracked files.
Warning: this operation cannot be undone!
 - Use the 
—dry-runflag to see what would be deleted- The 
-fflag to do the deletion - The 
-dflag will clean directories 
 - The 
 
1  | ❯ git clean --dry-run  | 
GIT RESET
- Reset is another command that performs different actions depending on the arguments.
- with a path
 - without a path
 - By default, git performs a 
git reset —mixed 
 - For commits:
- Moves the HEAD pointer, optionally modifies files
 
 - For file paths:
- Does not move the HEAD pointer, modifies files
 
 
RESET –SOFT: MOVE HEAD
1  | ❯ git reset --soft HEAD~  | 
RESET –SOFT: RESULT
RESET –MIXED: MOVE HEAD, COPY FILES TO STAGE
1  | ❯ git reset HEAD~  | 
RESET –MIXED: RESULT
RESET –HARD: MOVE HEAD, COPY FILES TO STAGE & WORKING
1  | ❯ git reset --hard HEAD~  | 
Warning: this overwrites files and cannot be undone!
RESET –HARD: RESULT
Warning: this overwrites files and cannot be undone!
GIT RESET  CHEAT CHEAT 
- Move HEAD and current branch
 - Reset the staging area
 - Reset the working area
 
1  | --soft = (1)  | 
DANGER: GIT RESET CAN CHANGE HISTORY
1  | ❯ git reset --soft HEAD~  | 
Warning: never push changed history to a shared or public repository!
GIT RESET – 
1  | ❯ git reset <file>  | 
GIT RESET – : RESULT 
GIT RESET  –  
1  | ❯ git reset <commit> -- <file>  | 
GIT RESET  – : RESULT  
GIT RESET  –  CHEAT CHEAT  
Move HEAD and current branch- Reset the staging area
 Reset the working area
This operation does not work with flags!
UNDO A GIT RESET WITH ORIG_HEAD
- In case of an accidental 
git reset - - Git keeps the previous value of HEAD in variable called 
ORIG_HEAD - To go back to the way things were:
git reset ORIG_HEAD
 
Git Revert
GIT REVERT - THE “SAFE” RESET
Git revert creates a new commit that introduces the opposite changes from the specified commit.
The original commit stays in the repository.
Tip:
- Use revert if you’re undoing a commit that has already been shared.
 - Revert does not change history.
 
GIT REVERT - PICK A COMMIT TO UNDO
1  | ❯ git log --oneline  | 
1  | ❯ git revert 2b0b3f2  | 
SUMMARY: COMMON WAYS OF UNDOING CHANGES
- checkout
 - reset
 - revert
 
Exercise: Fixing Git Mistakes
1  | git checkout exercise6  | 
- Make bad changes to a file, then use 
git checkoutto fix it. Usegit checkoutto reset your file back to an earlier point in time. 
1  | echo "bad data" > hello.template  | 
- Use git clean to remove untracked files from your repo. Remember to use 
--dry-runfirst. 
1  | git clean --dry-run  | 
- Stage a change and then use 
git resetto unstage it. Usegit reset --hardto reset your branch back pointer, staging area, and working area to an earlier commit. Use “mixed mode” to reset your branch back to an earlier commit, then useORIG_HEADto reset your branch back to where you were. 
1  | git status  | 
- Practice using 
git revertto safely revert a commit with a new commit. 
1  | # Let's revert the last commit.  | 
Rebase & Amend
Git Amend
AMEND A COMMIT
- Amend is a quick and easy shortcut that lets you make changes to the previous commit.
 
1  | ❯ cat index.txt  | 
COMMITS CAN’T BE EDITED
- Remember, commits can’t be edited!
 - A commit is referenced by the SHA of all its data.
 - Even if the tree the commit points to is the same, and the author is the same, the date is still different!
 - A new commit is created.
 
Rebase
WHAT IS REBASE ANYWAY
Imagine our tech_posts and master branch have diverged.
We don’t want a messy merge commit in our history.
We can pull in all the latest changes from master, and apply our commits on top of them by changing the parent commit of our commits.
Rebase = give a commit a new parent (i.e. a new “base” commit)
REBASE: REWINDING HEAD
1  | ❯ git checkout tech_posts Switched to branch 'tech_posts'  | 
REBASE: APPLY NEW COMMITS
1  | ❯ git rebase master  | 
POWER OF REBASING - REPLAY COMMITS
- Commits can be:
- edited
 - removed
 - combined
 - re-ordered
 - inserted
 
 - Before they’re “replayed” on top of the new HEAD.
 
INTERACTIVE REBASE (REBASE -I OR REBASE –INTERACTIVE)
Interactive rebase opens an editor with a list of “todos”
- in the format of: 
<command> <commit> <commit msg> - git will pick the commits in the specified order, or stop to take an action when editing or a conflict occurs.
 
- in the format of: 
 interactive rebase with a shortcut:
git rebase -i <commit_to_fix>^- (the ^ specifies the parent commit)
 
REBASE OPTIONS
pick- keep this commit
 
reword- keep the commit, just change the message
 
edit- keep the commit, but stop to edit more than the message
 
squash- combine this commit with the previous one. stop to edit the message
 
fixup- combine this commit with the previous one. keep the previous commit message
 
exec- run the command on this line after picking the previous commit
 
drop- remove the commit (tip: if you remove this line, the commit will be dropped too!)
 
EXAMPLE REBASE
1  | ❯ git log --oneline  | 
TIP: USE REBASE TO SPLIT COMMITS
Editing a commit can also split it up into multiple commits!
- Start an interactive rebase with 
rebase -i - mark the commit with an edit
 git reset HEAD^git addgit commit- repeat (4) & (5) until the working area is clean!
 git rebase --continue
Fixup & Autosquash
TIP: “AMEND” ANY COMMIT WITH FIXUP & AUTOSQUASH
What if we want to amend an arbitrary commit?
git add new filesgit commit --fixup <SHA>- this creates a new commit, the message starts with ‘fixup!’
 
git rebase -i --autosquash <SHA>^- git will generate the right todos for you! just save and quit.
 
FIXUP & AUTOSQUASH EXAMPLE
1  | ❯ git log --oneline  | 
1  | ❯ git rebase -i --autosquash 25b3810^ # use the -i and --autosquash flags && use ref of the parent commit  | 
REBASE –EXEC (EXECUTE A COMMAND)
$ git rebase -i —exec “run-tests” <commit>
2 options for exec:
- add it as a command when doing interactive rebase
 - use it as a flag when rebasing
 
- When used as a flag, the command specified by exec will run after every commit is applied.
 - This can be used to run tests.
 - The rebase will stop if the command fails, giving you a chance to fix what’s wrong.
 
Abort
PULL THE RIP CORD
- At any time before rebase is done, if things are going wrong:
git rebase --abort
 
REBASE PRO TIP
Before you
rebase/fixup/squash/reorder:Make a copy of your current branch:
git branch my_branch_backup
git branch will make a new branch, without switching to it
If rebase “succeeds” but you messed up…
git reset my_branch_backup --hardYou’re back in business!
REBASE ADVANTAGES
- Rebase is incredibly powerful!
 - You can slice and dice your git history.
 - It’s easy to fix previous mistakes in code.
 - You can keep your git history neat and clean.
 
COMMIT EARLY & OFTEN VS GOOD COMMITS
Git Best Practice:
- “commit often, perfect later, publish once”
 
When working locally:
- Commit whenever you make changes!
 - It’ll help you be a more productive developer.
 
Before pushing work to a shared repo:
- Rebase to clean up the commit history
 
WARNING: NEVER REWRITE PUBLIC HISTORY
- Rebase commits are copies
 - If other people are working on the same repository they would be working on different commits.
 - You could cause massive merge conflicts
 - Even worse, you can cause people to lose their work!
 
Warning: If you rewrite history and push to a public repo, monsters will eat you!
Exercise: Git Rebase & Amend
1  | liuyong$ git checkout exercise7  | 
- Make a commit, then practice using the 
--amendoption to make another change to the previous commit. 
1  | echo "This is the first file" > first.txt  | 
- Make two non-conflicting changes to two different branches. Rebase one branch onto the other.
 
1  | git checkout master  | 
- Make another change to your current branch. Use an interactive rebase (
git rebase -i) to rebase the two branches. Try squashing your two commits and rewording the message during the rebase. 
1  | echo "Another new feature" > another_feature.txt  | 
Forks & Remote Repos
Github vs. Git
GITHUB VS GIT - THE KEY IS COLLABORATION
- Git:
- Open source version control software
 
 - Github:
- Repository hosting
 - Browse code
 - Issues
 - Pull Requests
 - Forks
 
 
Remotes
A remote is a git repository stored elsewhere - on the web, in github, etc.
origin is the default name git gives to the server you cloned from.
Cloning a remote repository from a URL will fetch the whole repository, and make a local copy in your .git folder.
You may have different privileges for a remote.
- Read/Write for some, Read Only for others.
 
CLONE REPOSITORY
git clone git@github.com:lisa/projA.git
VIEWING REMOTES
1  | ❯ git remote -v  | 
CLONED SOMEONE ELSE’S REPOSITORY
1  | git clone git@github.com:dan/projB.git  | 
Forks, Pull Requests & Upstreams
FORK
- A fork is a copy of a repository that’s stored in your GitHub account.
 - You can clone your fork to your local computer.
 
MERGING CHANGES TO ORIGINAL PROJECT FROM A FORK
STAYING UP TO DATE
- While you work on your fork, other changes are getting merged into the source repository.
 - In order to stay up to date, set up an upstream
 
UPSTREAM
- The upstream repository is the base repository you created a fork from.
 - This isn’t set up by default, you need to set it up manually.
 - By adding an upstream remote, you can pull down changes that have been added to the original repository after you forked it.
 
❯ git remote add upstream https://github.com/ORIG_OWNER/REPO.git
Github Workflow
TRIANGULAR WORKFLOW

TRACKING BRANCHES
Track a branch to tie it to an upstream branch.
- Bonus: Use git push / pull with no arguments
 
To checkout a remote branch, with tracking:
git checkout -t origin/feature
Tell Git which branch to track the first time you push:
git push -u origin feature
1  | ❯ git branch * master  | 
FETCH
- Git fetch is important for keeping your local repository up to date with a remote.
 - It pulls down all the changes that happened on the server
 - But, it doesn’t change your local repository!
 
PULL
Pulling will pull down the changes from the remote repository to your local repository, and merging them with a local branch.
Under the hood:
git pull = git fetch && git merge
If changes happened upstream, git will create a merge commit.
Otherwise, it will fast-forward.
PUSH
Pushing sends your changes to the remote repository
git only allows you to push if your changes won’t cause a conflict
TIP:
- To see commits which haven’t been pushed upstream yet, use:
git cherry -v
 
- To see commits which haven’t been pushed upstream yet, use:
 
GIT PULL —REBASE
- Git pull —rebase will fetch, update your local branch to copy the upstream branch, then replay any commits you made via rebase.
 - Bonus: When you open a PR, there will be no unsightly merge commits!
 
NOTE: TAGS
- Git doesn’t automatically push local tags to a remote repository.
 - To push tags:
git push <tagname>git push --tags
 
CONTRIBUTING TO OPEN SOURCE PROJECTS - PULL REQUESTS
Before opening a PR:
- Keep commit history clean and neat. Rebase if needed.
 - Run projects tests on your code
 - Pull in Upstream changes (preferably via rebase to avoid merge commits)
 - check for a CONTRIBUTING (.md/.txt) in the project root
 
After opening a PR:
- Explain your changes throughly in the pull request
 - Link to any open issues that your pull request might fix
 - Check back for comments from the maintainers
 
ADVICE
- Encourage developers to work on their own forks of a repository.
 - Mistakes are less likely to happen if no one is pushing directly to the “source of truth” for your codebase!
 - You can rebase and force push freely to your own origin, as long as no one else is cloning your branch.
 
PUSHING/MERGING YOUR CHANGES BACK TO A REMOTE
- Rule of thumb:
- Rebase commits on your local feature branch
 - Merge feature branches back to origin (or upstream)
 
 - When accepting a pull request:
- Squash and merge or rebase with care.
 - You’ll lose context about the work on the feature branch!
 - It’ll make it harder to debug when issues arise in the future
 
 
Exercise: Forks & Remote Repos Exercise
1  | git checkout master  | 
- Create your own Github fork of https://github.com/nnja/advanced-git-exercises.
 
In Github, go to https://github.com/nnja/advanced-git-exercises and create your own fork of this repo by clicking the Fork button in the top right corner. This should create a copy of the repo that belongs to you.
- Look at your git remotes. Rename your origin remote (nnja’s copy) to upstream. Add your personal fork as the origin remote.
 
1  | git remote -v  | 
Danger Zone
Local & Remote Destructive Operations
LOCAL DESTRUCTIVE OPERATIONS
git checkout -- <file>- If the file is present in the staging area, it’ll be overwritten.
 
git reset --hard- Will overwrite changes that are staged and in the working area.
 
Unless changes are stashed, there’s no way of getting them back!
Tip: use
git stash --include-untrackedto include working area changes in your stash
REMOTE DESTRUCTIVE OPERATIONS - REWRITING HISTORY
- There are many operations that can rewrite history:
- rebase
 - amend
 - reset
 
 - If your code is hosted or shared:
- Never run 
git push -f 
 - Never run 
 
Recover Lost Work
- Use ORIG_HEAD:
- The commit HEAD was pointing to before a:
- reset
 - merge
 
 
 - The commit HEAD was pointing to before a:
 - Check for repository copies:
- github
 - coworker
 
 
ORIG_HEAD TO UNDO A MERGE
- use ORIG_HEAD to undo merges
 git reset --merge ORIG_HEAD- use 
--mergeflag to preserve any uncommitted changes 
USING GIT REFLOG AND ‘@‘ SYNTAX
- By default, git keeps commits around for about 2 weeks.
 - If you need to go back in time, and find a commit that’s no longer referenced, you can look in the reflog.
 - The syntax of reflog is different.
HEAD@{2}means “the value of HEAD 2 moves ago”
 
1  | ❯ git reflog  | 
GitHub
GitHub Shortcuts
- Press ‘?’ on any github.com page for a list of shortcuts
 - Then, hit ‘Show all’
 
Continuous Intergration
- Merging smaller commits frequently, instead of waiting until a project is “done” and doing one big merge.
 - This means that features can be released quicker!
 - CI only works well when there are tests that ensure that new commits didn’t “break the build”
 - It’s even possible to perform a deployment at the end of a CI build!