The Mijingo Blog

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

How I Learned to Teach

by Ryan Irelan

A couple years ago, I wrote an essay on my experience learning and teaching a foreign language and how that formed my approach to teaching technical topics here at Mijingo.

Two years after returning from Germany, I was a graduate student teaching elementary German to undergraduates. On the first day of the semester I walked into the classroom, stood in front of the class and introduced myself … in German. How I learned German was how I now taught German (thanks to an excellent teaching program). This was my first experience preparing a curriculum that used immersive learning techniques. It worked for me and it worked for my students. That experience stuck with me.

Read the whole thing to learn how immersive language learning techniques can help you be more successful learning web development skills.

Immersive learning isn’t limited to just languages. You can use it to teach and learn anything: code, software, content management systems, development frameworks, or productivity workflows.

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.

Information is Cheap

by Ryan Irelan

Not long ago, I posted this on Twitter:

Information is cheap, meaning is expensive.

That’s a quote from George Dyson, the American and Canadian science historian and author.

Here’s what preceded the quote, from an interview with The European Magazine:

Finding answers is easy. The hard part is creating the map that matches specific answers to the right question. That’s what Google did: They used the power of computing – which is cheap and really does not have any limits – to crawl the entire internet and collected and index all the answers. And then,by letting human beings spend their precious time asking the right questions, they created a map between the two. That is a clever way of approaching a problem that would otherwise be incomprehensibly difficult.

We now live in a world where information is potentially unlimited. Information is cheap, but meaning is expensive. Where is the meaning? Only human beings can tell you where it is. We’re extracting meaning from our minds and our own lives.

In my world, plain, vanilla information on a topic isn’t always enough to successfully learn it.

I’ve written about teaching with context before and how it’s always, always a winning situation for both the student and teacher.

Relating what you’re teaching to your students—teaching with context—is one ingredient of helping your students succeed. Your students could be in a classroom in front of you, viewers of a digital training course you created, or the readers of documentation you wrote. Your students could even be the attendees of a talk you’re giving at a conference.

There are dozens, hundreds, perhaps even thousands of tutorials on the same topic. But so many of them just state the steps and the facts. Most of them lack a coherent story and context: the why.

Information is indeed cheap (and easy to find). Giving that information meaning is what good teachers and tutorials do to help students learn.

Brief Overview of Craft Routing to Templates

by Ryan Irelan

How does Craft know which template to render when? It all starts and ends with Craft’s request routing.

The Craft documentation for Routing starts us off perfectly:

When a request comes in, Craft goes through several checks when determining where to route the request.

Craft does a routing check sequence that every request goes through so it ends up at the right place, delivering the right page or asset.

Pull up the routing documentation page and let’s talk through it.

The first three checks in the routing sequence:

  • “Should Craft handle this request in the first place?”
  • “Is it a resource request?”
  • “Is it an action request?”

cover whether Craft should take the request at all (sometimes it’s not necessary), if it’s a request for a Craft-managed resource, or if it’s an action request (like submitting a form or other actions from third-party plugins).

The fourth check is if the request is for an entry or category page. If there is a URI match then Craft will load the proper template (the one you specified when setting up the category or section).

The fifth check is if the request matches any Dynamic Routes you set up in the Craft control panel. Dynamic routes are hugely powerful in allowing you to create custom URIs that don’t necessarily match the template path. This saves you from having to conceive an unusual template directory and file naming scheme just to get the URLs to be how you want. If there is a match then Craft will render the template specified in the matching Dynamic Route.

The second-to-last check in the sequence to see if the request URI matches a template. If the URI is a valid template path (directory + template), then Craft will render that template.

This is a literal routing of the URI to the template.

If you have a request for template offices/austin.html and Craft goes through its checks and doesn’t find a match before it gets to the template check then it will render the offices/austin.html template. If you had an entry with that URI then it would render the entry instead (using whichever section entry template you specified).

At the end of the check sequence, if there are no matches, Craft will return a 404 error. If you don’t have a custom 404 template, Craft will render the default view. To create a custom 404 template, add a 404.html template file in the root of your craft/templates directory and Craft will use it.

