The Mijingo Blog

Latest news, updates, free tutorials, and more from Mijingo.

What is a bare Git repository?

by Ryan Irelan

The standard way of initializing a new Git repository is to run git init. The directory in which you do this will be become the Working Tree for the repository.

As part of the initialization process, Git creates a .git directory (which his hidden by default because of the . in the name) that contains the repository itself. This is brains of the repository; it's where Git tracks your changes, stores commit objects, refs, etc. You probably only rarely interact with that hidden directory.

Okay, so all of this is to lay the groundwork for understanding a bare Git repository. What the heck is it?

A bare Git repository is a repository that is created without a Working Tree. Go ahead and create one to see.

git init --bare .

Run ls on that directory and you won't see a Working Tree but just the contents of what is typically in the .git directory.

Why this setup?

A bare Git repository is typically used as a Remote Repository that is sharing a repository among several different people. You don't do work right inside the remote repository so there's no Working Tree (the files in your project that you edit), just bare repository data.

And that's it.

Git the Essentials

Learn everything you need to be proficient in Git. 40+ videos, 6 hours of learning, a better understanding of Git.

Get Git Essentials

What is a Git Remote Repository?

by Ryan Irelan

By default Git is completely local to your computer. You can optionally have remote copies of the repository (either on a central server or service—like Github—or on a co-workers computer).

To get your copy of the repository up to a remote server you use the command git-push. If you want to retrieve others’ changes to the repository you use git-pull.

A Remote Repository in Git is a special type of repository in that it doesn't have a Working Tree. This is different than your local repository, which has your project files and then a hidden .git directory.

You can host your own Git remote repository or use one the popular online services, like Github, Gitlab, or Bitbucket.

Git the Essentials

Learn everything you need to be proficient in Git. 40+ videos, 6 hours of learning, a better understanding of Git.

Get Git Essentials

What is the Working Tree in Git?

by Ryan Irelan

Th Working Tree in Git is a directory (and its files and subdirectories) on your file system that is associated with a repository.

It's full of the files you edit, where you add new files, and from which you remove unneeded files. Any changes to the Working Tree are noted by the Index (see below), and show up as modified files.

When you open the files for a project that is being managed as a Git repository then you are access the Working Tree.

Git the Essentials

Learn everything you need to be proficient in Git. 40+ videos, 6 hours of learning, a better understanding of Git.

Get Git Essentials

Using Git Hooks

by Ryan Irelan

Git hooks are similar to SVN hooks; you can execute a script at a point in the Git routine. Git hooks are both local and server-side. The local hooks pertain to local activities, like committing, merging, checking out, etc. The server-side hooks deal with receiving pushes from a local client.

The scripts that Git hooks execute are stored in the .git/hooks directory of your project. In every repository there are a collection of sample hooks that you can rename and use as inspiration for your own.

The scripts can be in any language that support executable scripts. The samples are mostly shell scripts, but you can use Perl, Ruby, Python, or something else that is familiar to you.

Here are all the hooks available in Git:

  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • applypatch-msg
  • pre-applypatch
  • post-applypath
  • pre-rebase
  • post-rewrite
  • post-checkout
  • post-merge
  • pre-push
  • pre-receive
  • update
  • post-receive

Local Git Hooks

Local Git hooks reside in the .git/hooks directory and are not treated as project files. They are not tracked in the Index and because of that they are not included when someone clones a repository.

Because of this there are some limitations to keep in mind while working with Git hooks. First and foremost: local hooks are not a reliable way to enforce policies, like a commit message structure. And, because you are unable to include the contents of the .git/hooks directory in version control, you will need to consider a way to share hooks that you’d like your team to use.

Here are the local hooks:

  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • applypatch-msg
  • pre-applypatch
  • post-applypath
  • pre-rebase
  • post-rewrite
  • post-checkout
  • post-merge
  • pre-push

Server-side Hooks

Server-side hooks are set up to kick off scripts when a typical remote repository actions takes place.

There are only three server-side hooks:

  • pre-receive
  • update
  • post-receive

