In order to bolster up my ol’ skill-set, I decided to check out my old online free class stomping grounds: Udacity. I decided with all the home projects I had been doing, I should probably supplement with some formal learning.
The first class I’m starting with is a free 10 hour course on Git. This is important since I’ve been using Github and honestly have had little to no idea what I’ve been doing, other than knowing it is a way to retrieve source code from other people’s projects.
After some introductory content in Lesson 1, we got to the important part: how to install Git. Since I’m on a Windows environment (sorry Linux, this isn’t goodbye, it’s just see you later), I went with the following set up instructions:
- Went to https://git-scm.com/downloads
- Download the software for Windows
- Installed Git choosing all of the default options
- Configured Git with custom Udacity provided files (see video below)
- Performed first-time Git setup (command line code below)
- Downloaded code editor Atom https://atom.io/ (developed by GitHub)
- Associated Git with Atom (command line code below)
# sets up Git with your name git config --global user.name "<Your-Full-Name>" # 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 git config --list #associate git with Atom git config --global core.editor "atom --wait"
And with that, we’ve finish Lesson 1! 🙂
Lesson 2 was focused on how to create, clone, and check the status of a repo. The commands focused on were: git init, git clone, and git status. Besides the git commands, the following shell commands will also be used:
- ls – used to list files and directories
- mkdir – used to create a new directory
- cd – used to change directories
- rm – used to remove files and directories
- pwd – print the name of the working directory (stands for “print working directory”
First task was to create a directory for the course called udacity-git-course, create a directory inside the course for this specific project called new-git-project, and finally move into the new-git-project directory using the cd command. After that, we ran the “git init” command to initialize a new repository (aka repo).
However, BEFORE running the commands to perform the above, I used “cd” to move to my Desktop where I’ll be storing my project. Also, I’m lazy and love to copy and paste shell commands, and in git bash terminal the paste shortcut is Shift+Insert.
cd Desktop/ mkdir -p udacity-git-course/new-git-project && cd $_ git init
After successfully creating a repo, there is a new file called the .git directory. This is where files and directories are stored that Git uses to record commits and keeps track everything. Editing, deleting, or renaming any of the files in this directory will likely cause loss of work. It’s okay to look, but not touch.
Before continuing to the next part of the lesson to clone a repo, the course went into more detail about what is contained in a Git directory.
- config file – where all project specific configuration settings are stored
- description file – this file is only used by the GitWeb program, so we can ignore it
- hooks directory – this is where we could place client-side or server-side scripts that we can use to hook into Git’s different lifecycle events (the only part of a repo that is okay to mess with)
- info directory – contains the global excludes file
- objects directory – this directory will store all of the commits we make
- refs directory – this directory holds pointers to commits (basically the “branches” and “tags”)
- Additional information: Git Internals – Plumbing and Porcelain, Customizing Git – Git Hooks, Initializing a Repository in an Existing Directory, git init docs, git init Tutorial
Next part of the lesson we cloned a git, and I am borrowing this screenshot to remind me how a person manually sets up a web project repo!
So now that we know why we would want to clone a repository, the next step is to actually clone one! In several projects prior to this, I have cloned repositories either in command line or via GitHub Desktop, but this is definitely filling in the gaps in my knowledge about what exactly I was doing.
#check current working directory pwd #backing out of my current working directory into the udacity-course-git with the cd .. command cd .. #clone repo and rename it blog-project git clone https://github.com/udacity/course-git-blog-project blog-project
Now that we’ve cloned the sample web blog udacity repository, we can look at the HTML page it creates by opening the “index.html” file in Mozilla (or Chrome or whatever your favorite browser is).
For more learning, Udacity offered the following resources (in case you ever want some great reading material on a rainy weekend night with a glass of wine in hand): Cloning an Existing Repository, git clone docs, git clone Tutorial
The last part of Lesson 2 focused on the command “git status” to determine the state of the repository. Apparently this command is *SO IMPORTANT* that they recommend you run it after using any other command! Now only will this help new users like me better understand how Git works, but it’ll also prevent making incorrect assumptions about the state of the files/repos in play.
To interpret the output:
- On branch master – this tells us that Git is on the master branch (default)
- Your branch is up-to-date with ‘origin/master’. – Because git clone was used to copy this repository from another computer, this is telling us if our project is in sync with the one we copied from
- nothing to commit, working tree clean – this is saying that there are no pending changes.
- Additional resources: Checking the Status of Your Files, git status docs, git status Tutorial
And with that we move on to Lesson 3: Reviewing a Repo’s History.
The two main commands in focus this time are: git log (show history of all commits) and git show (displays information about given commit by providing commit’s SHA).
#navigate to project working directory cd Desktop/udacity-git-course/course-git-blog-project #show commit log git log
By default the log shows the SHA, author, date, and the message of a commit. To navigate the log, use the command line pager Less commands as follows:
- to scroll down, press:
- j or ↓ to move down one line at a time
- d to move by half the page screen
- f or Page Down or space bar to move by a whole page screen
- to scroll up, press:
- k or ↑ to move up one line at a time
- u to move by half the page screen
- b or the Page Up button to move by a whole page screen
- press q to quit out of the log (returns to the regular command prompt)
In order to condense the git log into one line, we were introduced to the –oneline flag to add to the command. This command shows only the first 7 characters of the SHA, along with the message, and removes the date and author information. In order to add the file names and number/type of changes use the –stat flag. To display the actual changes made to a file, use the -p (–patch) flag.
git log --oneline git log --stat git log --patch
Patch output explanation:
- Diff shows the difference between the original version and the new version, and the names can be different if the name of the file is changed
- The next line shows the original and new SHA along with removed and added files
- The portion with the @@ symbol shows where the line changed started in the original file, along with the number of lines changed
- The lines with the green + signs is the details of lines added
- The lines with the red – sign is the details of lines removed
- Additional information: Generating patches with -p
In the final part of Lesson 3 we covered the “git show” command, which just lets you output detail about a specific SHA. It can also be combined with the other flags previously covered.
git show --stat SHANUM
In Lesson 4 we focused on three commands: git add (adds to staging), git commit (adds staging code to master), git diff (shows the difference between two files).
git status git add index.html
To add the other files, instead of writing “git add css/app.css js/app.js” we will condense it to just a “.”. The period refers to the current directory and can be used as a shortcut to refer to all files and directories (including all nested files and directories).
git add .
Finally we are ready for a commit! After running the “git commit” line, my code editor “Atom” popped up. I typed in the first line the text describing the commit, and then saved and closed. This completed the “git commit” action and has made me increase my nerd coolness by one level!
And now they gave a neato tip, next time I can bypass the editor popping up by using the -m flag!!! The drawback though is you can’t review the code that is about to be committed or edit the descriptions / commented out sections.
git commit -m "Initial commit"
The next part of Lesson 4 broke down a few good ground rules for commits. My take aways are:
- Don’t do multiple unrelated changes in a single commit (grouping together similar functionality is fine within reason)
- Keep the message short (under 60 characters) and explain what the commit is (not the how or why)
- The best way that I’ve found to come up with a commit message is to finish this phrase, “This commit will…”. However, you finish that phrase, use that as your commit message.
- If you need to explain the “why” in more detail, let the commit open in the code editor and include a blank line of space under the main line of the commit message. Then you can add a description that will elaborate (this way it does not show up when using the –oneline flag)
- Udacity has its own Commit Messaging Style Guidelines to review and borrow from in case collaborations don’t have their own
Next we edited part of the index.html file in order to see the command “git diff” in action. It looks identical to git log -p, only it shows the changes in the files between the working file and the committed file only.
To ignore a file in the directory that you never want to add to staging or commit, we created a document called “.gitignore” and stored it in the “.git” hidden file directory. NOTE: I had major issues getting git to know that I made a file using ATOM. So I downloaded Notepad++ and made sure I the encoding was “UTF-8”. I then discovered the issue was the placement of my .gitignore file–DO NOT PUT IT IN THE “.git” DIRECTORY but instead the same directory as the main part of the project!
Once I moved the file to the correct location, it worked so I committed the change of adding the file. Now all you need to do is add the names of the files into that document and they will no longer be included in “git add” statements. Nifty!
.gitignore can also use wildcards so you can exclude multiple files at one time through a processing called globbing. Some globbing rules are:
- blank lines can be used for spacing
- case sensitive
- # marks line as a comment
- * matches 0 or more characters
- ? matches 1 character
- [abc] – matches a, b, or c
- ** – matches nested directories – a/**/z matches
And now we’re ready for Lesson 5 on branching and merging!! HUZZAH!
In this lesson we will be covering: git tag (add tags to specific commits), git branch (design functions in parallel), git checkout (switch between different branches and tags), and git merge (combines changes from multiple branches).
First up is tagging! This will allow us to specify things like version numbers to the specific commits, for example. To launch tagging, we entered the following command and our code editor popped up for us to interact where we typed “Ready for content” and then saved & closed. Note that the “-a” flag is used to automatically capture the person who made the tag, the date the tag was made, and a message for the tag itself.
git tag -a v1.0
Now the tag will show up in the “git log” after the SHA. To delete a tag, run the command:
#replace v1.0 with the tag's name to delete git tag -d v1.0 git tag --delete v1.0
Tagging will by default only affect the most current commit, in order to tag a past commit just add the SHA at the end of the line:
git tag -a v1.0 a87984
Next on the lesson we reviewed the “checkout” function in order to switch the “head” between the “master” and the other branches. We are also using the “git branch” command to list the branch names in the repo, add a branch, and delete a branch.
#list out branches git branch #add a branch named sidebar git branch sidebar #switch to new branch git checkout sidebar
When we switch to the new branch, here is what is happening:
- remove all files and directories from the Working Directory that Git is tracking
- (files that Git tracks are stored in the repository, so nothing is lost)
- go into the repository and pull out all of the files and directories of the commit that the branch points to
Adding a SHA at the end of the “git branch branchname” command will not only make a new branch, but it will point to that specific SHA. This is useful if there is an error in an earlier commit that needs to be fixed, so a new branch to fix that is made to explore fixing that functionality.
After a branch is merged back into its master, you can delete the branch. To do this, we use the -d flag. HOWEVER, you cannot have the head currently pointing to the branch about to delete, so we will need to switch back to the master first. Git will also not let you delete a branch that has commits made to it that have not yet been merged with another branch. If you still want to delete the branch regardless of commits you use a capital “-D” flag to override that functionality.
#switch back to master branch git checkout master #delete sidebar branch git branch -d sidebar #delete sidebar branch with open commits git branch -D sidebar
We continued on in the class and added a background color to the css.app file, and then make a sidebar branch that pointed to the SHA made PRIOR to the commit adding the css.app background color. When I opened up the css.app file in Notepad++ after switching to the new branch THERE WAS NOTHING IN THE FILE!!! SO. EFFING. COOL!!!
#added css changes & committed git add . git commit -m "Set background color for page." #added sidebar branch to point to commit PRIOR to change git log --oneline git branch sidebar 34a2243 git branch sidebar #opened css.app and WAS FREAKIN' AMAZED
This next section I kind of messed up, we added a footer with social links but I forgot to add it to a separate branch and I already committed the change. So I quickly Googled how to remove the latest commit so I could redo the work easily and match the Udacity course.
#remove the latest commit git reset --hard HEAD #removes the last X commits (2 in example) git reset --hard HEAD~2 #according to Udacity, use a ^ at the end for removing "Relative Commit Reference" (will learn about in lesson 6) git reset --hard HEAD^
While making this new branch, we also learned you can create a new branch WHILE checking it out. Yay timesavers!
#added new footer branch while checking it out and starting it in the same location as the master branch git checkout -b footer master
Now that we have commits on three separate branches, we learned the command to view all of them together.
#view all commits on all branches with bullets to show branches git log --oneline --graph --all
Now we are going to merge in the footer changes to the master branch. Because the footer has additional commits that the master branch does not, this is going to be considered a “fast forward merge’. This means instead of a new commit being made, it just moves the current branch forward to the same commit as the branch it is merging in.
#move to master branch, check status, merge in footer git checkout master git status git merge footer #check log to see the master and footer branches now point to same commit git log --oneline --graph --all
In order to merge divergent commit branches, run the same command only it will make a new commit. It is common practice to use the default message that is suggested with this commit by simply saving & closing the editor to complete the merge and commit the change.
git merge sidebar #click save and close when code editor pops up
Sometimes merges fail, and this is called a merge conflict. A merge conflict occurs when a change to a line has happened in both places needing to merge. This means the programmer (me) will need to fix this before being able to complete the merge.
To force a merge conflict we were asked to do the following:
- change the heading on the
- create a
heading-updatebranch that’s located on the commit right before the recently modified
- change the same heading
- switch back to the
- merge in the
#made sure master branch was selected git checkout master #edited Index heading git add . git commit -m "Changed heading" #created new branch pointing to master branch commit prior to the heading change git log --oneline #identify SHA to point to git checkout -b heading-update SHA #changed same heading in Index file git add . git commit -m "Changed heading" #switch back to master and try to merge git checkout master git merge master heading-update
Now that we got the merge error, opening up the Index file will actually show the conflict!!!
<<<<<<< HEADeverything below this line (until the next indicator) shows you what’s on the current branch
||||||| merged common ancestorseverything below this line (until the next indicator) shows you what the original lines were
=======is the end of the original lines, everything that follows (until the next indicator) is what’s on the branch that’s being merged in
>>>>>>> heading-updateis the ending indicator of what’s on the branch that’s being merged in (in this case, the
To resolve, we simply fix the code to reflect what we actually want it to be:
#stage the changes, made the commit git add . git commit #save and close to accept code editor's default comment
And with that, we are done with Lesson 5!!!!
Moving on to the final Lesson, we learn how to modify the most recent commit (git commit –ammend), revert a commit by undoing its changes (git revert SHA), and reset commits by completely deleting them in order they were applied (git reset).
First up is the git ammend, this will allow us to edit the description of a commit, but it will also let us make new changes and group them under the same commit. This way back-to-back commits that do the same thing won’t be cumbersome. To do this:
- edit the file(s) to make the new changes
- save the file(s)
- stage the file(s)
- and run
git commit --amend(this will add to the current commit instead of making a new one!)
To revert a commit in general, we can run the command “
$ git revert <SHA-of-commit-to-revert>“. This will undo the changes made by the commit, and also add a new commit to record the change.
Lastly there is the reset command, which seems similar to the revert command only it erases the commit. Instead of just undoing it and making a new command, this will literally erase the entire commit and any record of the change along with the change itself. However, Git will keep track of this deletion for 30 days that you can salvage from by using the “git reflog” command.
In order to reference commits, sometimes they need to be referenced relative to another commit. To do this, there are special characters called “Ancestry Referencs” to be used:
^– indicates the parent commit
~– indicates the first parent commit
For example, the commit previous to the current one could be referred to by: Head^, Head~, or Head~1. To refer to the grandparent (or two prior) use Head^^, Head~2. To refer to the great-grandparent (three previous) we can use Head^^^ or Head~3.
The difference between ^ and ~ is when a merge is involved. A “^2” will refer to the second parent of the merged commit, whereas a “~2” or “^” will refer to the previous commit’s first parent. Using “git log –oneline –graph” will help show the path of the parent vs second parent branches to easily identify where the relative reference of a commit will be chosen.
There are 3 different flags though that can be used when utilizing the “git reset” command. These will change it so the commit isn’t necessarily sent to the trash, it can instead be moved back to staging or the working directory!
- “git reset –mixed Head~1″ will move most recent changes back to working directory, you can then re-commit then and generate a new SHA
- “git rest —soft Head~1″ will move the changes from the SHA into the staging area. If you run the commit at that point, the SHA will still be different due to the new timestamp
- “git reset —hard Head~1″ will move the changes to the Trash
Prior to using the rest command, it’s good practice to create a backup branch to revert the changes if neccessary.
git branch backup
Now if we use the command to remove the changes from a recent commit where the Index file was modified, we can use another command to remove the changes from the working directory and then merge in the backup branch to fast-forward merge.
#reset commit and move changes to working directory git reset --mixed Head~1 #remove changes from working directory git checkout -- index.html #fast-forward merge backup changes to restore original state git merge backup
And with this I have COMPLETED THE COURSE!!! Next up I was thinking of either doing the Shell Workshop just to get a little context on all the command line I have used for the past several years. These little courses are great to fill in the gaps from the years of being a hobbyist!