Notes on Go, part 6 of ∞

To deal with the idiosyncratic failing test issues from my last go post, I got to do a bunch of stuff with our monorepo and learn a bit more about the Godep tool, and now I know more about why the stuff at the end of this post works.

The solution to my problem was to update the version of sqlmock that I was using. One of the potential issues with monorepos is that if you update a package, you have to update it across the entire monorepo, because of how Go dependencies work. One solution to this problem is to make whoever wants to change versions do all the updates across the repo. Another (less ‘Go’) solution is to have two versions of the dependency in your project. Which is what we did.

It took me a few tries to get everything down in a way that made both Godep and git happy, so here is my recommendation on the order of steps to take.

  1. Checkout your master branch and make sure it is up to date.

  2. Make sure your local Godeps/_workspace is up to date by running the godep restore command. I think this is the one I was having the most trouble with, because ‘restore’ is not what I think I want to do, conceptually. The restore command is (I think) making your local Godep/_workspace match what is in the Godep.json file. So if you’ve messed added ore removed a whole bunch of stuff, and want to start over, the ‘restore’ command is an accurate reflection of what you are doing, but it also works as an ‘update’, which is conceptually what I thought I wanted to do.

  3. Check your git status and make sure you don’t see anything unexpected. In my case, I didn’t expect to see really anything in my status because our Godep folder is checked into git.

  4. If you haven’t already, do a godep get PACKAGE/I/WANT.

  5. Update the import statement(s) in your actual *.go file(s).

  6. To save this into your dependencies, use godep save -r ./.... The -r flag takes care of re-writing any import statements to now point to your Godep/_workspace folder. The ./... makes sure it checks the current folder and all folders inside of it to catch any new imports.

  7. Again, check your git diff. At this point, I expected to see:

– the import changes
– the new package in Godep/_workspace

If it all looks good, commit!

  1. If this update was a breaking version change, now go back and fix your code that it compiles and runs again.

  2. Finish the thing that sent you down this rabbit hole in the first place!

Tips and Tricks: Intermediate Git configuration

There are several ‘levels’ at which you can configure git. The three I know about are:

  • repository-level
  • repository branch-level
  • global

They are slightly self explanatory.

  • repository branch-level means that the configurations/aliases are applied ONLY to a specific branch in that repository. I haven’t had a need to use this one yet, so I can’t tell you a ton about it.
  • repository-level means that the configurations/aliases are applied ONLY to that repository, but to all branches on that repository. This can be configured to use different email addresses to different projects (ex: work email vs personal email), among other things.
  • global means that the configurations/aliases are applied to ALL git repositories on your system.

So, how do we set this up?

From the command line

Most of the tutorials on how to set up aliases give the command line version.

In your git repository, you can type git config XXX (where XXX is filler for whatever configuration you want to set). To set the configurations globally, you can type git config --global XXX. Adding the --global flag sets it for all git repositories. Some examples:

git config --global user.name "Clare Glinka"
– This sets my name as “Clare Glinka” for all repos.

git config --global user.email myemail@example.com
– This sets my email as myemail@example.com for all repos.

git config merge.ff false
– disables fast-forward merges by default at the repository level. Fast-forward merging will be disabled for all branches in that repo. Adding the --global flag will disable fast-forward merging for ALL repos.

You can check out other configuration settings in the Git documentation on customizing your git configuration and the git-config manual page.

Now that we’ve set some configs, how do we look at them? (because nothing is real till we see the output, right?)

git config --list will list all the configuration settings for your current directory/branch, including things like your remotes.

git config --list --global will list all the configurations settings for your system. For me, this is a much shorter list, since it does not include things like remotes.

Edit .gitconfig

There is another way to set configurations that I find a little easier to look at sometimes. That is checking out the .gitconfig file. For your global settings, .gitconfig lives in your ~ directory, and you can open it up and edit it with your favorite text editor. You can check out your repository-level configuration file by looking at REPO/.git/config.

References

First-Time Git Setup
Customizing Git Configuration
git-config Manual Page
StackOverflow: Can I make fast forwarding be off by default in git?
Git Tip: git config user name and email for local (not global) config

Free private remote git repos

If you want a remote backup of your private git repos, a la Github but free, there are 3 options I know of.

  1. BitBucket. Has unlimited free private repos, but sets limits on the number of collaborators. Also lacks issue tracking.

  2. GitLab. Has unlimited free private repos, WITH free issue tracking that is very similar to how Github works.

  3. DIY. Host it yourself! Except you have to pay for hosting. So there’s that.

I’m using GitLab for my Ultra Top Secret projects right now. So far so good! Their interface is a little rougher than GitHub, but more than workable.

Git: Working With Remote Repositories

In an earlier post, I covered how to add and remove remote repositories. Now that we’ve told our local git repo where all these remotes are, now what?

Push

We want to share all the changes we’ve made on our project with our collaborators. Or we just want a backup incase our computer catches fire. The next step is to push the changes we’ve made to our remote repo. The push command is pretty safe and it is pretty hard to mess anything up by using it.

Here is the general outline of the command:

git push <alias>

Typically, we will just be pushing to origin, the default remote repository:

git push origin

Sometimes, when we have multiple branches, we might need to specify which branch we want to push to the remote:

git push origin master

And actually, this formula can be generalized as:

git push <alias> <branch name>

With this, we can push to any remote (that we are authorized to access) and specify any branch we like!

Fetch