They all operate around when the server receives a git-push from a client. These are reliable methods for enforcing some sort of repository or standard. You can run checks, kick of an integration script, testing, etc.

Implement a Git Hook

For our example we’re going to implement a local hook. We’d like to display a message after each commit, reminding us to push our commits to the remote repository.

The setup for this message will be to use the post-commit hook. This hook is triggered after each successful commit. For our implementation, we want the hook to trigger and display a message for us. 
There isn’t a sample file for post-commit already in place. That’s okay, we can create it.

Create a new file called post-commit in .git/hooks.

I’m going to use Ruby as the scripting language. Remember, Git Hooks can use any executable script. But I like Ruby so we’ll use that. This Ruby code is as simple as it comes, with just a single puts statement.

Add this code to the post-commit file:


#!/usr/local/bin
puts "======================="
puts "Please remember to push your commits!"
puts "======================="

With the code in place, we can then save the hook file and set it as executable.


$ chmod +x post-commit

Test it by making a change to our project and creating a commit. If you see the message, it worked!

If you didn’t, check your code, that the hook file is executable, and that you have it properly named.

In another article I’ll talk about triggering hooks on the server.

Git the Essentials

Learn everything you need to be proficient in Git. 40+ videos, 6 hours of learning, a better understanding of Git.

Get Git Essentials

Git Merge Therapy

by Ryan Irelan

Have a seat on the sofa for a moment, please. I want share something important with you.

Ready?

Git merge conflicts are normal and okay.

They are supposed to happen and, most likely, will happen regularly. They don’t happen because you did something wrong. They happen because Git is trying to protect you from losing your hard work.

If you’re new to Git or haven’t done extensive work with it in a team environment then you probably haven’t had the experience of a lot of merge conflicts.

In a future article I will share how you can resolve conflicts but right now, let’s talk about prevention.

We can do some things to prevent conflicts; here’s a list of a few:

  • Ignore generated files
  • Ignore cache or other runtime directories and files
  • Have a good branching strategy
  • Avoid whitespace errors

I’ll go into each one in detail in future articles.

Until then: Git conflicts are okay!

Git the Essentials

Learn everything you need to be proficient in Git. 40+ videos, 6 hours of learning, a better understanding of Git.

Get Git Essentials

The Big Picture of Git

by Ryan Irelan

When starting out with Git, it’s much easier to understand how to use it if we also understand the basics of what Git is.

By that I mean what Git is beyond the commands. Conceptually speaking.

What is a Version Control System (VCS)?

Git is a version control system. You’ll hear this referred to as a VCS sometimes. This is a general term to describe tools that track changes to files over a period of time. The reason we track the changes is so we can revert to previous versions, have a log of the work that was completed, as well as have an incremental backup of the project.

Version control systems aren’t just for code but that’s where they got their start and are most widely used.

You could–and I have–use version control for a book you’re writing.

You could use version control for designs you’re creating for a project.

You could use version control for a series of documents, like proposals, contracts, or agreements.

If it’s a file, it can be tracked by a version control system.

Okay, great. So why should use a version control system for your projects?

First and foremost is because it’s a reliable way to track changes to your files. You might’ve used a simple version control system in the past where you zipped up a project and put a date on it, thereby capturing that day’s work. A version control system also lets you snapshot changes to the project but in a more structured and reliable way.

Getting Git

There are lot of other version control systems out there and perhaps you’ve used one or two before. In the past I’ve used CVS, Subversion, and Mercurial, in addition to Git. I prefer Git because it is local, simple, and fast.

So let’s talk briefly and at a high level of how Git works.

Snapshots of Your Project

When you initialize a new Git repository, you are telling Git to track a set of files.

This set of files will be in a common directory (and subdirectories).

Git now cares about what happens to those files.

At first Git will just tell you that it sees a bunch of files but isn’t yet tracking them. It’ll be up to you to add those files so Git will care about them on an individual basis. After that, Git will notice every change to the file.

By initializing a Git repository, you tell Git: “Hey I want you to pay attention to this set of files. If you don’t know about a file yet, please tell me. If something changes in a file, please tell me. In return, I’ll commit those changes to your repository so you are aware.

