how to restart a gunicorn server without leaving vim

I’ve been using the gunicorn WSGI server lately while I work on my next project. gunicorn is fantastic, except for one tiny nuisance. I have to restart gunicorn as I change my app code. At the beginning, this meant I would switch over to the terminal where gunicorn was running. Then I’d kill the parent process by hitting CTRL+C, and then start it up again, by typing:

gunicorn crazyproject.webapp:make_application

Other frameworks often have a development mode that forks off a helper process that watches the source code folder. When some file changes, the helper tells the server to reload.

I’m not using any frameworks this time, so I don’t have that feature. I never really liked the fact that every time I saved a file, I would restart the server during development. Instead, in this case, I want to easily restart gunicorn, but only when I want to, and I don’t want to leave my editor.

It turned out to be pretty easy to do.

First I read in the excellent gunicorn docs how to tell gunicorn to reload my app:

How do I reload my application in Gunicorn?

You can gracefully reload by sending HUP signal to gunicorn:

$ kill -HUP masterpid

Next I added a –pid /tmp/gunicorn.pid option to the command that I use to start gunicorn, so that gunicorn would write the parent’s process ID into /tmp/gunicorn.pid.

Now any time I want gunicorn to reload, I can do this little command in a terminal window:

$ kill -HUP `cat /tmp/gunicorn.pid`

Those backticks around cat /tmp/gunicorn.pid tell the shell to do that part of the command first, and then feed the result into the rest of the command.

You can always use ! in vim to run some command-line program. If I had to explain the difference between vim and emacs, the one difference that is most interesting to me is that vim makes it super-easy to send buffer contents to other programs or read buffer contents from other programs, while the people behind emacs seem to think that any external dependency should ultimately be moved into emacs itself. I get the feeling that vim wants to be my text editor, but emacs wants to be my OS.

Anyhow, while I’m in vim, I run that command to restart like this:

: !kill -HUP `cat /tmp/gunicorn.pid`

After using that code for a while, and feeling confident it worked right, I mapped F12 in vim to do that action for me by adding this little thing to the end of my ~/.vimrc:

:map :!kill -HUP `cat /tmp/gunicorn.pid`

Now that means I hit F12 when I want to reload gunicorn.

Some notes from when I start using git

When I switched to git from subversion at my old business, I stored notes on how to do certain tasks. I’m pasting it below. Maybe some of this will help you out.

If you know a better way to do these tricks, please let me now.

My git diary
============

.. contents::

Slowly learning how to use git.

Typical upgrade flow
--------------------

I just committed a bunch of code and I want to see what the diffs were,
so I ran this::

$ git diff HEAD^

My production server runs branch 3.5.1 of my software. I want to start
work on a scary new feature that may take a long time, so I made a new
branch called 3.5.2 in my local sandbox::

$ git checkout -b 3.5.2

Now I can commit all my intermediate stuff in here.

Somebody found a bug in the production site (running 3.5.1) so I switch
to my 3.5.1 checkout::

$ git checkout 3.5.1
$ vi # fixing the problem
$ git commit -a -m "Fixed the prod bug"
$ git push origin 3.5.1

That last line sends my local commits to my remote bare repository.
That remote bare repository is on a box with an SSH server and RAID
storage.

Then I connect to the production box and pull down the most recent
changes::

$ ssh prod
matt@prod$ cd where-the-repo-is
matt@prod$ git pull origin 3.5.1
matt@prod$ restart-everything

That restart-everything command is a homemade script that does just what
you think it does.

Now back in my dev sandbox, I want to pull the bug fix from 3.5.1 into
my 3.5.2 branch. So I do it like this::

$ git checkout 3.5.2
$ git pull . 3.5.1

And now my 3.5.2 branch has that code in it. Hurray! Understand that
the dot (.) in git pull . 3.5.1 means that git should retrieve code from
this repository, not the fancypants remote one.

Pulling stuff
-------------

When I run::

$ git pull origin 3.5.1

That means to pull from the origin's 3.5.1 branch into whatever branch I
currently have checked out.

A typical day
-------------

I have two branches, an experimental branch and a public branch.
The production server used by customer runs the public branch.

Usually I work in my development branch. Sometimes I have to do some
code into production so this is how I do it::

$ git checkout stable # switch my local copy to the stable branch.
$ git pull origin stable # update local copy, just in case.
$ vi blah.py # do the bug fixes.
$ git commit -a -m "Notes about bug fixes"
$ git push origin # This is my deploy system.
$ git checkout dev # Go back to my development branch.
$ git pull origin stable # merge in that bug fix.

So far, this works well. I did something similar with SVN, and it also
worked fine. But git is way better at safely merging and it is much
faster.

Undo changes to a single file
-----------------------------

I typically edit a dozen files and then figure out that I want to undo
some stuff. If I did::

$ git reset --hard

Then my whole working copy would be destroyed. Usually, I just want to
do something like revert one file. So this is how::

$ git checkout that/particular/file

That deletes my working-copy changes just there. Everything else is
left as-is.

How to submit patches by email
------------------------------