Ready to learn more about Craft?

If you want to learn more right now about Craft, I have a popular 2 ½ hour video course that will get you started on the right path.

Get the Craft video course

Sublime Text Tips and Plugins

by Ryan Irelan

Magnus Gyllenswärd of Thoughtbot did a short overview of some of the features and plugins he uses and likes in Sublime Text as part of his Thoughtbot Lunchtime Lightning presentation.

Here are some of the things he covers:

  • Fetch - fetch remote files from anywhere
  • Gist from condemil, create and edit Gists.
  • Less Tabs from Web Artisan. Remove tabs that you haven’t used in a while.
  • Emmet - Official plugin for Sublime Text for writing markup faster.
  • Multiple cursors - a flagship feature of Sublime Text. Memorize this if you don’t know it already.
  • Sublime Text Projects - a feature I don’t really use but probably should!
  • Can I Use plugin, that lets you highlight a property and see its support on

By the way, if your company doesn’t do lunch time talks where you share information and techniques internally, I strongly encourage it. Whether you call them Lunchtime Lightning talks, Lunch ‘n’ Learns—as they were at my previous company—or no name at all, these gatherings are a way to rapidly transfer knowledge among team members. Very valuable!

(Link via Gabe at Macdrifter)

How to install Gulp.js

by Ryan Irelan

Just like its JavaScript Task Runner neighbor Grunt, Gulp also makes it simple (and fast!) to automate those really annoying web development tasks, like concatenating files, processing Sass, minifying JavaScript files, or optimizing batches of images.

In this tutorial, we’ll learn how to install Gulp.js.

Just like with Grunt, our first dependency is Node.js, so the video will start there. I’ll continue on after the video with some more steps to get set up.

Once inside the project where you want to run Gulp (you can get project shown in the video as part of the JavaScript Task Runners course I put together), we need to create a package.json file that we’ll use to define the decencies for the project, including Gulp.

We’ll do that on the command line using:

npm init

which will walk us through the process by asking some questions about our project. Once we’re done with the questions, npm will generate the package.json file for us, saving it at the root of our project.

We want to save Gulp as a dependency for our project, so in the project root we run:

npm install gulp --save-dev

We use --save-dev so the module is saved in package.json as a dependancy. When someone else wants to work on the project on their computer, they can run nom install and all of the dependencies listed in package.json will be installed automatically.

After the installation of Gulp is done, you should see some output and then a new command prompt.

We look at the package.json file and we see that gulp was added as a dependency for this project.

To ensure that Gulp is available for us on the command line, we need to install it globally:

npm install gulp -g

Running Gulp will now work for us, inside the project:


That should output:

[08:29:38] No gulpfile found

because we don’t yet have a Gulpfile.js file defining our Gulp tasks.

Creating a Gulpfile.js File

Either create a new file in your favorite code editor (right in the root of the project, alongside the package.json file), or do it in the command line:

touch Gulpfile.js

Now when we run Gulp:


We should get a bit more output, like this:

[08:33:46] Using gulpfile ~/projects/test-project/Gulpfile.js
[08:33:47] Task 'default' is not in your gulpfile
[08:33:47] Please check the documentation for proper gulpfile formatting

Gulp now sees our Gulpfile.js file but there’s nothing in it. At the very least, Gulp needs a default task to run when we use the plain gulp command. Let’s add one, shall we?

Open up the Gulpfile.js file and add the following to it:

var gulp = require('gulp');