Let me try an analogy and see if this works.

Imagine you’re a summer camp counselor. Your job is to take care of, educate, and otherwise entertain a specific group of kids. The kids are organized into groups.

You arrive at the camp on Day 1 and you know you’re responsible for a group of kids. You walk into the room and your supervisor says: “Okay, Ryan, this is your group.”

You look out at the group of kids and say “Okay, ya’ll are mine. I will take care of you.”

“First order of business. I see I have 15 kids here. But I don’t know your names. I need you to form a line and then give me your names so I can write them on this list. This is the list I will use to track your progress at camp so I can report back to your parents when they pick you up on Sunday.”

The kids form a line and, one by one, they give you their name and you write it down on the paper attached to your clipboard. You now have them tracked and know exactly who the kids are.

As summer camp goes on, you watch your campers and their actives. If Suzanne swims a 1km lap in the lake, you mark that change down next to her name on the list.

If Albert gets sick because he ate too many bowls of chocolate pudding after dinner, then you mark that down next to his name to track his health.

The bottom line is: you are watching these kids and tracking how they change during their time at camp.

This analogy may be a little thin but I hope you get the idea. Key takeaway: Think about Git as a system that watches a set of files you tell it to.

This is the git init command.

Once you tell it to watch a set of files, you then have to introduce it to each file.

This is the git add command.

(I go over the actual commands in my Git Essentials course bundle.)

Just like with the campers and and counselor, think about your Git repository as the set of files. Every time you make a change to a file and commit that change (record it as a change), Git snapshots the state of the entire collection of files at that moment.

This might sound like Git is just zipping up the files and such. It’s much more nuanced than that (and it’s something we cover in the Git: Under the Hood course).

Git only saves and records changes to the files that have changed. For the other files, the snapshot simply points to the previous snapshot. This allows Git to efficiently store files without becoming unnecessarily large over the lifecycle of a project.

So, what is Git doing?

It’s caring about your project files because you told it to. Every time you work with Git think of it in this way. Git cares a lot and sometimes you have to tell it no longer care (git ignore), too.

And, as you’ll learn in a different video on merging branches in Git, Git cares so much that it won’t let you lose changes or work. It really is looking out for you.

What this in video form

Git the Essentials

Learn everything you need to be proficient in Git. 40+ videos, 6 hours of learning, a better understanding of Git.

Get Git Essentials

The Pieces of Git

by Ryan Irelan

As far as the Git workflow is concerned, there are three pieces of Git that we should be aware of before moving forward with some slightly more complex (but totally doable!) explanation.

They are:

  • Repository
  • Index
  • Working Tree

Let’s cover each one in a bit more detail.

Repository

A repository is a collection of commits, and a record of what the project’s working tree looked like at one time. You can access the history of commits via the Git log.

There’s always a current starting point in a repository and that’s called the HEAD. A repository also contains tags and branches.

The job of the repository is to be the container that tracks the changes to your project files.

Working Tree

This is a directory on your file system that is associated with a repository.

You can think of this as the filesystem manifestation of the repository. It’s full of the files you edit, where you add new files, and from which you remove unneeded files. Any changes to the Working Tree are noted by the Index (see below), and show up as modified files.

Index

This is a middle area that sits between your Git repository and your Working Tree.

The Index keeps a list of the files Git is tracking and compares them to your Working Tree when you make changes. These changed files show up as modified before you bundle them up into a commit.

You might have heard this called the staging area where changes go before they are committed to the repository as commit objects.

If you ever use the -a flag when committing, then you are effectively bypassing the Index by turning your changes directly into a commit without staging them first.

Learning More About Git

To learn more about Git check out our Git courses, lessons and tutorials.

Learn more about Git

Creating and Applying Patch Files in Git

by Ryan Irelan

In a previous article, I talked about how to use git-cherry-pick to pluck a commit out of a repository branch and apply it to another branch.

It’s a very handy tool to grab just what you need without pulling in a bunch of changes you don’t need or, more importantly, don’t want.

This time the situation is the same. We have a commit we want to pull out of a branch and apply to a different branch. But our solution will be different.

