Git – Rebasing to a specific commit

I was working on homework that challenged us to create tests to build a rails app from the ground up. We had to learn how to create new database entries, save them, and edit them. I finished the homework on a master branch and decided I wanted to do it again for practice. So I created a topic branch off of an early commit (e3f8704) to do the work from scratch.

$ git checkout -b homework e3f8704

Later I realized I made a mistake and needed to use interactive rebase to fix a commit message on the topic branch. To do so, I just passed in the commit I used to branch as an option. This tells Git that you want to rebase from that commit.

$ git checkout homework
$ git rebase -i e3f8704

Resource: https://git-scm.com/docs/git-rebase

Cleaner Git logs and Git aliases

If you spend any time during your day reading Git logs, you probably hate having to page through the log to see a specific commit. Here’s a couple of nice git log options to help you quickly glance at your commit history.

--abbrev-commit abbreviates the commit SHA to just 6 or 7 unique characters.
--pretty=oneline prints only one line of your commit message. This is especially useful if you follow the convention of writing descriptive subject lines for your commits. This lets you page through many lines of commits and know exactly how your project progressed. Here is a nice guide for writing good commit messages.


Git aliases

If you find yourself using these two git log options frequently, you might want to consider aliasing them. A Git alias allows you to create a ‘shortcut’ command. The code below creates a permanent global change to my Git configuration. So that I can write git cleanlog instead of git log --abbrev-commit --pretty=oneline.

git config --global alias.cleanlog 'log --abbrev-commit --pretty=oneline'

Another Git command that I aliased was the reset command to remove files from the index. To me, writing git unstage seemed to be a sensical command to type when I want to unstage files.

git config --global alias.unstage 'reset HEAD -- '

If you feel like aliasing is the way to go, start thinking about the Git commands you use on a daily basis and start creating your own aliases. You might want to start simple, like alias.co checkout and then add more options as you find yourself using more complex flow control commands.

EDIT: Mar 10, 2016

I find myself using a few more really simple, but useful Git aliases nowadays.

git config --global alias.commit 'commit -v'
git config --global alias.s 'status -s'

Git – Merge vs. Rebase

Version control systems are an essential tool in software development and branches make it easier to manage code and organize projects. So being able to keep track of feature branches goes a long way in moving projects along efficiently.  I’ll outline what I’ve learned to be good practices for managing code on your local repository as well as your remote(s). And then I’ll cover the basics of merging vs. rebasing and how both methods can be used to re-integrate feature branches back into master.


Managing Branches

Rule #1 – Preserve the master branch

Your master branch should contain all of latest and greatest code that is worthy of your final product. Ideally, all of the work you do should be completed in feature branches and then merged back into master when it’s been tested and approved. If you’re having conflicts when you pull or push on your master branch, something may have gone terribly wrong and it’s definitely worth taking the time to figure out what happened and fixing the problem.

Rule #2 – Be clear

Visualize a desktop screen on a computer that is littered with over 100 files. You decide you want to organize them so you group them into directories, each with a unique name. But you get careless and name one directory ‘important’, another ‘essential’, and yet another ‘files to keep’. What’s the difference between these directories? Can you tell me their contents by just glancing at them?

Branches are ways to work on groups of files that are all related to one topic. If you’re creating a way for people to purchase things on your website, maybe you’ll call the branch ‘purchase’. Or maybe you can be even more specific and have a ‘shopping_cart’ branch as well as a ‘credit_card_authentication’ branch. The point is that being specific is important to maintaining your sanity while working on multiple projects at once. Name your branch something so specific that you can identify it’s purpose and contents with a quick glance.

Rule #3 – Be consistent

This rule goes hand in hand with being clear about your work. In short, try to follow conventions for naming branches locally as well as remotely so that you don’t confuse yourself. Specifically, any major remote project repository should be called upstream and your own forked copy on GitHub should be called origin. In addition, if you have a project directory called ‘shopping_cart’, your local and remote branches should also be called ‘shopping_cart.’