gulp.task('default', function() {
    // Code for the default task

We have to first require gulp at the top of the file, so we can use Gulp to run our tasks. After that, we define our default Gulp task. The task is empty (containing only a code comment) but it will be enough to check that Gulp is running properly.

Save the file changes and the pop back onto the command line and re-run gulp:


You should now see more output from Gulp, this time showing that it ran the default task:

[08:43:04] Using gulpfile ~/projects/test-project/Gulpfile.js
[08:43:04] Starting 'default'...
[08:43:04] Finished 'default' after 79 μs

Now you’re ready to start defining your own Gulp tasks and automate those pesky development chores!

Learn More About Grunt & Gulp

My video course will get you up and running on both task runners in just 90 minutes.

Get the Grunt & Gulp video course

How to Install Grunt

by Ryan Irelan

Installing Grunt is the first step to automating your web development workflow with a JavaScript Task Runner and it takes just a few steps.

Here’s a video of the steps (pulled right from the course). The written steps are also below.

To install Grunt we need to use the command line.

  • Install Node.js. Using the big green button on the NodeJS site, download the installer package for your operating system. This includes NPM or Node Package Manager, which we also need to manage our Grunt plugins.
  • We do want to make sure we are up to date with npm. So, first, run:
npm update -g npm
  • Now we can install the Grunt command line tool using npm:
sudo npm install -g grunt-cli

This will install the grunt command line tool in your system path and allow it to be run from anywhere on your system. It doesn’t install Grunt, just allows us to run the local project version of Grunt from the command line.

Learn More About Grunt & Gulp

My video course will get you up and running on both task runners in just 90 minutes.

Get the Grunt & Gulp video course

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.

Ryan at Peers Conference 2015

by Ryan Irelan

On April 30th, in Philadelphia, I’m teaching a workshop on Git version control at Peers Conference.

The workshop is called “Git: Under the Hood” and is a three-hour extravaganza that will cover intermediate-to-advanced information about how to use Git to work faster and smarter.

I’d be delighted (and you’ll learn a lot) if you attend both my workshop and the conference. You can get two half-day workshops and a two-day conference pass for only $499. Three full days of great information.

A bit about Peers, for those of you new to it:

We’re a different kind of conference. One where you’ll hear from folks you know, and some new voices you don’t. We bring together developers, designers and web business owners to share their knowledge and experiences. (And have some fun, too.) Whether you’re a pixel-pusher, an artisan or a maker, Peers is for you. Let’s do something awesome, together.

Go register and reserve your space!

Three Twig Tag Types in Craft CMS Explained

by Ryan Irelan

Templating in Craft using Twig can, at first, be a little confusing. If you, like me, come from other systems that have a proprietary template tag system, then it might take a little time to wrap your head around how Craft and Twig work.

But once we learn about the different types of tags things will be clearer and you’ll discover the power of using Twig in Craft. This tutorial will give you the direction and guidance you need to get started.

Let’s jump right in.

There are three tag types in Twig and Craft:

  • Statement/Logic Tags
  • Output Tags
  • Comment Tags

You will always use the first two in your Craft templates. The third, comment tags, are optional but a handy way of documenting anything that isn’t obvious by reading the code.

Statement/Logic Tags

Statement or logic tags use the curly brace plus percent sign delimiter. In Twig and Craft they can come in multiple forms.

Some are just a single tag, like this Craft-specific Twig tag:

{% requireLogin %}

which you would put at the top of a template in Craft to require a logged-in state. If a visitor is not logged in than Craft will automatically redirect them to the log-in page.

Other logic tags take parameters, like the redirect tag in Craft:

{% redirect "about/tos" %}

The redirect tag takes one parameter, which is the URL or path to where you want to redirect the visitor. This is a tag specific to Craft but there are some Twig tags you should know, too.

Another type of tag is one that has an opening and closing tag, like the for tag in Craft.

{% for %}
{% endfor %}

The tag pairs have an opening tag and a closing tag. The closing tag will typically have an “end” prefix, like endfor, endpaginate, and endblock.

Even the set tag we use to set a variable can be used as a tag pair. The simple version looks like this:

{% set author = "Ryan Irelan" %}

But using a tag pair for set, you can assign a block of text to a variable. Here we’re setting the variable socialLinks to an unordered list of social network links:

{% set socialLinks %}
<ul class="social">
    <li class="twitter"><a href="">Twitter</a></li>
    <li class="facebook"><a href="">Facebook</a></li>
    <li class="googleplus"><a href="">Google+</a></li>
{% endset %}

Another example of a tag pair–and by far your most used tag while writing Twig template code for Craft–is the for-loop. It’s how you will loop through and display section entries in your templates and output other lists, like categories.

This is a for-loop to display content from an array of blog posts:

{% for entry in craft.entries.section('blog') %}
    {{ entry.body }}
{% endfor %}

It uses the curly brace plus percent sign delimiter for both the opening and closing tags of the for-loop. This delimiter tells Twig that what’s between needs to be executed as a statement (in this case a for-loop).

Output Tags

The code with the double curly braces are output tags. They print variable contents to the screen (i.e. output content in your template).

{{ author }}

The author variable would output my name (because we set it in the previous example).

If you want to use an output tag to pass in data to another tag, like when we set a variable in Twig, then you don’t need to use the double curly braces.

{% set name = author %}

If we printed out the value of the name variable we just set than it would render:

Ryan Irelan

But output tags can generate the output on the fly and then print it to the screen. How about a little math?

{{ 4 * 4 }}

This output tag will do the multiplication of 4 and 4 and print out the product. I’m unsure how practical it is to do math like this in the template but there you have it.

The Twig documentation calls out that the curly braces are not part of the variable itself but instead an indicator that the value of the variable contained within should printed to the screen.

Comment Tags

This tag type is straight-forward but perfect for adding comments to your templates but not have those comments render in the page source like HTML comments would.

{# Begin logic for sidebar #}

Using a single opening curly brace paired with a pound sign, we can create the un-rendered comments. They’ll always be available in your template file but never rendered by Twig.

Any code that is inside the comment tag will not be executed by Twig.

{# removing this for now to debug
    {% for entry in entries %}
        {{ entry.body }}
    {% endfor %}

There’s a lot more to templating with Twig in Craft but this introduction to three different tags will get you set off in the right direction.

Don’t miss my new course on Craft + Twig

Coming soon is a brand new video course on Twig & Craft that will help you grasp what Twig is, how Craft and Twig work together, and some templating best practices. Sign up below to get notified when the course is ready!

Ready to learn more about Craft?

If you want to learn more right now about Craft, I have a popular 2 ½ hour video course that will get you started on the right path.

Get the Craft video course

Important SVG Elements

by Ryan Irelan

There are a lot of elements–and attributes–to consider when writing SVG. But to get started, we don’t have to learn them all. Let’s review the most important ones you’ll encounter while working with generated SVG or SVG you coded yourself.

svg Element

You’re probably already very familiar with this. It’s the main element of SVG and inside of which you nest any shapes, paths, lines, etc. that you want to draw.

The SVG element defines the viewport or canvas for SVG content.

Here are some of the specific attributes for svg:

  • height - the height of the viewport
  • preserveAspectRatio - forces the aspect ratio so your image isn’t stretched when using the viewBox element to define a new coordinate system.
  • viewBox- Allows you to set a new coordinate system by defining where x,y coordinates where the system starts as well as the width and height.
  • width - The width of the viewport for this SVG element.

g Element

This element is used to create groups of SVG objects. For example, if you had a series of related rectangles (rect), you can group them together inside of a g element. The nice thing about this is that any transformations you apply to g apply to everything inside of the group.

The g element accepts all global attributes (like stroke, fill, etc).

circle Element

This element does exactly what it says in the name: it creates circles.

circle accepts three element-specific attributes:

  • cx - This attribute defines the x coordinate of the center of the shape.
  • cy - This attribute defines the y coordinate of the center of the shape.
  • r - Defines the radius of the circle.

rect Element

This is the elements we used in all our examples up to this point. It creates rectangles.

The rect elements takes the following attributes:

  • height - Defines the height the shape.
  • width - Defines the width of the shape.
  • x - The x coordinate where the shape should start drawing.
  • y - The y coordinate where the shape should start drawing.

line Element

The line element allows you to draw lines in SVG. Each line connects two points by setting x and y coordinates.

Here are the attributes available in line:

  • x1 - the start of the line on the x axis
  • y1 - the start of the line on the y axis
  • x2 - the end of the line on the x axis
  • y2 - the end of the line on the y axis

path Element

You’ll see the path element if you take an existing artwork and convert it to SVG (in Adobe Illustrator, for example). Illustrator converts the artwork to SVG by tracing the shapes in the image and converting them to SVG path elements.

Any shape can be created with the path element. It takes the following specific attributes:

  • d - this is the definition attribute, which defines the path to follow to create the shape. The path is defined using “path descriptions:” Moveto, Lineto, Curveto, Arcto, ClosePath.
  • pathLength - Use this attribute to define the total length of the path.

polygon Element

The polygon elements allows you to create any shape with many sides. A typical example would be an octagon. You plot the sides of the polygon using points (the only specific attribute for this element).

text Element

Use the text element to set text in your SVG. text takes the global style attribute, which you can use to apply styles (size, font, stroke, etc) to the text.

  • dx -
  • dy -
  • lengthAdjust -
  • text-anchor -
  • textLength - An exact value of the length of the text. This used for very specific layouts.
  • rotate - A list of numbers that will determine the rotation of the text.
  • x - the coordinate where the text begins
  • y - the coordinate where the text begins

textPath Element

The textPath element allows you to put text along a path element and have the text follow the shape. This is a classic SVG demo element because it can make text on a curve.

Did you like this review of SVG elements?

Invest a small amount of time to improve how you use SVG with our hands-on video course, Up and Running with SVG.

Get the video course

Search Git Commits with grep

by Ryan Irelan

A log of commits in Git (retrieved using git-log) can be filtered and changed to output only the commits (or types of commits) that we want to see.

Typically, you review the repository history using git-log by running:

git 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, unless you have a display the size of a building.

Sometimes, however, we want to only find changes that included certain keywords in the commit message. To do this we use the --grep option and pass in a term or regular expression.

git log --grep="homepage"

This will return a log with commits that only reference the word “homepage” in the commit message.

Used in conjunction with other git-log options (like --author and --since), you can very quickly narrow down the commits to exactly what you’re looking for.

Ready to learn more about Git?

Invest a small amount of time to improve how you use Git with our practical tutorial.

Get the video course

Grunt & Gulp Together (at last)

by Ryan Irelan

We’ve been learning about both Grunt and Gulp with the Mijingo JavaScript Task Runners course.

Two powerful tools, right?

As I mention in the introduction video, you don’t have to choose between the two. Use Grunt for this project and Gulp for that other project. 

Or use them together!

This short tutorial tells you how. Let’s get started.

Joining Gulp and Grunt

You make Grunt and Gulp work together by running your Grunt tasks in your gulpfile.js file. You’ll need to do the following steps in a project already set up with Gulp. Since you learned with the Mijingo course, you can just open up the Gulp project you built in the course and start there.

Install the Node package gulp-grunt by running:

npm install gulp-grunt --save-dev

If it’s not there already, move your Gruntfile.js file to the project (if you’re using the sample project from the course you’ll want to copy it over). We need it there so we can access the tasks inside of Gulp.

We have to make sure the Grunt plugins are installed so the Grunt tasks can run. No Grunt plugins, no Grunt tasks.

Individually install the Grunt plugins you need, or copy the dependencies from package.json in the Grunt project to package.json in the Gulp project.

Because we have added new dependencies, we need to install them in the project. Run

npm install

to install all project dependencies, including the Grunt plugins we just added to the package.json files.

Near the top of your Gulp file, require the gulp-grunt plugin like so:


Because we’re calling gulp, we need to do this after we define the gulp variable. This loads in the Grunt tasks defined in your Gruntfile.js file. Now we have access to them and can call them from our Gulp file.

Before we do, let’s make sure everything is working okay with our Gulp file. Let’s run gulp in the command line as a test to check.


Look good? No errors? Good, let’s continue.

Now we need to tell Gulp to run our Grunt tasks. We’ll add the Grunt task sass:dist to the default Gulp task. It will look like this:

gulp.task('default', function() {
    gulp.start('uglify', 'sass', 'grunt-sass:dist');

We added the Grunt sass:dist task to the default Gulp tasks by specifying it in the start method.

All Grunt tasks run in Gulp will use the grunt- prefix so they don’t conflict with your Gulp tasks of the same name. You don’t have to rename your Grunt tasks to make this happen, gulp-grunt will handle this prefixing automatically.

Now for the grand finale. Let’s run the Grunt task in Gulp.

Run gulp in Terminal to fire off the default Gulp task.


At the end of the output you should see something like this:

Running "sass:dist" (sass) task

Done, without errors.
[20:38:24] Finished 'grunt-sass:dist' after 1.2 s

That’s it, you did it!

Further Reading

To learn about all of the options for using the gulp-grunt Gulp plugin, review the official documentation.

Learn More About Grunt & Gulp

My video course will get you up and running on both task runners in just 90 minutes.

Get the Grunt & Gulp video course

Two Types of Git Tags

by Ryan Irelan

There are types of tags in Git: annotated and non-annotated. The names say it all: with one type we tag with an annotation on what the tag is about, while the other is tag without annotation. Both, however, are tags and mark a point of time in the life of the repository.

Annotated Tags

Annotated tags are created with a message so there’s some context–other than the name of the tag–to go with the tag.

git tag v1.2.0 -m "version 1.2.0, including new API"

In addition to the message, annotated tags also include the name of the tagger, and the date the tag was created.

If we run

git show v1.2.0

we will get something like this above the list of changes:

tag v1.2.0
Tagger: Sally Smith 
Date:   Tue Jan 27 14:06:02 2015 -0600

version 1.2.0 of the site

Non-annotated Tags

Non-annotated tags (also called “lightweight tags”) are created without a message, so the only hint as to what the tag is about is how you name it.

git tag v1.2.1

Non-annotated tags will look like a commit object, showing the changes made to the repository, but it won’t have metadata about the tag.

When do I use which tag type?

That short answer is: that’s entirely up to you.

But if you want to include the name of the tagger and a date, you should use the annotated tag. I would use annotated tags for official releases, like MySoftware v1.2.1.

git tag MySoftware-v1.2.1 -m "version 1.2.1, including new API"

This tag shows the tagger name and date, in additional to any information about the release.

For casual tagging, a lightweight or non-annotated tag should be enough.

Both tag types include the entire history log of commits, so you will always have a record of what happened leading up to the tag (remember, a tag is just a snapshot of a point in time in the life of a repository).

Ready to learn more about Git?

Get the video course

Reverting a Git Merge

by Ryan Irelan

Sometimes you get in a situation–and this is a no-judgement zone, we’ve all been there–where you merge branches and you messed up and need to undo the merge because, well, because your co-workers are kind of mad you broke the project.

Let’s say that happened. How do you revert a merge?

We have a my_feature_branch that I’ve been working in. We also have a develop branch that I merge into and deploy to my testing/staging server.

git checkout develop
git merge my_feature_branch

My merge of my_feature_branch into develop broke the site. I need to save myself from further embarrassment in front of my team, so let’s undo the merge into develop.

Because the merge is a commit that points the HEAD to a specific commit, we can undo the merge commit and roll back to the pre-merge state.

To revert the previous commit (our merge commit), we do:

git revert HEAD

We can also specify the exact merge commit that we want to revert using the same revert command but with a couple additional options.

git revert -m 1 dd8d6f587fa24327d5f5afd6fa8c3e604189c8d4>

We specify the merge using the SHA1 hash of the merge commit. The -m followed by the 1 indicates that we want to keep the parent side of the merge (the branch we are merging into).

The outcome of this revert is that Git will create a new commit that rolls back the changes from the merge.

We are saved from embarrassment! The project is working again. Now back to work to figure out why that merge broke the commit.

Ready to learn more about Git?

Get the video course

Learn more advanced Git techniques

by Ryan Irelan

Today I released a brand new course called Git: The Next Steps. It’s a follow-up to the Basics of Git course that gets you up and running with Git version control.

The course has three modules: How Git Works, Git Workflow Tools, and Solving Problems with Git.

We start out with digging in and learning how Git works and why it really is just a bunch of interrelated commit objects (what? you’ll see what I mean when you take the course).

The workflow tools module gives you practical Git commands that will help you immediately. A cool way to create useful, helpful Git log output, merging stashing, and tagging.

Module 3 gives you information for when things go wrong. Because they will go wrong! Learn all about git-bisect, git-revert, and git-reset.

There’s a lot more to learn about Git and this course will take you to the next step.

Start learning Git now

Find Out What A Command Does

by Ryan Irelan

In the command line, you’ll often find yourself wondering exactly what some command does, what the options are, and how, just maybe, you can make your use of that command even better. Here’s how to do it.

The first place I always look when needing more information about the command is the manual (or man as the cool kids might refer to it). Most well-maintained and well-documented tools will have robust manual pages for you to review.

Let’s say we need to know more about git-reset, a tool in Git that allows you to (destructively) rollback changes to your repository.

I know the command is git reset and if add the --help option to it, I’ll get the manual for git-reset.

git reset --help

In the case of git-reset, we get a healthy amount of well-written documentation and very, very helpful Examples area. The examples provided offer real-world scenarios you might face, right from the folks who are working on the Git source code.

Manual for git-reset

Another way to get help with a command is to use the man command:

man ssh

This will display the manual for the SSH command (note that ssh --help does not work).

Not every tool has as robust a manual as Git and SSH but most all do, and you can learn a lot from them. Next time you get stuck, check out the manual!

Want to learn more about the command line? Our Command Line Fundamentals course will get you started on the path to success.

Adding Your Completed Courses to LinkedIn

by Ryan Irelan

An important way to show ongoing professional improvement is by using LinkedIn’s Courses listing. Courses is a section in your LinkedIn profile where you can list the training courses you took online, in person, or at a traditional school.

Adding Mijingo courses to LinkedIn

The major driving force behind Mijingo is to provide you tools and training to continue your professional development. And, you know, it’s important to show that you’re always learning, improving, and staying on top of new techniques in your field.

Let’s make sure you can show what you’ve learned!

To add Mijingo courses you’ve completed to your LinkedIn profile, follow these steps:

  1. Log in to LinkedIn
  2. Under Profile menu, choose Edit Profile
  3. Right under your profile overview, you should see “Add a section to your profile”. Click View More and then choose Courses to add the Courses section to your profile.
  4. Click “Add course” to add a new course. For the course name, use the full name of the course on and append “from Mijingo” at the end. E.g. “Up and Running with SVG from Mijingo”. Leave the course number blank. Lastly, associate it with the position you have or had while taking the course.

Once you’ve added courses that you’ve successfully completed, save your additions and then review your profile to ensure everything looks correct.

Saving Changes with Git Stash

by Ryan Irelan

In the Basics of Git course, I was in the middle of making some changes to the homepage of our sample site when a another change request came in. I needed to quickly save–or stash away–my changes and then apply them back to the repository later, after my other work was complete.

The easiest way to do this is with git-stash, a useful git command that allows you to store the modifications you’ve made in our working directory and go back to a clean working directory.

From the Git Manual (run git stash --help to see it on your own):

Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away and reverts the working directory to match the HEAD commit.

Git stash isn’t a replacement for smart use of branches (we don’t want to start a new feature in a main branch and then stash it away until you’re ready to apply it) but can be a life saver if we find ourselves needing to quickly shifting gears to another task, bug report, or request.

git stash list

Fire up a current project to try out git stash.

First, let’s check if we have any existing stashes.

git stash list

The list option shows all of the existing stashes, if there are any. If you do have some they’ll be listed like this:

stash@{0}: On develop: testing out git stash
stash@{1}: WIP on master: 4fd1101 fixing layout on homepage product listing
stash@{2}: On develop: product bundle download template

Each stash is listed in a separate line, starting with the stash name that consists of the word “stash” and an index (starting with zero) in curly braces. The latest stash is the one at the top, with the index of zero (confusing, right?).

Let’s add a stash. To do that we use the stash savecommand.

stash save "updated the offline file"

The last two parts of that stash command are optional. We can just do:


instead and it will still create a stash with any changes in the working directory but without are customized message. The save option is automatically assumed if it isn’t included.

Here’s the list of stashes now:

stash@{0}: On develop: updated the offline file
stash@{1}: On develop: testing out git stash
stash@{2}: WIP on master: 4fd1101 fixing layout on homepage product listing
stash@{3}: On develop: product bundle download template

To apply a stash to the working directory, we have a couple of options. The first is:

git stash pop

which will remove the most recent stash from the list and apply it to the current working directory. It’s just reversing what you did when saving the stash (but keeping any subsequent repository changes intact).

You can also be specific and pop any stash in the list:

git stash pop stash@{1}

We should see something like this at the end of the output:

Dropped stash@{0} (38f88c1479dc8a3c63f794feed7cd276ae3c6c7e)

The other option when applying a stash is to use:

git stash apply

Just like with pop, we can choose to not specify a stash and it will use the latest. Or, we can specify one, like this:

git stash apply stash@{1}

With apply, we’ll get similar output when applying the stash, but without the message that the stash was dropped. Why? Because git stash apply applies the stash we specified but it doesn’t drop it from the list of stashes.

If we run:

git stash list

We get the full list of stashes, including the one we just applied.

stash@{0}: On develop: updated the offline file
stash@{1}: On develop: testing out git stash
stash@{2}: WIP on master: 4fd1101 fixing layout on homepage product listing
stash@{3}: On develop: product bundle download template

These are the basic commands when using stashes day-to-day. There’s more to it, and I encourage you to run:

git stash --help

to see all of the commands.

Do you need a primer on Git? Check out our course Basics of Git to get started today.

SSL/Non-SSL Site Locally with MAMP

by Ryan Irelan

In the last blog post we walked through how to set up MAMP Pro for SSL websites. This assumed that your website would be SSL all the time, for every connection. While more and more sites are becoming all SSL, many still only invoke SSL connections for critical situations, like signing in or authenticating, important form submissions, and financial transactions, like purchases.

In these SSL and non-SSL situations, a site visitor is being ushered between secure (SSL, https) and insecure (http) connections, depending on what they’re doing on the site. On Apache, this is typically set up as two different host records, one for port 80 (http) and one for port 443 (https).

When setting this up locally–as a way to emulate how our production server would work–we also need to set up two different host records on Apache.

This tutorial requires that you have a paid (or trial) copy of MAMP Pro.

Set up Non-Secure Host Record

First, let’s set up a normal MAMP host record.

(If you’re new to localhosting, I recommend our free course on localhosting, which includes how to use MAMP.)

Create the MAMP site to point at the local (public) directory of the site files you want to use. Restart the MAMP servers and then go to the site URL to confirm that it is working.

Set up Secure Host Record

This part is already covered in the previous tutorial on setting up SSL on MAMP. In summary: we’ll need to create the new host record for SSL–pointing to the same local directory as in the first step–and make sure we check “SSL” as part of the setup.

Redirecting from Non-SSL to SSL

Unless your software, CMS, or web application is set up to handle the redirect from non-SSL to SSL based on URL, you will want to do it with a redirect, using mod_rewrite rules.

Every situation will be slightly different but here’s an example of how I redirectred non-SSL connections to SSL:

RewriteCond %{HTTPS} off
RewriteCond $1 ^(account|cart/checkout|admin) [NC]
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

This starts with a mod_rewrite conditional to check if the request has HTTPS off (meaning it’s a non-secure request, over port 80), then it checks if the request has one of the URIs listed (delimited by pipes).

I can add as many URIs there to check as I wish. In this example, I’m checking for account, cart/checkout, and admin. These are all common examples of places you’d want to have SSL connections.

If the conditions evaluate to true, then the request is redirected to an https of the same URL. We’re using some variables to grab the current HTTP host and request URI.

Now when someone access, Apache will redirect to https://mijingo./dev/account automatically, never allowing /account to accessed over port 80.