Instead of using git-cherry-pick we will create a patch file containing the changes and then import it. Git will replay the commit and add the changes to the repository as a new commit.

What is git-fomat-patch?

git-format-patch exports the commits as patch files, which can then be applied to another branch or cloned repository. The patch files represent a single commit and Git replays that commit when you import the patch file.

git-format-patch is the first step in a short process to get changes from one copy of a repository to another. The old style process, when Git was used locally only without a remote repository, was to email the patches to each other. This is handy if you only need to get someone a single commit without the need to merge branches and the overhead that goes with that.

The other step you have to take is to import the patch. There are a couple options for that but we’ll use the simplest one available.

Let’s create our patch file.

Using git-format-patch

I am on the repository the-commits, which is the sample repository I used in my Git version control courses. I have the experimental_features branch checked out.

This experimental_features branch has an important change in it that I want to bring to a feature branch I have going. This feature branch is going to be merged into the development branch (and eventually the master branch) so I only want to include non-experimental changes. Because of that I don’t want to do a merge because I’d like to not pull in the other features that are half-baked and would mess up my production-path branches.

Here’s the latest when I run git-log:


$ git log
commit 4c7d6765ed243b1dbb11d8ca9a28548561e1e2ef
Author: Ryan Irelan 
Date:   Wed Aug 24 08:08:59 2016 -0500

another experimental change that I don't want to allow out of this branch

commit 1ecb5853f53ef0a75a633ffef6c67efdea3560c4
Author: Ryan Irelan 
Date:   Mon Aug 22 12:25:10 2016 -0500

a nice change that i'd like to include on production

commit 4f33fb16f5155165e72b593a937c5482227d1041
Author: Ryan Irelan 
Date:   Mon Aug 22 12:23:54 2016 -0500

really messed up the content and markup and you really don't want to apply this commit to a production branch

commit e7d90143d157c2d672276a75fd2b87e9172bd135
Author: Ryan Irelan 
Date:   Mon Aug 22 12:21:33 2016 -0500

rolled out new alpha feature to test how comments work

The commit with the hash 1ecb5853f53ef0a75a633ffef6c67efdea3560c4 is the one I’d like to pull into my feature branch via a patch file.

We do that using the command git-format-patch. Here’s the command:


$ git format-patch a_big_feature_branch -o patches

We pass in the branch with which we want Git to compare against to create the patch files. Any commits that are in our current branch (experimental_features) but not in the a_big_feature_branch will be exported as patch files. One patch file per commit. We used the -o flag to specify the directory where we want those patches saved. If we leave that off, Git will save them to the current working directory.

When we run it we get this:


$ git format-patch a_big_feature_branch
patches/0001-rolled-out-new-alpha-feature-to-test-how-comments-wo.patch
patches/0002-really-messed-up-the-content-and-markup-and-you-real.patch
patches/0003-a-nice-change-that-i-d-like-to-include-on-production.patch
patches/0004-another-experimental-change-that-I-don-t-want-to-all.patch

Those four patch files (named sequentially and with a hyphenated version of the commit message excerpt) are the commits that are in the current branch but not the a_big_feature_branch.

Let’s look at the guts of one of them.


From 4c7d6765ed243b1dbb11d8ca9a28548561e1e2ef Mon Sep 17 00:00:00 2001
From: Ryan Irelan 
Date: Wed, 24 Aug 2016 08:08:59 -0500
Subject: [PATCH 4/4] another experimental change that I don't want to allow out of this branch

---
 index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/index.html b/index.html
index f92d848..46e4eb2 100644
--- a/index.html
+++ b/index.html
@@ -9,7 +9,7 @@
   <!-- Set the viewport width to device width for mobile -->
   <meta name="viewport" content="width=device-width" />
 
 <title>Little Git &amp; The Commits</title>
 <title>Little Git &amp; The Commits FEATURING ELVIS BACK FROM THE DEAD</title>
 
   <!-- Included CSS Files (Uncompressed) -->
-- 
2.7.4 (Apple Git-66)

