Save Time by Automating Your Git Pulls

Stephen Keating
Level Up Coding
Published in
6 min readOct 31, 2019

--

Lazy Koala
Photo by Holger Link on Unsplash
“git pull! git pull! git pull!”

I love that laziness is a virtue for programmers, so when I found myself running git pull commands on the same repo over and over, I knew it was time to automate it. In this post, I’m going to review a couple git basics, give a *brief* introduction to Mac system processes and AppleScripts, and then finally explain the actual script I’m running to automate the git pulls. Oh yeah, there’s some bonus stuff at the end too. Before diving in, here’s a screenshot of the final script:

preview image of the script that will be given in text at the end of the post
spoiler alert!

Why am I git pull-ing again?

If you’ve forgotten your git basics, a git pull command will fetch content from a remote repository, download it to your local machine, and merge with the local repository so that it matches. A pull combines both a fetch command and a merge command.

In my case, I wanted to always have the latest code from bootcamp lectures, and the instructors post the code to a GitHub repo. Because I cloned the repo (reminder: you won’t be able to pull updates if you’ve forked) to a folder on my Mac, I can go into the terminal after each class and git pull the new code. At first, I would cd into the proper directory, tediously write out the entire path each time, before finally running the pull command. However, if you add the -C flag to your git command, you can update a repo from anywhere. Here’s what it looks like for me:

git -C /Users/stephenkeating/Development/code/lectures/ pull

Awesome. Now, anytime I know there is new lecture code in the repo, I can type this command from any directory in terminal to pull the new code. I’m already saving time. But I’m really lazy. I don’t want to open up Terminal and type this every time. Enter AppleScripts.

Trust the Process. Flip the AppleScript.

Processes are programs running on your Mac. Processes can be apps, system apps used by macOS, or invisible background processes.

Things are about to go deep here, and you can skip to the next section if you don’t care about understanding the details. Also, full disclosure: I tried multiple automation strategies before a friend suggested looking into using a system process.

If you’re unfamiliar with system processes, you can learn a lot by simply opening up Activity Monitor on your Mac (it’s in the Applications/Utilities folder). You’ll see all the things running in the background on your computer. (Free tip: Activity Monitor is a useful app to keep in mind if your Mac ever starts to run slowly: fire it up to see and kill the CPU/Memory hogs.) As you can see in Activity Monitor, all kinds of things are running in the background on your Mac. It’s generally a very bad idea to start quitting system processes that you don’t understand, but all we’re doing is adding a small one.

We’re going to write a script that is launched by a system process called launchd. If you read this awesome description of launchd, you can find out all about computer daemons and agents, but for our purposes, all you need to know is that we will write a script in a .plist file that will be launched by launchctl and executed by launchd. I highly recommend reading the manuals on these terminal commands before proceeding. In your Terminal type:

man launchd

and then:

man launchctl

This gives all the juicy information (press q to quit when you’re done reading the manuals). This works for most terminal commands, btw.

Enough Talk, Let’s Go!

All of this can be done without any special tools, but if you’re looking for an app to manage system processes, check out LaunchControl. Anyways, here we go: open up your code editor and create a .plist file in this path:

/Users/stephenkeating/Library/LaunchAgents/

Odds are your user name isn’t the same as mine, so you’ll have to modify the bit after /Users. Also, the Library folder is usually hidden, so go here for help on seeing hidden folders in Finder or Terminal. Title your file something like:

local.gitPullLectureCode.plist

Finally, here is the full code from my plist file (you saw the screenshot above):

Let’s examine the important parts here, one by one.

The Label:

<key>Label</key>
<string>local.gitPullLectureCode</string>

This gives our process a name, so we can identify it when we view all processes either in the terminal or in Activity Monitor. Per convention, names are written in reverse domain notation, with the .local domain for private agents.

The Argument:

<key>ProgramArguments</key>
<array>
<string>git</string>
<string>-C</string>
<string>/Users/stephenkeating/Development/code/lectures/</string>
<string>pull</string>
</array>

Eagle eyes will notice our git command from above, just chopped up a bit. The line you’ll need to modify here is:

/Users/stephenkeating/Development/code/lectures/

This path must be the folder where you have cloned the repo that you want to pull. Test it out by running:

git -C /Users/yourUserName/yourFolder/yourFolder pull

You’ll know you have the right path if you get a message that reads either “Already up to date.” or “Updating…” (not working? no worries. one final github how-to link).

The Log:

You can actually leave this out if you want, but these lines of code create a log that you can check to see how your process is doing:

<key>StandardErrorPath</key>
<string>/tmp/local.gitPullLectureCode.err</string>
<key>StandardOutPath</key>
<string>/tmp/local.gitPullLectureCode.out</string>

The Timer:

This part is spicy and quite customizable:

<key>StartInterval</key>
<integer>60</integer>

Consulting our launchd info, you can see that StartInterval runs the job every n seconds. I’ve set mine to 60. In other words, this script runs in the background every 60 seconds. You could change yours to whatever you want, but since this costs almost zero CPU, I wanted it to run every minute — I need my updates right away! Another option would be to make your script run at particular calendar intervals.

That’s it! If you’ve setup everything properly, your script will automatically be loaded and start running the next time you log in. If you want to start it right away, you can type the following in your terminal:

launchctl load ~/Library/LaunchAgents/local.gitPullLectureCode.plist

You’re done! Enjoy automatic git pulls!

And when the day comes you don’t need these updates anymore, just delete the .plist file. Easy.

Larry David knows whats up.

But wait, there’s more!

Ok, our script is running, git pulls are happening every 60 seconds. Pretty, pretty good. I promised a bonus though.

You see, not only do I want these updates to be done for me, I want to be told when they happen. Let’s use Mac’s folder actions to set up a notification whenever files are added. In Finder, navigate to the local copy of your repo. Right click on the folder name and select Folder Actions Setup. Select Run Service, and add a new item alert. Be sure to enable Folder Actions, and now you’ll see get a notification any time a file or folder is added. Extra spicy. You can always turn these off by right clicking again on the folder name and deleting the action.

--

--

full stack web developer. trying not to get picked last at the pickup 🏀 game // he/him