Rule #4  – Commit often and commit well

If you’re working on a feature branch, you could theoretically have one commit for that branch. Just save your work as you go and then make one commit when you’re done coding. WRONG! Commits keep track of the work you’ve done and create a history that reflects the actual changes you made to a file. Good commit messages are important because they summarize what changes you made and, more important, why you made them. Do you press the save key incessantly while writing word documents? Commits are like the save key…it’s hard to overuse them.


How to integrate into master

There are two main methods used for integrating code into the master branch and the first is git merge. Anytime you need to bring code into a branch (even if it’s not master), you need to use the merge command to take the commits from one branch and merge them into your target branch. You can add complexity and power to merging code back into the master branch comes from another re-integration method called git rebase. I’ll go into detail about rebasing in a bit, but basically it’s away of updating a feature branch so that it accurately reflects the most recent changes made on master. It’s sort of like updating your phone – your phone’s contents are still unique to you, but it’s running on the most recent software updates.

As with many things in life, people are often split on whether using merge vs. rebase is the best way to re-integrate code into the master branch. It ultimately boils down to personal preference as both methods are legitimate ways of managing branches and merging into master. I’ll go over the details of what each method does and then you can decided which you prefer.


Merge

Merging is a fairly simple process by which you can integrate code from a topic branch into the master branch. Let’s imagine that you branch off of master to do some work on a small code fix. You make just two commits and are ready to bring those changes into master. In the meantime, someone else made another commit that got integrated into the master branch. This isn’t necessarily a problem because Git will figure out how to merge the two branches together in the best way possible.

Essentially, Git takes a look at both branches and finds the commit that’s a common ancestor to both branches. In the image below, that’s the first commit represented by a blue circle. It then compares all the commits made on master and on the topic branch, decides if they can be combined without conflicts, and then creates a new merge commit.

Merge commit

This last step is important. Anytime that you merge two branches, Git creates a special commit called a merge commit. Unlike all other commits, which have one ‘parent’, merge commits have two parent. It points at the two branches that it merged together so that you can trace back into the two branches that resulted in the merge.

Sometimes, you might find that you modified the same file in two branches. If there are any conflicts because that file exists as two different versions, you will have to resolve them manually. The built in mergetool is a good tool for those who are just starting to find merge conflicts that they need to resolve. Basically, you will have to choose which version of the file you want to keep, line by line.

For example, let’s say you have a file called ‘foo.txt’ in both branches. In the master branch, line 1 says ‘hello’ and in your feature branch, it says ‘hi’. This is a conflict that Git cannot resolve so you have to use mergetool and decide, do I want line 1 to say ‘hello’, ‘hi’, or both?! If you choose both lines, line 1 will stay as ‘hello’ and your line, ‘hi’ will get input as line 2. The important thing to remember is that you probably DON’T ever want to replace the version on master with the version on your feature branch. If it exists on the master branch, it’s probably not code that you want to be changing.


Rebase

Rebasing is a powerful Git tool that can modify the history of commits made on a branch. Now, you might be thinking that Git is supposed to preserve history, that the whole point of using this amazing VCS was so that you could remember exactly all of the changes that were made at some point in time. Well you’re right. Git won’t ERASE any history and it won’t change the contents of any commit. What we’re talking about is rebasing (updating) your topic branch to reflect the most recent changes in master.

Rebase 1

If you make a topic branch and do some work, you could merge those changes back into master with a merge commit. But maybe you want to make sure that your changes don’t conflict with any commits on master BEFORE you merge. You know…because your colleagues might appreciate it if you fix all merge conflicts before they try to merge your code into the master branch? At this point, you would run rebase on the topic branch and it changes its history. Look at the image below. Notice that it rebases the topic branch so that its ‘base’ is built off the last commit on master.

Rebase 2