It looks like an email, doesn’t it? That is because all patch files are formatted to look like the UNIX mailbox format. The body of the email is the diff that shows which files have changed (in our case just index.html) and what those changes are. Using this file, Git will recreate the commit in our other branch.

Specifying a Single Commit

In this situation, I don’t need all of those patch files. All but one are commits I don’t want in my target branch. Let’s improve the git-format-patch command so it only creates a patch for the one commit we do want to apply.

Looking back at the log, I know that the commit I want to apply has the hash of 1ecb5853f53ef0a75a633ffef6c67efdea3560c4. We include that hash as an argument in the command, but precede it with a -1 so Git only formats the commit we specify (instead of the entire history since that commit).


$ git format-patch a_big_feature_branch -1 1ecb5853f53ef0a75a633ffef6c67efdea3560c4 -o patches 
  outgoing/0001-a-nice-change-that-i-d-like-to-include-on-production.patch

Now we get a single patch file, which is much safer because there’s no change we’ll accidentally apply patches of changes we don’t want!

We have the patch file, now how do we apply it to our branch?Using git-am.

What is git-am?

git-am is a command that allows you to apply patches to the current branch. The am stands for “apply (from a) mailbox” because it was created to apply emailed patches. The handy thing about git-am is that it applies the patch as a commit so we don’t have to do anything after running the command (no git-add, git-commit etc.).

The name git-am is a little strange in the context of how we’re using it but fear not: the result is exactly what we want.

Let’s apply a patch and see how it works.

Using git-am

The first thing we need to is switch over to our target branch. For this example we’ll move to the branch we compared against in the git-format-patch command.


$ git checkout a_big_feature_branch

After that we’re ready to apply the patch file with the commit we want to include.

Note: I’m working in the same repository on the same computer. When I switch branches, the patch file comes with me because it is still an untracked file. If I staged and committed the patch file then I’d need to find another way to make it accessible. You could do this by moving the patch file out of your repository to where you can access it when on the destination branch.

Because we refined the git-format-patch we only have one patch file in the patches directory:


patches/0001-a-nice-change-that-i-d-like-to-include-on-production.patch

To apply the patch to the current branch, we use git-am and pass in the name of the patch we want to apply.


$ git am patches/0001-a-nice-change-that-i-d-like-to-include-on-production.patch

And the we get confirmation that the patch was successfully applied:


Applying: a nice change that i'd like to include on production

Looking at the log now we see our change is replayed as a commit in the current branch:


$ git log
commit 69bb7eb757b2356e365934fdbea744877c3092bb
Author: Ryan Irelan 
Date:   Mon Aug 22 12:25:10 2016 -0500

a nice change that i'd like to include on production

And now our change is there!

Note that the new commit has a different hash because it is part of a different working tree than the one we formatted as a patch.

Learning More About Git

To learn more about Git check out our Git courses, lessons and tutorials.

Learn more about Git

Using git-cherry-pick

by Ryan Irelan

Recently I ran into a problem on a project where I was working on the wrong branch and committed changes. Those commits were supposed to go elsewhere and I now I need to get them into the correct branch!

There are a few options to solve this:

  • Merge the incorrect branch into the correct branch. But I don’t want to that because there are items in the incorrect branch that I don’t want. So, that’s out.

  • Recreate those changes in my working branch and just go on with my day. But that’s a waste of my time and I’m adamantly against redoing work!

  • Create a patch and then apply that patch to the new branch.

All solid options but there’s still something better:


$ git cherry-pick

Let’s review where we’re at and then how to solve the problem using git-cherry-pick.

The State of Things

I created a new commit in my repository, in the branch called some_other_feature. But that’s the wrong branch!


$ git branch
    develop
    master
    my_new_feature
*   some_other_feature
    stage

