forked from nnja/advanced-git
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e9806af
Showing
13 changed files
with
2,049 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
## Advanced Git | ||
|
||
### Resources | ||
|
||
All of the resources you need for class are located in this repository. | ||
|
||
**Slides:** The PDF of the slides is in the `presentation` folder. | ||
|
||
**Exercises** are in the `exercises` folder. The exercises will instruct you to clone an additional repository that is set up for completing the included exercises. | ||
|
||
|
||
### Description | ||
|
||
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… | ||
- 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… | ||
- 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… | ||
- Discover lesser-known features of git that will save you hours of time when resolving merge conflicts and track down bugs… | ||
- Learn how to harness the power of the GitHub API to fetch information about your repositories. | ||
|
||
### Author and Class Information | ||
|
||
Nina Zakharenko | ||
[@nnja](https://twitter.com/nnja) | ||
|
||
Front End Masters | ||
[Video screencast](http://frontendmasters.com/workshops/git-indepth/) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# Advanced Git | ||
## Exercise One - Under The Hood of a Simple Commit | ||
|
||
### Overview | ||
In this exercise, we'll create a simple commit, and then peek under the hood at the objects stored in our `.git` folder to gain some insight into how things work. | ||
|
||
### Prerequisite | ||
If you have a Mac with `brew` set up, install `tree`. This makes it easy to visualize the contents of your `.git` folder. | ||
|
||
### Exercise | ||
1. Create a new folder and initialize it as a git repo | ||
2. Create a file, stage it, and commit it to your new repo | ||
3. Look at your `.git` folder, using `tree` if you have it | ||
4. 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. | ||
5. Look at your `.git/HEAD` and `.git/refs/heads/master` files and see if you can figure out where these references are pointing to. | ||
|
||
## Solutions | ||
|
||
### Step 1 - Initialize the Repo | ||
Create a new sample project folder. Run `git status` to see that it is not yet a git repository. Use `git init` to initialize it as a repository. | ||
|
||
``` | ||
$> mkdir -p ~/projects/sample | ||
$> cd ~/projects/sample | ||
$> git status | ||
fatal: Not a git repository (or any of the parent directories): .git | ||
$> git init | ||
Initialized empty Git repository in /Users/nnja/projects/sample/.git/ | ||
``` | ||
|
||
### Step 2 - First Commit | ||
Create a new document, stage it for a commit, then commit it to your repository. | ||
|
||
``` | ||
$> echo 'Hello World!' > hello.txt | ||
$> git add hello.txt | ||
$> git commit -m "Initial commit" | ||
[master (root-commit) aceb9e8] Initial commit | ||
1 file changed, 1 insertion(+) | ||
create mode 100644 hello.txt | ||
``` | ||
|
||
### Step 3 - View the .git Folder | ||
Using `tree`, look in your `.git/objects` folder, you should now see three objects, represented by long SHA1 hashes. These represent the tree, blob, and commit that we created in the last step. | ||
|
||
``` | ||
$> tree .git | ||
.git | ||
├── COMMIT_EDITMSG | ||
├── HEAD | ||
├── config | ||
├── description | ||
├── index | ||
├── info | ||
│ └── exclude | ||
├── logs | ||
│ ├── HEAD | ||
│ └── refs | ||
│ └── heads | ||
│ └── master | ||
├── objects | ||
│ ├── 43 | ||
│ │ └── 388fee19744e8893467331d7853a6475a227b8 | ||
│ ├── 58 | ||
│ │ └── 1caa0fe56cf01dc028cc0b089d364993e046b6 | ||
│ ├── 98 | ||
│ │ └── 0a0d5f19a64b4b30a87d4206aade58726b60e3 | ||
│ ├── info | ||
│ └── pack | ||
└── refs | ||
├── heads | ||
│ └── master | ||
└── tags | ||
``` | ||
|
||
### Step 4 - Inspect the Objects: | ||
Note: The SHA1 hash for your commit will be different than the one displayed here. The SHA1 hash for your `blob` and `tree` will be the same as mine, as long as the content is the same. | ||
|
||
One of the objects should be a tree object. The tree contains the filename `hello.txt` and a pointer to the blob. | ||
|
||
``` | ||
$> git cat-file -t 581caa | ||
tree | ||
$> git cat-file -p 581caa | ||
100644 blob 980a0d5f19a64b4b30a87d4206aade58726b60e3 hello.txt | ||
``` | ||
|
||
The blob object, pointed to by the tree, contains the contents of the file `hello.txt` | ||
|
||
``` | ||
$> git cat-file -t 980a0d5 | ||
blob | ||
$> git cat-file -p 980a0d5 | ||
Hello World! | ||
``` | ||
|
||
The commit object contains a pointer to the tree, along with metadata for the commit, such as the author and commit message. | ||
|
||
``` | ||
$> git cat-file -t 43388f | ||
commit | ||
$> git cat-file -p 43388f | ||
tree 581caa0fe56cf01dc028cc0b089d364993e046b6 | ||
author Nina Zakharenko <[email protected]> 1507168309 -0700 | ||
committer Nina Zakharenko <[email protected]> 1507168309 -0700 | ||
Initial commit | ||
``` | ||
|
||
Because this is our very first commit, it doesn't have a parent. The next commit we make will point to our initial commit as the parent. | ||
|
||
### Step 5 - Look at refs | ||
|
||
Let's look under the hood at our `HEAD` variable. `HEAD` is just git's pointer to "where you are now," usually referring to the current branch. More on this later. We can see that right now, it points to our current branch - `master` | ||
|
||
Now, if we look at our `master` reference, we can see that it points to the latest commit. | ||
|
||
``` | ||
$> cat .git/HEAD | ||
ref: refs/heads/master | ||
$> cat .git/refs/heads/master | ||
43388fee19744e8893467331d7853a6475a227b8 | ||
``` | ||
`43388f...` is the hash of the commit we saw in the last step. You can confirm this by running `git log` | ||
|
||
``` | ||
$> git log --oneline | ||
43388f Initial commit | ||
``` | ||
|
||
Git stores references in the `.git/refs/heads/` directory, and the `HEAD` pointer in `.git/HEAD` | ||
|
||
We can verify this by creating a new branch. | ||
|
||
``` | ||
$> git branch new_branch | ||
``` | ||
|
||
The `git branch` command will create a new branch without switching to it. | ||
|
||
Now, if we look in `.git/refs`, we'll see two branches. The `master` branch, which is created by default, and `new_branch`. | ||
|
||
``` | ||
$> tree .git/refs | ||
.git/refs | ||
├── heads | ||
│ ├── master | ||
│ └── new_branch | ||
└── tags | ||
``` | ||
|
||
#### End of Exercise One |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Advanced Git | ||
## Exercise Ten - Hooks | ||
|
||
### Overview | ||
In this exercise, we'll set up a pre-commit hook and see how this powerful tool might be used to keep low-quality code from getting into your repo. | ||
|
||
### Prerequisite | ||
You should have the [`advanced-git-exercises`](https://github.com/nnja/advanced-git-exercises) repository cloned locally. Checkout the `exercise10` branch to begin: | ||
|
||
``` | ||
$> git checkout exercise10 | ||
Switched to branch 'exercise10' | ||
``` | ||
|
||
Note: This pre-commit hook script will only work in a Bash environment. Windows users can follow along but the script my not work as expected. | ||
|
||
### Exercise | ||
1. Copy the `pre-commit` script into your git hooks folder and make it executable. Try committing a shell (.sh) script to your repo with no shebang (#!) line at the top - your commit should fail. Try committing a script with a shebang line - your commit should succeed. | ||
|
||
## Solution | ||
|
||
### Step 1 - Set up a Pre-Commit Hook | ||
Git has the ability to call arbitrary scripts at different points in time, such as pre-commit, post-merge, and pose-checkout, among others. | ||
|
||
In our `exercise10` branch we should have a little bash script called `pre-commit`. This script will run before a commit - it will call git to get the names of any .sh script that's staged to be committed, then check the first two characters to see if they match `#!` (called a shebang line in bash). If this line doesn't exist, it will throw an error and not allow the change to be committed. | ||
|
||
Move this script into your git hooks folder, make sure it's executable, then make a new shell script - without a #! line - and try to commit it: | ||
|
||
``` | ||
$> cp pre-commit .git/hooks/pre-commit | ||
$> chmod +x .git/hooks/pre-commit | ||
$> echo "Bad bash script" > test_script.sh | ||
$> git add test_script.sh | ||
$> git commit -m "Adding a new test script" | ||
No shebang found! Not allowed to commit! | ||
``` | ||
|
||
Oh no! Let's fix our test script so that it has a valid #! line and try committing it again: | ||
|
||
``` | ||
$> echo '#!/bin/bash\n Good bash script' > test_script.sh | ||
$> git add test_script.sh | ||
$> git commit -m "Adding a new test script" | ||
[exercise10 6b346ab] Adding a new test script | ||
1 file changed, 1 insertion(+) | ||
create mode 100644 test_script.sh | ||
``` | ||
Success! This was a very simple example, but it's easy to see how this can be extended to do proper linting or checking of code - or even run unit tests - before commit, to decrease the chances of bad code being checked-in. | ||
|
||
#### End of Exercise Ten |
Oops, something went wrong.