This is extremely useful because it let’s you see how your changes in the topic branch stack up to the changes made on master. Think about this for a second. Remember that when you merge a branch onto master, Git will notify you if you have any merge conflicts. Rebase will do the same exact thing, but right when you rebase it. So basically, merge and rebase will both help you merge commits onto the master branch, but the difference lies in when you get notified of merge conflicts.

Merge warns you of conflicts while you are trying to merge. Rebase makes you address those conflicts right when you rebase so you can clean them up BEFORE you merge.

Once you try to merge those topic branch commits, your master branch will end up looking like a straight line as if the topic branch commits were just pasted in front of the master commits. This is because of the way Git interprets your branch architecture. If your topic branch just has two different commits compared to your master branch, all Git does is add those to master.

Rebase 3

This is different from a normal merge where Git notices that there are commits that are not shared between your master branch and your topic branch so it creates that special merge commit. In a rebase, you will eventually have to use git merge and create a merge commit. However, the history of your commits will look cleaner as rebasing simply builds your branch commits on the most recent master commits.


An important note about rebasing

Rebasing is extremely useful when you’re managing a large project with a lot of topic branches. It allows developers to compare their code to the recent changes being merged into the master branch so that they can check that their code won’t cause merge conflicts. But there’s a situation when you should NEVER rebase.

If you rebase your topic branch, it will change all of the SHA keys for the commits on that branch. Git does this automatically because you’re effectively telling Git to change the base of your branch from an old commit to the most recent commit on master. Since the ‘history’ of the branch is being changes, the commit SHAs do as well.

So if you ever push your commits onto a public repository, one that other developers are actively pulling from, you should NEVER rebase that branch. Think about it. If your friend pulls all of your commits from a branch and then you rebase that branch, you’ve just changed ALL of the commit SHA keys for that branch. And then next time they pull from that public repository, Git will tell them that they have some serious problems because the commits on the public repository don’t match the commits on their local one…uh oh. Hopefully, you guys catch the problem and can remedy it, but wouldn’t you just like to avoid the problem altogether?


If you want to read more about Git, checkout the Git documentation online. It’s an AMAZING resource, the inspiration for some of my images in this article, and just plain fun reading…if you’re a Git nerd.

Git – Amending multiple commit messages

Home_Alone_Boy1

There may come a time when you’ve really botched your commit messages and you need to amend a few of them all at once. You could amend all of them one at a time and then push them to a remote. Or you could just amend them in a large batch and save yourself some time and probably a bit of anxiety.

Remember, by amending commit messages, the metadata of the commits change so it will have a new SHA key – even if you didn’t change any code at all. Obviously, this will create conflicts with your remote, which has all of the old commit SHA keys. So once you’re done with your amendments, be sure to force push your changes to remote.


 Checking for commit errors

In class, we’re using Pivotal Tracker (PT) to keep track of ‘stories,’ or tasks, that required to complete for homework. It’s just one of many project management tools out there based on the Agile Way. In addition, we’re using a PT service on GitHub that requires us to add our PT story ID onto each commit message we write on a topic branch. Well guess what? Yours truly totally forgot about this requirement.

To check how badly I messed up, I went back to the branch I needed to amend, which happened to be one called 104389600_chapter_1_master, where 104389600 is the PT ID, chapter_1 is the topic branch name, and master is the branch I branched off of. Then, I ran git log to see how many amendments I needed to make.

$ git branch
  104389594_introduction_master
* 104389600_chapter_1_master
  104391102_chapter_0_master
  master
$ git log
commit d9f5b78f5e4701f0d5052827ea5ec8badc01a3cf
Author: Tim <timsjpark@gmail.com>
Date: Tue Sep 29 23:40:47 2015 -0600

 Add ex1.rb to run chapter exercises

commit d8ece159bc942fde9bf0b538c72b2c2df705acd4
Author: Tim <timsjpark@gmail.com>
Date: Tue Sep 29 23:40:00 2015 -0600

 Added Readme