The new commit should be on the my_new_feature branch. I could merge the branches but the some_other_feature branch contains commits and changes that I don’t want in the other branch (they are not ready for merging into any upstream branches, like develop or master.

Here’s the commit I need to get into my_new_feature:


commit ec485b624e85b2cad930cf8b7c383a134748b057
Author: Ryan Irelan 
Date:   Fri Aug 19 10:44:47 2016 -0500

    new contact page

Using git-cherry-pick

The syntax of git-cherry-pick is this:


$ git cherry-pick [commit hash]

The first step is fetch the commit hash for the commits we want to cherry-pick. We can do that using git-log and then copying the hash (in full or just the last 7 characters will work) to our clipboard.

Next, we need to be on the branch where we want the changes to be (our destination branch).


$ git checkout my_new_feature

Now we can run the git-cherry-pick command and apply the commit to our destination branch.


$ git cherry-pick ec485b624e85b2cad930cf8b7c383a134748b057

This will return something like this:


[my_new_feature 1bf8955] new contact page
Date: Fri Aug 19 10:44:47 2016 -0500
1 file changed, 1 insertion(+)
create mode 100644 contact.html

If we look at our log for this branch, we now see our commit:


$ git log
commit 1bf8955d5e6ca71633cc57971379e86b9de41916
Author: Ryan Irelan 
Date:   Fri Aug 19 10:44:47 2016 -0500

    new contact page

What’s happening when we run git-cherry-pick?

  • Git is fetching the changes in the specified commit and replaying them in the current branch. The commits are not removed from the source branch; they remain intact.
  • Because this commit is being applied to a new branch and therefore has different contents it will get a different hash than the source commit.

With the problem solved, we are ready to move on with our development work!

Learning More About Git

To learn more about Git check out our Git courses, lessons and tutorials.

Learn more about Git

New Course: Git Under the Hood

by Ryan Irelan

A new course is now available in our Git version control series.

Git: Under the Hood digs in on some of the theory behind Git so we can understand exactly how Git works.

We use the low level “plumbing” commands in Git to manually create Git data objects (trees, blobs, commits) while doing the typical git-add git-commit workflow.

This course isn’t for everyone. If you use Git and like to tinker and see how things work, then this course is definitely for you.

Learn Git’s Plumbing

New Lesson: Using Git in Sublime Text

by Ryan Irelan

A new lesson is available now on how to use Git version control right inside of Sublime Text 3. The goal for this lesson is to learn one way to work a bit more efficiently while coding. There are a few packages available for connecting Git and Sublime Text. In the past I’ve used one called Sublime Text Git and it’s a popular choice. Recently I’ve started using Git Savvy and I really like it so I wanted to share it.

This lesson walks you through installing an using Git Savvy in Sublime Text 3.

Watch the Lesson

Installing Sublime Text Package Control

by Ryan Irelan

Installing packages (add-on functionality that isn't core to the Sublime Text application) in Sublime Text is faster using the Package Control tool.

Package Control isn't part of Sublime Text but an independent project that makes adding additional functionality to Sublime Text easier. If you like Package Control and find yourself depending on it for your work, consider saying thanks to the developer with a small donation to help cover server costs.

To install Package Control on Sublime Text 3, you need input a series of commands into the Sublime Text console. This is actually a Python console but for our needs we just need to paste in a series of commands and Sublime Text will take care of the rest.

Get the Python Code

From the Package Control installation instructions, we grab the Python code to install Package Control. Get the latest version from the site (I could past it here but the code changes with each release and I want to make sure you have the latest code).

Run the Code

To kick of the installation, we run the code in the Sublime Text console.

  1. Type `control-`` to open the console in the bottom portion of the Sublime Text application window.
  2. Paste in the code and press enter.
  3. Once complete and successful, restart Sublime Text.

Type shift-command-p to open the command palate and type:

package control

If you see options for Package Control (like Package Control: Install Package) then Package is properly installed.

Sometimes the tool doesn't install properly. If this happens to you, use the manual installation instructions instead.

Export Files from a Git Repository

by Ryan Irelan

In this free lesson video, Ryan walks through how to use the git-archive command to export the files from a Git repository into a ZIP file.

Watch the lesson on archiving files from Git

Ready to learn more about Git?

We have more courses, articles, and tutorials on Git. Start learning immediately!

See the courses

Understanding Git Log

by Ryan Irelan

Git logs allow you to review and read a history of everything that happens to a repository. The history is built using git-log, a simple tool with a ton of options for displaying commit history.

What’s in Log?

A Git log is a running record of commits. A full log has the following pieces:

  • A commit hash (SHA1 40 character checksum of the commits contents). Because it is generated based on the commit contents it is unique.
  • Commit Author metadata: The name and email address of the author of the commit.
  • Commit Date metadata: A date timestamp for the time of the commit
  • Commit title/message: The overview of the commit as written in the commit message.

A Typical Log

Git logs can be whatever you want them to be. Git-log offers dozens and dozens of options but let’s start with the simplest.


git log 

This outputs the most basic log:


commit 98aa8d722bdecc4e56156cfe1a793a4d16848eb8
Author: Ryan Irelan 
Date:   Sat Jan 10 23:26:40 2015 -0600
 
Adding in new homepage
 
Includes the assets needed for Foundation
 
commit dd8d6f587fa24327d5f5afd6fa8c3e604189c8d4
Author: Ryan Irelan 
Date:   Tue Jan 6 20:07:17 2015 -0600
 
added origination declaration at bottom of RSS feed

This is a snippet of the log, showing two commits. We have a commit SHA1 hash, the author, the date, and the commit message, explaining what happened in the commit. This layout is the default look of the log.

Git has something called Commit Limiting to make it easier to narrow down hundreds or thousands of commits to the ones you want to review.

Directory Restricted Log

The default log is great for grabbing a quick look at what just happened in the repository. But it takes up a lot space and you can only see a handful of commits at once.

When I’m developing a project, I sometimes only want to know what happened in a specific directory. Let’s say I’m working on some CSS or Sass and only want to know about changes in my Sass directory. I can get much more specific with git-log and restrict it only to a specific directory.


git log scss

This will only return commits that had changes in the scss directory.

Log by branch

We can use a similar syntax as directory restriction and build a log for just one branch. We only need to specify the branch we want to see.


git log develop

We can clean that up a little by removing any merge commits (which can bulk up the log if there are a lot of merges, like there would be a develop branch.


git log develop --no-merges

Learning More About Git-Log

To learn more about Git-log, like time-restricted logs, search logs, and more, check out our Intermediate Git course that will make you a Git power user.

Learn more about Git

How to Create Git Aliases

by Ryan Irelan

An alias, otherwise known as a shortcut, allows to place a simple command in front of a longer or less memorable command.

For example, we could type:


git commit -m "some change"

Or we could type even less and do:


git c -m "some change"

We’re only saving a few letters but considering how many times you commit in a day or week, it’s a bit easier on your fingers. Less tapping of the keyboard and more working on the fun code.

To create a Git alias, we need to open up our .gitconfig file and edit it. Because we want to have these aliases available to us in every project, we are going to edit the .gitconfig file in our user directory.

If you don’t already have the file in your user directory, that’s okay. We can have Git handle that for us.

We’ll create an alias first using the git-config command, to which we pass the type of config file (in our case it’ll be global in our user home directory) and then define the alias.


git config --global alias.c commit

This will add the following line to our ~/.gitconfig file. Let’s take a look to see if it was saved.


git config --list

This lists out all of our config items and you should see the alias:


c = commit

listed as output.

Now we have access to that alias within Git. We can type:


git c -m "something"

and it will work just as if we typed out the full command.

Let’s open up the config file and take a look. We’ll open ours in Vim, but you can use any editor you want.


vim ~/.gitconfig

You should see something like this:


[alias]
    c = commit

Let’s add another alias by hand without using the git-config command. It’s just a text file so we can edit it and type out our alias by hand.

Let’s add an alias to make it quicker to get the status of our working directory. Under the existing alias for commit, let’s add this:


st = status

We’ll save our .gitignore file and then try it out.


git st

And we should get some output from Git (assuming we’re inside a Git project) as if we ran the full command.

We can add another for git-log, too.


l = log

And how retrieving the basic log is two letters faster than before!

Okay, let’s do one more to quickly archive the entire repository.

Git provides a command called git-archive that allows us to export the entire repository as either a zip for tar archive file.


git archive --format=zip -o latest.zip HEAD 

This command will output the current repository at HEAD to the a zip file named latest.zip. It will save the file right where you are in the repository.

This can come in handy if you have to quickly share your work with someone who is not in the Git repository or if you need to throw the files up on a server somewhere.

To alias this we add this to our .gitconfig file:


zip = git archive --format=zip -o latest.zip HEAD

Now when we run:


git zip

in a valid Git project directory, git-archive will zip up the entire project and place it in the project root.

One Bit of Advice

You don’t have to have a fully decked out .gitconfig file right from the get-go. Add aliases to your config file as it makes sense and as you need them. They can be tough to remember if you add too many at once!

Ready to learn more about Git?

We have courses, articles, and tutorials on Git. Start learning immediately!

See the courses

Git Tutorials Page

by Ryan Irelan

I created a single page that collects all of the Git learning resources here at Mijingo.

It includes both video courses, the new online workshop, and all of the articles I’ve posted here on the blog.

Go to the Git page

New Online Workshop: Git: Under the Hood

by Ryan Irelan

On May 27, 2015 I’m teaching a live, online workshop called Git: Under the Hood.

This is a three-hour workshop covering the innards of Git and some workflow best practices to help you use Git better. If you already use Git but want to know more about how it works under the hood–the Git “plumbing”–and some powerful workflow tools and commands you can use immediately, this workshop is for you.


The workshop takes place on May 25th 12:30 PM - 3:30 PM CDT.

In order for this to be as personal as possible (so I can answer a lot of questions), I have to limit the attendance. If you think you want to attend, I wouldn’t wait too long to enroll.

Enroll in the Workshop

Preventing Fast-Forward Git Merges

by Ryan Irelan

I’ve written about why you shouldn’t use fast forward Git merges before. In short, using non-fast forward merges keeps your history complete and intact. Using the --no-ff option will prevent you from merging branches and having the child branch history get the boot.

In my PeersConf workshop recently I covered this again. My internet friend Stephen Lewis had a good solution for making sure that Git always uses non-fast forward merges.

git config --global --add merge.ff false

I just added it to my global config; please consider adding it to yours.

Pick Your Tools and Use Them

by Ryan Irelan

From a recent Twitter series I shared:

Not everyone likes Sass or wants to use Grunt or even likes a CMS. That’s okay. If the tools help you, use them.

Git Aliases in .bash_profile

by Ryan Irelan

Learn how to add system-wide Git aliases to your .bash_profile that allow you to:

  • create a shortcut to quickly push changes to the develop branch of your project
  • quickly push to the master branch using a bash alias
  • stage a boatload of files (added and deleted) with one five-letter command. This is perfect to large updates to CMSes, frameworks, and web apps.

This 7 minute video is an excerpt from the OS X Shell Tricks course.

Next Page

What are our customers saying?


"Just purchased your Flexible Twig course. Love it!"
Tyler Morrison
"Been enjoying @mijingo 's Learning Craft video tutorials. Feeling like I've got a good basic understanding of #craftcms Very impressive"
Laura Montgomery
"I bought your Craft Starter Pack a year and a half ago. Worth every dollar. In fact, I would've paid twice as much for it, because you saved me so much time."
Timothy Ingram
"Ben's knowledge of Craft combined with his relaxed and informal teaching style makes for a great learning experience."
Steve Abraham
"Ben puts a lot of thought into his teaching approach and has the ability to explain complex concepts in a way that just make sense"
Gareth Redfern
"Ben is great at taking a complex subject and breaking it down in a way that you can wrap your mind around. I thought that plugin development was something I would never understand, and happily Ben proved me wrong!"
Jonathan Melville
"I really appreciate all the videos and writing you have done. Your work has given me a jump start on my front end development business."
Shan Ricciardi

Perfect for Small Teams & Companies


Mijingo's courses are perfect as the training curriculum for both small teams and entire companies.

Our courses are offered in Team Packs (up to 5 people) and Company Packs (up to 25 people), so you can make one simple, fast purchase to train your entire staff.

Prices are listed with each course. Need more than 25 or something custom?

Send Your Requirements
Team Pack2-5 People
Company Pack6-25 People
Custom Pack25+ People