Eric / NYC / Milky Way

Visual

Blog Index

Random 5

Stripe and Tap

Multi-tab Websockets

Ruby vs. Ruby

Cookies

Web Accounts

Emoji Bits

Honeypot Bots

Bad Content

JS Data Chutzpah

Sendgrid Ban

Clean URLs

Git

Concerns

Rails UJS

Extending Devise

ENV Variables

See All

Little Git

May 2020

A Beginner’s Git reference

Reading technical documentation is sometimes boring, but reading Git documentation is always boring.

With that said, here’s a post about Git.

Big Picture

$ git status

Unlike much of Git, this command is crystal clear . We’ll see if any files have been updated, added, deleted, staged, committed, etc. This is a good place to start a work session.

$ git branch -a

Show me all the branches that exist for the project, both local and remote. Also, show me what branch I’m on! Ommitting the -a flag will only show local branches.

These first couple commands only provide information — they don’t affect your repo in any way — this is a relief! You can run these commands 500 times without a worry.

First complication

It turns out git branch -a is sometimes outdated, so we need to prune things every now and again. This command removes all outdated remote branches.

$ git fetch --prune

Our view of the remote branches becomes outdated when a remote branch is deleted — Git won’t automatically update your local reflection of deleted remote branches.

Depending on your git flow, remote branches may get deleted quite often, especially when closing Pull Requests on Github, so this command may feel a bit tedious.

The good news is that we can change our local config to auto-prune on every pull.

$ git config --global fetch.prune true

Deleting Branches

Remote

$ git push —d origin remote_branch_to_delete

That’s how we’d do it from our terminal (there are other variations), but as mentioned earlier, it’s likely that we’ll be deleting remote branches via Github’s Pull Request GUI on their website.

Once we delete remote branches, it probably makes sense to delete their associated local branches. Deleting fully merged local branches (or remote) is okay because Git has a long, long memory, and we can google how to revert if need be.

Local

$ git branch -d local_branch_name

The above command works if local_branch_name has been merged somewhere, but if it hasn’t, Git will complain, afraid that you might lose commits.

Perhaps this was just a test branch, and you don’t mind losing commits. The big -D flag should take care of that.

$ git branch -D local_branch_name

Basics

Let’s get back to the basics — 98% of Git involves simple commands like staging, committing, pushing, and traversing branches.

We made some changes to our code and we’re thinking it might be time to add some files into the staging area. Before we stage our files, it can be helpful to see what’s changed since our last commit. (Note that this is totally optional.)

$ git diff

This will likely fill our terminal window with text, some lines preceded with + and others with -. I think we can guess which lines have been added and which removed.

LESS

There’s often so much text that the diff wants to print that it will overflow the terminal window viewable height. Just to complicate matters, our Terminal will display the results using something called LESS which is what’s a terminal pager program.

If you haven’t seen this before, you might feel stuck. Scrolling with your mouse or touchpad has suddenly stopped working. There is nowhere to type our next command.

Luckily, typing q will restore sanity — which I’m guessing is short for Quit.

So what is LESS? It’s basically a way to turn a long block of text into a PowerPoint, in your terminal window. Text is suddenly only viewable by page. Pressing the spacebar will move you to the next page. Using the down/up arrows will just move us 1 line at a time.

Of course there are a million commands, but all we have to remember is q and spacebar.

Alternatively, if we want to avoid this situation, we can run

$ git --no-pager diff

which will print the log without LESS — meaning no pagination.

Branch Check

Ok so we’re happy with what we saw on our git diff. Before staging, let’s double check that we’re on the correct branch.

git branch will tell us, or perhaps we set up a persistent branch label in our terminal (skip ahead to Terminal Settings at the end for more info).

If we’re on the wrong branch, we can still checkout the correct branch without much trouble. Our unstaged changes will be carried with us.

If we proceed with staging to the wrong branch, we’ll have to mess around with un-doing things, which can get complicated.

Staging

Now we want to stage these files, which is just a temporary step to collect ourselves before we commit these changes to the record.

There are a couple flags worth remembering:

Stage all files that have been added or updated:

$ git add .

All files that have been added, updated, or deleted:

$ git add -A

An individual file:

$ git add filename

though I don’t stage individual files often, so I’m not sure why I’m mentioning it. To that point, here are the official git docs if you want serious, trustworthy Git information.

Committing

Our files are staged, and we think we’re ready to commit them. This is probably the most important command in Git!

This is the proverbial snapshot of our files, at this moment in time. We can come back and visit whenever, forever.

One quick side note before committing — perhaps we forgot to run a git diff before staging. If we want to check the diff at this point, we have to say git diff --staged because we want to see the difference between our staged files and the previous commit.