Our collaborators have been hard at work! We want to update our local repo with the changes they’ve pushed to our shared remote. If we want to download all of the changes, but not merge them into your files just yet, we want to use the ‘fetch’ command. This is the ‘safer’ command, because we can check on the changes before merging them into our own files.

If we only have one remote:

git fetch

If we have more than one remote:

git fetch <alias>

If we want to download from all remotes:

git fetch --all

Now we have all of our changes from the remote on our local machine, but our local files haven’t been updated yet.

I like to take a look at what git thinks is happening.

git diff <branch-name> <remote-alias>/<branch-name>

This should show us the changes that will be made to our files. Assuming everything looks about right, it’s time to merge.

Check we are on the correct branch:

git branch

Then merge:

git merge <remote-alias>/<branch-name>

Pull

Sometimes referred to as a ‘fast forward’, the ‘pull’ command does a ‘fetch’ and a ‘merge’ all in one command. I think of this as THE DANGER ZONE. Sometimes, it is exactly what I want, like when I am the only one making commits to a branch or repo, or I know that I want to merge all the changes in the remote with my own local changes. If this is the case, the pull command makes getting updates from the remote really easy.

git pull <alias> <branch-name>

And we’re done!

 

Other Resources:

  • I found this blog post on git fetch vs git pull to be very helpful. Spoiler: git fetch is the way to go!
  • As always, obsessively reading the documentation on push, fetch, and pull was really helpful.
  • And many thanks go Jeff Felchner for giving a talk at MakerSquare on using Git beyond the basics! Remember kids, NO FORCE PUSH!

Git: Adding Remote Repositories

Git and version control are some of the wierdest and funnest things I’ve been introduced to. I love the idea of taking continuous snapshots of the small steps of my work, and then being able to sift through them and pick the ones I want. I think I’m still at a fairly basic level, but within that context, I’ve learned so much!

Remote Repositories

Remote repositories are basically copies of your git repo that are not stored on your hard drive. This seems kind of obvious, but didn’t really click for me until I learned that you could have as many remote repositories (remotes, for short) as you want!

Step 1: Take a look at the remote repositories you already have.

git remote -v

You will see a list that looks something like this:

origin https://github.com/cglinka/urdb-1.git (fetch)
origin https://github.com/cglinka/urdb-1.git (push)

Or like this, if you have multiple remotes already set:

mks https://github.com/makersquare/urdb.git (fetch)
mks https://github.com/makersquare/urdb.git (push)
origin https://github.com/cglinka/urdb-1.git (fetch)
origin https://github.com/cglinka/urdb-1.git (push)

You can see the remote name (or ‘alias’, if you want to get technical about it) followed by the URL that actually describes the location of each remote repository.

All of my remotes are on GitHub, but you can have remotes on other servers, or so I’m told. I have not tried to set up my own git server yet. :D

NOTE: The repo you clone from and/or the first remote you add will by default be called your origin. So when you are reading tips and tricks about Git, origin is just your ‘default’ remote alias, which may or may not be true for your particular repo. This may or may not cause a lot of confusion and/or frustration, but checking your remote names/aliases will save you a lot of troubleshooting time.

Step 2: Add a new remote.

git remote add <ALIAS> <url>

Fill in ALIAS with the name you want to use to access that remote. You can’t use origin if you already have an origin assigned. I try and give them easy-to-remember names based on the GitHub username. For the last several weeks, we’ve been working on the same repos in class, with new branches every day for that day’s lesson. Instead of making a million folders with a million copies of the same repo, I added a second remote as ‘mks’ that pointed to the correct repo on the makersquare account so I could just update my local copy of the repo every day! I added a third remote that pointed to my partner’s repo of the same assignment.

Step 3: But I want to change the remote that origin points to!

It’s cool, you can do that! First, remove the current origin:

git remote rm origin

Then, check make sure you removed the origin:

git remote -v

Last, add the new origin;

git remote add origin <URL>

And just to be sure, check your remotes again:

git remote -v

Ta-dah! New origin added!

Git Tricks: git diff

I think one of the first things you learn in git is the

git diff

command. This one is really important for me, because I forget exactly what I’ve changed since I last committed. But sometimes, I forget to run

git diff

before I add my files to the staging area. Whoops!

 

I feel like I should have figured this out sooner (that’s how learning works, right? obvious once you know it), but there is a very nice command that fixes this problem for me!

git diff --cached

show the git diff for files I’ve already staged! Huzzah! My commit messages will never be a series of “Ummmmm, I don’t remember what I just did.”

Github repo confusion

Last week, I accidentally cloned down the wrong repo from GitHub. Whoops! I forked the repo for one of our class assignments, but I grabbed the URL for the MakerSquare repo, not mine. Fortunately, there was Google to the rescue!

Turns out, this is actually a little bit easy, though I read through the first 5 or so google search results before I did anything. This blog post was the most helpful because the commands were explained very nicely. It probably also helped that it was the 4th or so thing I read, so I was beginning to understand what I needed to do.

I did the following:

1. Check the current remote to make sure it is actually what I think it is

git origin -v

2. Remove the current origin

git remote rm origin

3. Add the new (correct!) origin

git remote add origin https://github.com/my_username/correct_repo.git

And tah-dah! All fixed! And in even nicer news, there is actually an even easier way of doing this that might be newer than said blog post. On GitHub Help, there is some information about using

git remote set-url

to do the same thing as the above step 3 and allows you to skip step 2 entirely.

Since this was an early mistake in a very simple single-branch repo, I didn’t have to take any other steps to make sure the HEAD was in the right spot or that any changes were correctly synced.