I cloned the ditz project and tweaked the code, and I wanted to submit a
patch, so this is what they told me to do::

For this type of thing, it's "very simple". git commit -a, add a
one-line description followed by a blank line and more commentary, and
then git format-patch HEAD^.

When I ran git format-patch HEAD^, that produced a file on my local
machine that had a pretty formatted patch. Then I emailed that patch to
the list with some text.

How to branch from a remote repository
--------------------------------------

This is what somebody in the #git room told me to do, since I use a
remote bare repository::

$ git fetch origin
$ git checkout -b newbranch origin/original

Here's another person's opinion::

$ git fetch && git checkout --track -b mynewbranchagain remotename/mynewbranch

Set the remote branch
---------------------

Normally I have to pull from my remote repo and specify the branch I
want to pull in like this::

$ git checkout experimental
$ git pull origin experimental

It is possible to associate my local branch of experimental with that
remote branch of experimental like this::

$ git config --add branch.experimental.remote origin
$ git config --add branch.experimental.merge experimental

And now I can run::

$ git pull origin

without specifying the remote branch. In fact this works too::

$ git pull

Compare one file across two local branches
------------------------------------------

I want to look at a diff of x.py in my public branch vs my experimental
branch, so this is what I did::

$ git diff public experimental -- x.py

I can see everything different between the two branches like this::

$ git diff public experimental

Break up a whole bunch of changes into different commits
--------------------------------------------------------

I'm irresponsible about committing after each conceptual unit of work.
Lots of time, I'll edit a file to fix one bug, then while I'm in there,
I'll edit some other code because I see a better way to do something
else. Then I'll maybe add a few doctests to a completely different
section just because I want to.

After a few hours, typically inside of the same file, I have edits
related to multiple separate tasks.

Before I commit my changes, I run::

$ git add -p frob.py

Which walks through all the changes in that file and asks me if I want
to stage each one. In the first pass, I stage all the hunks related to
the first issue. Then I commit those changes. Then I rerun git add -p
frob.py again and march through the file for the next the second issue.

Keep in mind that I committed my changes after the first pass, so when I
go through the file the second time, I won't get prompted for those
changes.

This is one of those git features that you just couldn't do with svn.

Find the commits in branch A that are not in branch B
-----------------------------------------------------

Sometimes I'll patch a production bug in my production branch and then I
will forget to merge it into the development branch. This is how I can
check for that::

$ git checkout production_branch
$ git cherry dev_branch

This will spit out a list of commits that are in production_branch but
not in dev_branch.

It will not return any commits made to dev_branch but not in
production_branch.

See a file as of a point in time
--------------------------------

Looking at a commit shows the changes. Sometimes I want to see the file
itself.

Here's how to look at foo.py as of two commits ago::

$ git show HEAD^^:b/foo.py

Here's how to see what foo.py looked as of a particular commit::

$ git show bf51ebdbc:b/foo.py

b/foo.py is the path to the foo.py from the top of the repository. I'm
not certain, but I don't think the current working directory matters.

Copy a file from one branch to another
--------------------------------------

I committed a file into one branch then checked out a new branch. This
is how I copied that file into the new branch WITHOUT merging it in::

$ git checkout newbranch # 1
$ git checkout otherbranch foo.py # 2

Step 1 moves me into the newbranch. Step 2 gets me a copy of the file
foo.py from otherbranch and saves it into this branch named newbranch.

See a file in a different branch
--------------------------------

After I checkout the maxhenry branch I want to see the version of
printable.kid in the mayfield branch::

$ git checkout maxhenry
$ git show mayfield:bazman/bazman/templates/printable/printable.kid

Set a file to an old version of itself
--------------------------------------

Sometimes I want to get the version of a file as of a certain commit and
check that in. There are lots of ways to do this, including using git
revert or git reset, but I've had good luck with this approach::

$ git log # Use this to find the commit you want.

$ git checkout ac778cbb5517e1aeef446c9a8a1092eef81717fa:repo-top/a/foo.py

After you run this, the index will have this old copy queued up to be
commited. You can use git diff --cached to see the changes.

Create a new branch on the remote repo
--------------------------------------

We just pushed the branch **mollusk** up to production, so now it is
time to create a new branch named **nosehair**::

$ git branch nosehair # creates the new branch
$ git checkout nosehair # switches to the new branch
$ git push origin nosehair # pushes it up to origin

Switch to a new branch that already exists on a remote repo
-----------------------------------------------------------

After somebody else already created the branch nosehair, and pushed it
up to the remote repository, here's how to switch to work on the
nosehair branch::

$ git fetch origin
$ git branch -a # make sure origin/nosehair exists!
$ git checkout -b nosehair origin/nosehair

Search through commit messages
------------------------------

This is how I found all commits that had a commit message that included
the word CCPL::

$ git log --grep=CCPL

This is how I limited it to just my (Matt's) commits for CCPL work::

$ git log --grep=CCPL --author=matt --all-match

Without the --all-match option, you'll see all commits by matt or that
have CCPL in the commit message.