Ok, now we’re ready to commit:

$ git commit -m 'my commit message here'

Messages are mandatory for commits, and sometimes this interaction is a pain - especially if you want to write a longer commit message.

One solution is to omit the -m ‘my message’ flag, and your terminal will open its default text editor - which in my case was Vim, inside of the terminal.

Personally, I don’t enjoy feeling trapped in a text editor, so here’s how you can change your terminal’s default text editor:

$ git config --global core.editor "atom --wait"

Now, every time you git commit (without the -m flag), Atom will open up a new text file in Atom, giving you a bit more breathing room. Saving and closing the file completes the commit.

The —-wait flag is important, or else the commit will fail before you get a chance to write your message.

Logs

We’ve made some commits, and we’re thinking about pushing to a remote repository. Maybe it’s been a few hours, or even a few days. Might make sense to take a brief look back at the commit history.

$ git log -1 shows us our last commit.

$ git log -5 shows us our last 5 commits.

$ git log shows us way too many commits, and we’re back in that LESS paradise we talked about earlier.

We can also specify a date range, if that’s easier, but I’ve found just asking for the last X commits to be simplest.

Sharing

We’ve collected some local commits, and we’re to share our changes with the bigger project. There are a variety of ways that happens — we’ll just talk about 2: merging and pushing.

Merging

Merging is good if we just want to share our updates locally, without worrying about what’s happening on remote yet.

First we want to check out our destination branch (where we want to merge into).

$ git checkout master

Then we can merge into master with the branch we were working on.

$ git merge branch_we_were_working_on

Pushing

We’re ready to share our local code with remote.

And we’ve already connected our local repo to the remote repo on Github (if we haven’t Github will explain how to do this).

$ git push

If it’s the first attempt at pushing to a remote, you’ll get an error saying that the upstream branch hasn’t been set. And your terminal will provide you the command you need.

$ git push --set-upstream origin my_branch_name

From then on, simple git push should do the trick.

Remote Comparisons

Now that our code’s sitting in a remote branch somewhere, we can employ new methods of comparing our code.

Instead of comparing our code to previous commits like we did with git diff, we’ll probably want to compare our code with other remote branches, as a merge is likely in our future.

Github’s web interface has a couple of nice options. If we aren’t ready to create a Pull Request, we can Compare our remote branch to another branch. If we’re ready for the Pull Request, there’s a useful interface to see how things compare, and if there are conflicts.

Pulling

We’re probably a bit late in mentioning this, but the ying to the push yang is pull.

When a collaborator pushes something to a remote branch, we’ll need to pull those changes to see them locally.

$ git pull

The above will work for individual local branches that track remote branches. In other words, make sure you have the my_feature local branch checked out if you want to pull from the my_feature remote.

One caveat is that we want to make sure that we’re fully committed before doing this, as the inner-workings of a git pull involve a merge, since the new remote code is merging with our local stuff.

A nice side effect of git pull is that we’ll see any new remote branches that have been created, although their contents won’t be automatically pulled to our local system.

If we just want to pull the contents of one of these new remote branches, we just need to check out the local version, and then run a git pull.

Branching

So far we’ve talked about moving around branches, but haven’t looked at how to switch to a different local branch:

$ git checkout existing_branch_name

If we want to create a branch, and immediately switch to it:

$ git checkout -b new_branch_name

This will copy the code from the originating branch.

Totally Optional Stuff:

Aliases

For repeatable tasks, it’s useful to shorten them as much as possible. Git is chock-full of repeatable tasks, so we can set up something called Git Aliases.

Now, if this at all introduces confusion, we shouldn’t do it, because clarity is far more important than brevity.

With that said, let’s set up some aliases. Instead of typing git commit over and over again, let’s just type git c

$ git config --global alias.c commit

And a few others we can shorten as well:

$ git config --global alias.st status
$ git config --global alias.b branch
$ git config --global alias.ch checkout

To see all the configs that have been set:

git config --list

Or we can peak in our .gitconfig file that lives in our home user directory (just need to show hidden files).

Terminal settings

It would be nice if we didn’t have to git branch, or with our alias git b, every time we need to be reminded of which branch we’re on. The good news is that there is a way. The bad news is that it requires tracking down your system’s .bash_profile file and editing it.

You can do this in the terminal, or you can update your Mac to show hidden files (files that start with .), and look in your root directory in finder. Opening .bash_profile is just like opening a text file, and we want to add this code in there:

parse_git_branch() {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}

export PS1="\u@\h \W\[\033[32m\]\$(parse_git_branch)\[\033[00m\] $ "

This little hack came from here

Conclusion

This is the end for now. Hope it wasn’t too boring 🙃