Vim, Git & Unix… 3 tools which go together like crispy bacon, mashed potato and mushy peas.
If you’re a front-end developer, specifically one that regularly works on remote files and has a need to dip in and out of servers making quick changes, and you’ve heard about the the power of these mythical power tools but have never used them, then this post is for you.
This post is designed to be a barebones-only, super-quick guide to give you all the tools needed to be able to effectively get around a linux/unix terminal, edit code in the never-been-bettered ultra-fast Vim and version control your stuff using Git.
What I’ll show you will only be the tip of the iceberg, but it will be enough for you to feel competent and use the commonly used functionality effectively. You’ll also understand enough to know when there is a gap in your knowledge and where to look to fill it. In other words I’m going to show you probably less than 5% of what these systems can do, but its the 5% that gets used 90% of the time.
I’ve designed this post to be followed from start to finish, teaching you bits and bobs along the way. We’ll start by pulling in a sample file, messing with it it Vim, version controlling it with Git and then deleting everything once we’re done. Nice and clean.
Assumptions: This post assumes to are working on a unix-based system, namely OS X or Linux. I simply don’t know anything about the intricacies of getting this stuff to run on Windows although I am told it is relatively simple. Google is going to have to be your friend on this one I’m afraid.
So let’s get to it.
Getting around the terminal
Lets start by having a look around the terminal.
Open up your terminal app and by default you will be sat in your home directory, idetified by
The prompt will look something like this:
Lets have a look whats in the directory, type
this will list the files and subdirectories, generally you would want a bit more information so lets get used to typing
a means show all (including hidden files) and the
l means show as a list.
Lets create a directory. Type
Now go into that directory
Now lets download a sample file to mess with using
curl -O http://www.simonsays.me.uk/downloads/sample.html
curl is a clean way of grabbing files (or indeed entire directories) from a remote location, the
-O (that is a capital O and not a zero) modifier tells curl to download the file and keep its name the same, without this modifier the contents will simply be shown in the terminal, so do that first if you want to see what you’re about to download.
if you now run
ls -al again then you will see the newly downloaded sample file in the directory listing.
Before we edit this file, we should really set up Vim. Out of the box its a bit rough around the edges and we need to add a few settings to make it tasty. I’m going to recommend you use a basic config file I’ve set up which you can edit later should you wish (I’ve commented the entire file so you can see exactly what is happening if you’re interested).
So, lets go back out one level to your home directory (this is where the
.vimrc config file needs to sit so it can be read by Vim)
and download my barebones version of the .vimrc file using curl just like before
curl -O http://www.simonsays.me.uk/downloads/.vimrc
and you’re done, Vim will now use my basic config file. So lets go back to our temporary directory and load up the sample file
cd foo vi sample.html
So before we begin editing, I need to explain a fundamental difference between Vim and most other text editors.
The default mode for Vim (the mode you are now in) is called command mode. From here you can’t type anything, this is the mode where we move around the file and tell the editor what we want to do. Examples in plain english of what command mode might be used for would be:
- Go to the next line
- Delete 3 lines
- Replace all occurences of xxx with yyy on lines 20-30
- On the current line, change the contents between the quotes to something else
Lets start by moving around, and for this test try and get used to leaving your hands in a standard typing position on the keyboard. Your cursor keys are set to:
h – left
j – up
k – down
l – right
This might seem a bit strange, but Vim is all about speed, so the thinking is your hands may as well be sat in there normal position when moving around.
To advance by one word, use
and to go back one word, use
Here are some common movement instructions to play with:
0 – go to the start of the current line
$ – go to the end of the current line
gg – go to the start of the document
G – go to the end of the document
:23 – go to line 23
: in Vim like in the last command puts you into command-line mode, this is different to the standard command mode in that it will not act until you have finished the command and pressed enter, this mode is for more complex commands as we will see shortly.
Lets build on the commands you just learned to move around and look at some different ways to delete lines to help get your head around the way Vim thinks…
Before we start obliterating half the sample file, you might want to know how to undo (and redo)… Its as simple as
u – undo
Ctrl-Shift-r – redo
So lets get on with the demolition…
Deleting stuff in Vim
d on its own simply starts the delete instruction and does nothing on its own, the characters you follow with define the action:
dw – delete the current word
dd – delete the current line
d0 – delete to the start of the current line
d$ – delete to the end of the current line
dgg – delete to the start of the document
dG – delete to the end of the document
And to extend this:
dfx – on the current line, delete everything from the current cursor position up to and including the next occurence of character “x”. I think of this as “delete until you find x”.
d3w – delete 3 words from the current word onwards (
3dw also works)
d5d – delete 5 lines from the current line downwards (
5dd also works)
There are multiple ways to start typing in Vim. A good starting point would be to just go directly to insert mode either before or after where the cursor is sitting by pressing
i – enter insert mode before the cursor
a – enter insert mode after the cursor
… and from here you can start typing.
Of course this command has its place, but there are cleverer ways to get to insert mode that avoids you needing to move the cursor around. Its better to think “go to xxx and start typing”
So go back to command mode and we’ll get into insert mode in a few different ways. To pull back out to command mode at any time simply press
Here are the common ways of entering insert mode.
I – go to the start of the current line and enter insert mode
A – go to the end of the current line and enter insert mode
o – add a new line under the current one and enter insert mode
O – add a new line above the current one and enter insert mode
Now lets mix together deleting and inserting…
To delete some content, and concurrently enter insert mode we use
As with deleting,
c on its own simply starts the change instruction and does nothing on its own, the characters you follow with define the action:
cw – change the remainder of the current word
cc – change the current line
c0 – change all the data to the start of the current line
c$ – change all the data to the end of the current line
cgg – change all the data to the start of the document
cG – change all the data to the end of the document
As you can see, this is a very similar same set of commands to when we were deleting above, I hope you’re starting to see that although this seems like a lot of information, its all just using a core set of concepts and then it comes down to just talking to the editor?
I’m going to expand on this one further by adding an
i into the mix.
ciw – change inside word, the inside means it will take the whole word rather then just the remainder of the word from the cursor position
This to me is generally more useful than the simpler
cw command. the
i part is very powerful and extends to another sub-set of commands. If you are inside quotes, parenthesis or html tags for example, you can change the entire contents:
ci" – change the contents of the quotes in which the cursor currently sits
ci( – change the contents of the parenthesis in which the cursor currently sits
cit – change the contents of the html tags in which the cursor currently sits
This concept is also applicable to delete commands and works with most other common surrounding elements such as braces, square brackets, etc… have a go with your regularly used ones and I’m sure you won’t be disappointed.
Copying and Pasting
… or yanking and pasting as Vim likes to call it, probably because the
c has been used up by the change command.
I’m not going to list all of the commands, because as I’m sure you’ve guessed it works in exactly the same way as delete and change… for example:
yy – yank the current line
y$ – yank from the cursor to the end of the current line
yiw – yank the whole word
You get the idea.
Pasting is simple:
p – paste the contents of the last yank inline at the cursor, or if it was a full line that was yanked, create a new line below and paste it there
P – same as above, but if it was a full line that was yanked, create a new line above and paste it there
So… last but not least…
Finding & Replacing
Finding is simple, its done with a simple forward-slash followed by what you’re searching for
Then you use
n – find next match
N – find previous match
So now we move onto replacing (or substituting as Vim would have you say since the command is initiated with an
s). As substituting is more complex in syntax than the shorter direct commands we’ve used so far, we use the command-line interface (initiated with
So a basic find and replace looks like this…
This will replace the first occurrence of “replace-this” with “with-this” on the current line only.
To make it substutute every occurrence on the current line only, we need to add
/g to the end of the command, meaning global:
And to make it substitute every occurrence in the entire document we need to add a
% before the
Last but not least if we want to focus in on a few lines only, instead of the
% we put the target range separated by a comma:
(As will most of the commands in Vim, its helpful to think of this in English, so while typing this command I would be thinking “Between these lines, substitute this for this, oh and make it global”.)
Saving & Quitting
Heres a nice simple one to finish:
:w – save (or write) the file
:q – quit the file
:wq – save the file and then quit
So lets exit, in this case lets not save the changes so that we’re singing off the same hymn sheet for the next section, to quit without saving we add an exclamation mark to force the quit:
:q! – quit the file without saving
You should now be sat back in the
foo directory. Lets look at versioning this bad boy.
Version Control with Git
Git Architecture Basics
In a nutshell, Git is a system for taking a snapshot of a selection of files/folders at a specific moment in time. The snapshot is stored safely in a repository (repo for short) to be referred back to, compared against, or restored from at a later time.
One of the primary uses of Git, although not relevant for this specific tutorial, is collaboration. Using Git you can “check out” a central copy of a project, work on it, then merge it back with the master copy.
An important fundamental to understand about Git is that it is structured into three layers.
Working Directory → Stage → Git Repository
The working directory is your live project, the place where you create, edit and work exactly as you would if no Git repo was present.
The stage (sometimes also called the index) is a powerful and very useful intermediate layer between the working directory and the repository. I like to think of the stage as a loading dock where you plonk modified files that are ready to be shipped off to the repo.
The repository is the soul of Git, it is the instant-access storage facility for every snapshot ever commited, along with the full modification history of every file and an audit trail of who did what and when they did it.
Installing & Configuring Git
Unlike Vim, Git isn’t baked into most unix platforms out of the box so we’ll need to install it.
To install Git on OS X, go here and use the standard visual installer:
On linux, just use apt-get:
apt-get install git
All installed? Jolly good.
There are lots of things that you can configure with Git, but in the spirit of this barebones tutorial, lets just identify ourself to Git so it can record who is making changes and get on with the job at hand.
Git is all run straight from the terminal command-line with all commands starting with
git… so lets jump in and type:
git config --global user.name "Your Name"
git config --global user.email firstname.lastname@example.org
This is a shorthand way of adding these two important elements, in the right format, to your global Git config file (global meaning these settings persist over all Git repositories you will create). The file is called
.gitconfig and will now be sitting in your home directory.
In Unix based systems, files starting with a
. are hidden files, and will only be seen when running
ls with the
With yourself identified to Git, we’re good to go, so lets version control this directory (and all subsequent sub-directories) from here on in.
to initialise git in the current directory.
What this is actually doing from a file system point of view is creating a hidden folder in the current directory called
.git which holds the code repository, all version history and repository settings. If you ever want to un-version-control a project, simply delete this directory.
Nothing is being tracked yet, and we can confirm the current state of affairs by running
You will use this command all the time, it is your way of seeing what Git is seeing in terms of files and their current position in the Git hierarchy.
You will see the sample file is under the heading of
Untracked:. This means that the file is on Git’s radar but it hasn’t been told to track it yet. Run
git add sample.html
to bring sample.html into the clutches of Git and to add it to the stage.
If you are initialising a sizeable existing project, and you know you want all of the files and subfolders to be added to the repo, then you can use
git add . – the
. is shorthand for “all”.
If you now run
git status again, you will see that the sample file is now under the heading of
Changes to be committed: which means its packaged up in the staging area and ready to be shipped off on the next commit truck.
The next step is to commit to the repository:
This will push everything that is in the staging area (in this case just one file) to the repo, creating a snapshot of the project at this moment in time. But not until you’ve added your message…
You have no doubt noticed that you have been blindsided and thrown without any prior warning into Vim! This is because with every commit, Git likes you to add a small note to the commit to refer back to. So to complete this stage, enter insert mode by pressing
i and type “Initial commit” (or whatever you want) and then
:wq to save, quit and return to the terminal.
git status again, you’ll see a nice clean status of “nothing to commit” which means we’re up to date and no new files have been added to the directory, it also means no existing files have been changed.
Let’s change a file, open sample.html in Vim
And change xxxxxx (vim, string some funky commands)
Now save and quit using
If you now run
git status you will see that the Git has is aware of the changes as it has now put sample.html underneath a heading of
So let’s commit this change to the repo, but let’s skip the stage. The stage is a useful intermediatry for crafting individual commits but you may find that it is just not necessary in your workflow, so let’s commit in a shorthand way which deals with pushing to the stage; then to the repository; and adding a commit message all in one command:
git commit -a -m "changed revision number"
-a will add all modified files to the stage, but won’t add new/untracked files in the same way the more comprehensive standalone command
git add does.
You are now successfully versioning this project.
So what’s the point of storing all of this stuff in an incremental manner? Well let’s look at comparing against, and reverting from historical commits.
git log --pretty=oneline
And you’ll see the 2 commits that have taken place so far.
— Pull / Clone / Etc
Let’s clear the decks
So there we have it. You’ve traversed the terminal, learnt how to do most of the important stuff in Vim, and dipped a toe into the world of Git project versioning.
I like everything neat and tidy, and there is one last command I’d like to show you in the terminal… Let’s kill everything.
Back up one directory:
Now let’s recursively delete the Foo directory which contains both the sample file and the git repository like so:
rm -r Foo/
rm (short for remove) command on its own is for deleting individual files, and by adding the
-r (recursive) modifier it acts upon directories and deletes every file and subfolder within.
There is another command for zapping directories,
rmdir, but this is only for deleting empty folders. It’s useful for deleting directories which you think are empty (but you’re not 100%) as it adds a safety net and stops you killing stuff you didn’t know was in there.
You’re now back in your home directory and the only thing that remains from this tutorial is the installation (and your very lightweight config) of Git.
Thirsty for more?
As I was writing this, I kept going off on tangents and talking about stuff which was powerful and useful (or that I simply thought was cool) but which was outside the barebones scope of this article. I stripped these bits out and they now form the basis for a more advanced tutorial that I’m working on.
Keep your eye on my stuff or better yet follow me on Facebook so you’ll see when it goes live.
Thanks for reading and I hope you found it helpful. Let me know below if you have any follow up questions or if there is something blindingly obvious that I missed.