commit 873e4bb55164372f2acec114f4d3fdc1a4dcf895
Author: Tim <timsjpark@gmail.com>
Date: Tue Sep 29 18:39:30 2015 -0600

 Create chapter_1 directory, and Readme and ex1.rb

 [#104389600]

commit 237eda11a586239ff8b67e06e406485f4b76acfd
Author: Tim <timsjpark@gmail.com>
Date: Tue Sep 29 18:58:27 2015 -0600

 Add file to have rubocop ignore Guardfile

commit e1a26f79b86ed9d5b27edf5e930289e4afdc2f78
Author: Tim <timsjpark@gmail.com>
Date: Mon Sep 28 20:20:08 2015 -0600

 Initial comment

As you can see, going back in time, I have two commit messages that need the PT ID added to the end of the message. The one before correctly shows the ID in brackets preceded by an octothorpe (#). You’ll also notice that the oldest two commit messages don’t have an ID. That’s because those commits were made in the master branch and the PT service aids in tracking topic branches, so it wouldn’t make sense for the master branch to have any ID in the commit message.


Preparing to make amendments

Now that we’ve spotted our problems, we need to start making amendments. To prepare to amend multiple messages, we first have to fetch from origin. Fetching looks for any new changes made in a remote repository. Then we use rebase to update our local repository. Luckily, our current branch is up to date and we don’t have to deal with any other obstacles other than amending our commits.

$ git fetch origin
$ git rebase origin/master
Current branch 104389600_chapter_1_master is up to date.

Now, let’s start amending our commits. We can accomplish this by typing in:

git rebase origin/master -i

If you read the documentation for git rebase --help , you would see that the -i option allows you to “make a list of the commits which are about to be rebased. Let the user edit that list before rebasing.”


Amending multiple commits

Once you type in git rebase origin/master -i you’ll be placed into vim. There, you want to look at the top, which lists your commits in chronological order.

NOTE: This is the opposite order of the git log output.

Since I wanted to amend the last two commits I made, I’ll replace the word pick with reword. Once you’re ready to amend those commits, get back into Normal mode by hitting ESC and then typing in :wq. If you’re new to vim, look for some extra help below the image.

reword

New to vim? Navigate to the line with the first commit you want to amend. Go to the first character, which should be ‘p’ in ‘pick.’ Then type cw on your keyboard – this keystroke tells vim that you want to changeword and place you in insert mode. See how ‘pick’ is now gone? Go ahead and type in reword and then hit ESC to return to normal mode.

Have multiple commits to amend? Navigate to the next commit you need to amend and return to the first character of the line. This time, hit the . key. Magic? The ‘dot’ key will create your last keystrokes in vim, which should have been cw, typing in reword, and then hitting ESC.

Finally, type :wq to ‘write’ your edits to the file and then ‘quit’ the vim editor.


Editing your commits

Now, all I have to do is add my Pivotal Tracker ID to each commit message. If you recall from before, I name my topic branches off of the PT ID for the story (task) I’m working on. One advantage of this is that when I go to edit commit messages, I know exactly which PT ID I’m using. I then add that ID to the bottom of the message preceded by a # and confined in square brackets. Finally, I go back to Normal mode and then :wq. Do this for each commit message.

edited message

Once you make your amendments, you’ll pop out of vim and back into your terminal. Notice that your have an output saying you successfully rebased.

$ git rebase origin/master -i
[detached HEAD 4da44d3] Added Readme
 Date: Tue Sep 29 23:40:00 2015 -0600
 1 file changed, 86 insertions(+)
[detached HEAD 58e1c94] Add ex1.rb to run chapter exercises
 Date: Tue Sep 29 23:40:47 2015 -0600
 1 file changed, 9 insertions(+)
Successfully rebased and updated refs/heads/104389600_chapter_1_master.

But wait…there’s more!

One last step. When I check git status , you’ll notice that my branch and origin “have 2 and 2 different commits each.” What the hell does that mean? Well remember that rebasing and then amending your commits changed their SHA keys. Since I amended two commits, my local branch has two new commits that origin doesn’t have and origin has the two old commits that my local branch doesn’t have.

Well I want my origin to reflect the changes I made with adding the Pivotal Tracker ID, which I know are correct. So I force push my changes onto origin with the -fu option. Run git status one more time and it looks like you’re all good…

$ git status
On branch 104389600_chapter_1_master
Your branch and 'origin/104389600_chapter_1_master' have diverged,
and have 2 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working directory clean
$ git push -fu origin 104389600_chapter_1_master
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 2.36 KiB | 0 bytes/s, done.
Total 8 (delta 2), reused 0 (delta 0)
To git@github.com:timsjpark/lrthw_exercises.git
 + d9f5b78...58e1c94 104389600_chapter_1_master -> 104389600_chapter_1_master (forced update)
Branch 104389600_chapter_1_master set up to track remote branch 104389600_chapter_1_master from origin.
$ git status
On branch 104389600_chapter_1_master
Your branch is up-to-date with 'origin/104389600_chapter_1_master'.
nothing to commit, working directory clean

Thanks to Jason Noble for showing me this nice Git feature.

Git 102 – Branching out

So, you’ve just created a local Git repository to keep track of your work and you’ve even pushed your commits onto a remote on GitHub called origin. That’s neat and all, but how is this actually useful for you and your collaborators?

In my last post, I mentioned that Git is extremely powerful when multiple developers are working on the same project. Remember, when you first initialize a Git repository, the software puts you on the master branch. You can think of this as the main source code, which will most likely evolve into your final product. Most likely, you don’t want a dozen developers with differing levels of experience (noobs) to all touch that code. What to do, what to do?


Go forth and branch out

Topic branches allow multiple contributors to work on code that already exists in the master branch. In the same way that you can push code into your remote origin, you can also take code from other remotes. So, let’s say you want to help your friend build his company’s website. You can pull code from his master branch and work on it in a topic branch (a.k.a. feature branch) without tinkering with the original code. Let’s get some visuals to help us understand this concept.

git102_branching

In the figure above, lines represent a branch and circles represent commits. As you can see, topic branches allow you to make commits that are totally separate from the master branch. This means that you and your friend can work on the same website simultaneously without having your changes interfere with his work. Now, you might be thinking, eventually you have to merge your code back with the master branch, right? To that I say…

patience-young-grasshopper

First, let’s learn to manage branching using GitHub and our command line.


Forking in GitHub

Now, this next process I’m going to explain isn’t an inherent part of managing topic branches. However, it is a powerful tool for managing large projects and, more importantly, it will strengthen your understanding of Git.

timsjpark_git_practice

If you go to any repository on GitHub, there will be an option to ‘Fork.’ All this does is COPY the repository to your own account. If you click it in a repository that you own, you’ll notice that your own account is listed. But it should be greyed out, obviously because you can’t copy your own repository twice. So, go ahead and try and fork my git_practice repository to yours.

timsjpark_rails

Once GitHub is done forking, it will automatically place you into the new repository in your account. There are two very important things to note.

(1) This is just a COPY of the original repository.

(2) Forking is a process that occurs only on GitHub. So far, no changes have been made on your local computer so the git_practice repository that you just forked only exists on your GitHub account.

In order to copy the GitHub repository you just forked onto your local computer, you’ll have to clone it. Go to the right sidebar on GitHub and click the clipboard icon to copy the SSH URL. Then cd into a directory where you want git_practice to exist. Maybe like your home directory. Wherever you are, type this next:

$ git clone URL
Cloning into 'git_practice'...
...some output here...
Checking connectivity... done.
$ git push -u origin master
Branch master set up to track remote branch master from origin.
Everything up-to-date

Cloning a remote repository just makes a copy of it on your local computer. Even though the local repository you just made is an exact copy of your remote origin, we push with the -u option just to make sure our local repository is tracking origin.

To summarize, we forked a git repository from another person’s GitHub account, which made a copy of that repository onto our GitHub account. Then we cloned our copy onto our local computer. So…what’s next?


Adding a new remote – ‘upstream’

Now that you’ve cloned your origin repository onto your local computer, it’s time to start adding some complexity into your branching scheme. Go ahead and type the following code. What you’ll notice is that you’re adding a new git remote, just like you did when you connected your local computer to origin. But hey, the new remote you’re adding is called ‘upstream.’ When you type git remote -v, what you’re seeing is all of the remote repositories that you can access from your command line.

$ git remote add upstream git@github.com:timsjpark/git_practice.git
$ git remote -v
origin	git@github.com:YOUR_USERNAME/git_practice.git (fetch)
origin	git@github.com:YOUR_USERNAME/git_practice.git (push)
upstream git@github.com:timsjpark/git_practice.git (fetch)
upstream git@github.com:timsjpark/git_practice.git (push)

In this specific case, if you’re following my instructions, your ‘git_practice’ repository is called origin and MY ‘git_practice’ repository is called upstream. So what’s the purpose of having a connection to two different remote repositories? Well, it’s relevant to your workflow when you help your imaginary friend build their website. NOTE: This isn’t the only way to manage a project, but it’s a good way.

Git convention dictates that you call your personal repositories origin. Don’t ask me why, it just is. So whenever you are working with another person’s project, their remote repository (on GitHub) is referred to as upstream by your computer. This helps distinguish between the original project repository (upstream) and your forked copy of it (origin).


What about topic branches?

So far, you haven’t made any topic branches yet. Every repository – local, origin, and upstream – all only have master branches. That’s great, but there’s a problem. Remember, that you don’t want to tinker around with any code in the master branch, because that’s the golden code that will eventually become a final product. So how do you start helping your imaginary friend build his website?

Topic branches bud off of master branches and allow you to work on small snippets of code. Usually, those snippets accomplish some feature. For example, if you want your website to have a shopping cart feature, you might build a shopping cart application in a topic branch. Simultaneously, your friend might be working on a user_login application in a different branch.

To create your own branch, type git checkout -b shopping_cart_master. What this does is it lets your checkout a new branch called ‘shopping_cart_master.’ It’s best practice to name your topic branch based on the topic/feature you’re working on and the branch that you built it off of. Since we’re branching off of the master branch, ‘master’ is appended at the end of our branch name. Use git branch to check what branch you’re on and git checkout BRANCH_NAME to move to another branch.

$ git checkout -b shopping_cart_master
Switched to a new branch 'shopping_cart_master'
$ git branch
  master
* shopping_cart_master
$ git checkout master
$ git branch
* master
  shopping_cart_master

Branches =/= directories

Here is an IMPORTANT concept to understand before you move on.

BRANCHES ARE NOT DIRECTORIES!

Branches are references to commits. Branches are data structures created by Git to allow you to work on different versions of code in ONE directory. Confused? Let’s take a look at a simple example to illustrate this point. Check which branch you’re in and then switch to the shopping_cart_master branch we just made. Now follow along with the code below.

$ git branch
* master
  shopping_cart_master

## Switch to the shopping_cart_master branch
$ git checkout shopping_cart_master
$ git branch
  master
* shopping_cart_master
$ ls
README
$ echo 'Does this file exist in master branch?' > file.txt
$ git add file.txt
$ git commit -m 'Testing differences in branch structure'
$ cat file.txt
Does this file exist in the master branch?
$ ls
README  file.txt

## Now we'll switch to the master branch and check for file.txt

$ git checkout master
$ git branch
* master
  shopping_cart_master
$ ls
README

Would you look at that? Even though you NEVER changed directories, there’s a file that exists in shopping_cart_master, but NOT master. It’s not magic. What’s happening is Git is keeping track of which files are in which branch. When you create a file in a topic branch and then switch to master, Git will automatically remove that file from master because it theoretically wasn’t made there.

THAT’S what enables you to fiddle with code. THAT’s the power of branching.


Breathe Deep…and exhale.

If you have followed all of this and you’re not confounded, then I’m really impressed. It takes some time to absorb all of this material so go ahead and walk away from this for a little while. Try to let it sink in. And then come back and see if you can read this again and have it make more sense.

Go through the practice code. Try and fork my git_practice repository and mess around with it. If things get hairy, just delete your local git_practice repository and delete the repository you forked on GitHub. Try again. Don’t give up.

Next time, I’ll explain how to manage these new branches you’re working on and, eventually, how to get your topic branches to merge back with your master code.

It’s pretty exciting…


Credit for branching images goes to Jason Noble, from DaVinci Coders

Git 101 – How to set up a git repository

Git is a distributed version control system (DVCS) used for software development. What does that mean? Fundamentally, Git tracks changes made to code by identifying changes with a alphanumerical ID. Each new version of code has a unique ID, so changes can be identified throughout the entire development process. This is particularly useful when multiple developers are working on a single project; they can collaborate on pieces of code and know who made what changes. But it’s also great if you are working on a personal project on your local computer and need to manage the versions of code that you develop.

The fact that Git is ‘distributed’ makes all of this possible. Whereas some VCS’s require all developers to log into a central server, Git users can make independent changes and later, Git will take care of figuring out what changes conflict and merge the code. So how can you use this powerful tool for yourself? Well it’s quite easy to set up. Just follow these steps.

NOTE: If you only plan on using Git locally, look out for points in this tutorial that you can skip.


Getting Started – GitHub and SSH keys

I’m assuming you’ve already downloaded and installed Git for your computer. If not, go ahead and do that.

NOTE: Skip the next couple of steps if you only want to work locally.

Then go to GitHub and create a new user account. I would advise you use an email address already associated with your professional life – this will help others find your work more easily. GitHub is just a web hosted interface for managing your git repositories. Don’t worry about what that means, we’ll go over it later.

Then generate public SSH keys for your computer. SSH keys are just a secure way for your computer to talk to GitHub without asking you for a password every single time you want to make changes to a project. GitHub already has great tutorial on doing this, so just follow it step by step.


Create a local repository

Now you’re ready to create a repository, or ‘repo’, on your computer. A repository is just a data structure that Git uses to track changes made to your code. Think of it as a storage space for your project. For now, we’ll create a repository in our home directory. If you open ‘Terminal’, by default you should already be in your home directory. But let’s just make sure by typing the following.

$ cd ~

Then we’ll make a directory to test practice in and then move into it.

$ mkdir practice
$ cd practice

Now comes the fun part. We’ll initialize a Git repository. We just initialize a git repository using git init. This step will create a hidden subdirectory in your directory called ‘.git’. This directory is in charge of keeping track of all of the logs and ‘commits’ (or changes) that you’ve made while working.

Since the purpose of Git is to track changes made in a repository, we should make some changes. A common first change is to create a Readme file with the text ‘Hello World’. Finally, we’ll check the status of our repository. You’ll notice that the output from git status tells us that our Readme is currently untracked. Now, what we’re going to do is ‘stage’ the files and then ‘commit’ them so Git tracks them.

$ git init
Initialized empty Git repository in /Users/tim/practice/.git/
$ echo 'Hello World' > Readme
$ git status
On branch master

Initial commit

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

	Readme

nothing added to commit but untracked files present (use "git add" to track)

On more thing, when you run git status , you might notice that the output tells us that we’re on ‘branch master’. We’ll cover branching in a later post, but just keep in mind that initializing a Git repository automatically puts you on the master branch.


Modify > Stage > Commit > Repeat…

After making some changes, you need to ‘commit’ the change that you make. In a sense, every commit you make is a snapshot of the new things you have added/modified in your project. So, the Git workflow is to (1) modify your files, (2) stage (prepare) them, and (3) commit the files to Git.

The two-step process to commit changes (stage > commit) is an important feature. It allows you to clearly identify and choose which files are tracked. So perhaps you’re working on two different files and you feel confident that you’re finished working on one of them, but the other needs more revision. Well, in Git, you can stage just the finished file and commit it and continue working on the other. This is the easy part!

$ git add Readme
$ git commit -m 'Added Readme'
$ git status
[master (root-commit) eb89f56] Added Readme
 1 file changed, 1 insertion(+)
 create mode 100644 Readme

See? All we had to do was add the modified file to the staging area and then commit it. The -m allows us to add a message so we can keep track of exactly what we did with each commit. If you forget to add this, terminal will ask you to add a message manually.


Publishing your repository to a remote

create repository

NOTE: Skip this whole section if you only want to work locally.

Now, we’re going to publish your local repository to a remote one on GitHub. Log in to your account, and on the to right corner, click the + and create a new repository. You can name it whatever you want, but it’s best practice to keep the same name as your local repository to avoid confusion. So we’ll call it ‘practice,’ give it a brief description, and make sure it’s Public. Whatever you do, DON’T initialize the repository with a Readme. Remember, we already have our own! On the next page, select the SSH button and then click the clipboard icon to copy the link.

GitHub ssh keys

Finally, we’ll push your local commit to the remote repository. First, we’ll try to connect to the GitHub servers using your SSH keys, which you should have already set up. The next step is a bit more complicated. git remote add origin URL adds a remote repository for your local one to communicate with. The convention is to name this remote ‘origin.’ This will not rename your ‘practice’ repository in GitHub to ‘origin,’ but it’s just the way your local repository keeps track of the remote. So if that’s confusing, let me repeat – you called the remote repository ‘practice’ in GitHub, but your computer needs a name for it as well and the convention is ‘origin.’ Finally, make sure to paste the URL that you copied from GitHub, which is the path for the remote repository that Git is adding.

Now that we’ve added a remote, we can push our local commits to the remote. Essentially, this means that our remote repository is a synchronized copy of our local one. Remember how I talked about the power of distributed revision control? This is the crux piece of that system – now your collaborators can visit your GitHub page and see the changes you’ve made to a project.

The last step of this process is to git push -u origin master. This tells our computer to push all the commits that we made locally onto our remote repository. -u tells the computer to automatically synchronize our local repository with our remote repository so the next time we git push, we don’t have to specify that the changes are going to origin master. ‘origin master’ is simply the master branch of the origin repository. Remember we have a local master branch? Well origin master is just the remote copy of our master branch.

See…it’s all making sense, right? Your local and remote repositories are just copies of each other. Your local has a master branch, so your remote should too. And while you see your remote called ‘practice’ on GitHub, your computer internally calls it ‘origin’. Anytime you want to update the changes you made on your local repository, you just have to git push them to the remote.

$ ssh -T git@github.com
Hi timsjpark! You've successfully authenticated, but GitHub does not provide shell access.
$ git remote add origin git@github.com:timsjpark/practice.git
$ git push -u origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 221 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:timsjpark/practice.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

Don’t worry if your code doesn’t look exactly the same. Obviously, your username through GitHub will be different. Did it work? Now, refresh your practice repository on your web browser. The changes you made locally also appear on GitHub, so you should be able to see your Readme. Pretty cool, huh?! Try making more changes to your Readme, adding files, etc. and see if you can push them to your remote.

NOTE: After you do your initial git push -u origin master, Git will remember to push the changes in your local master branch to the origin master branch. So if you practice making more changes, staging, and then committing them, the next line of code you write is just git push

Good luck, and stay tuned for more information about how to use Git to manage your projects!