Stupid Git Tricks #4: Pushing and pulling

You should almost never have to do a push of the form

$ git push origin something:somewhere

This is a good way to accidentally create a branch on the remote that you didn’t mean to, which an admin then has to delete. :-) In fact, it’s precisely how you create a new branch on the remote:

$ git push origin new_branch:new_branch

“But Kate,” you say, “I keep getting annoying messages that look like this when I just run git push:”

warning: You did not specify any refspecs to push, and the current remote
warning: has not configured any push refspecs. The default action in this
warning: case is to push all matching refspecs, that is, all branches
warning: that exist both locally and remotely will be updated.  This may
warning: not necessarily be what you want to happen.
warning:
warning: You can specify what action you want to take in this case, and
warning: avoid seeing this message again, by configuring 'push.default' to:
warning:   'nothing'  : Do not push anything
warning:   'matching' : Push all matching branches (default)
warning:   'tracking' : Push the current branch to whatever it is tracking
warning:   'current'  : Push the current branch

“Why does it do that?”

It does that because, for whatever reason, your config file isn’t set correctly. You can run

$ git config push.default matching

to set the default (back to) what it should be: This pushes all local branches that have a matching “origin/” branch to the remote.

This normally gets set up correctly when you clone a repo, but sometimes it gets confused for one reason or another, so resetting it manually will fix it.


“What if I have a bunch of commits but only want to push one particular branch?”

There’s two ways to do that:

$ git checkout branch-i-want-to-push
$ git push origin HEAD
- or -
$ git push origin branch-i-want-to-push

(Yes, that last one will create the branch on origin if it doesn’t exist there already, so be careful.)


“I tried to do a pull and it said I couldn’t — something about a ‘non-fast-forward merge???’”

This means your local tree is dirty. You should always commit before you do a pull — remember, unlike Subversion or CVS, a commit only affects your local repository, not the remote. If you aren’t sure that you want to commit the current changes, you can

$ git add <whatever you've changed>
$ git stash save
$ git pull
$ git stash pop

See http://schacon.github.com/git/git-stash.html for more on using the stash.


“I tried to do a push and it said I couldn’t — something about a ‘non-fast-forward merge???’”

There are two possible reasons for this:

  • you need to pull
  • you’ve rebased commits that have already been pushed

In the first instance, you just need to pull (and fix any resulting merge conflicts). In the second instance, you are severely screwed: Most remote repositories will not allow you to push something that’s been rebased after being pushed. This is to keep you from rewriting history on the official repository. You need to revert your rebase.

Stupid Git Tricks #3: A few words about merging

Fast-forward merges

There’s a notion that’s actually in all version control systems, but which is more readily apparent in git, namely, the so-called “fast-forward” merge. Charles Duan offers this extremely useful explanation (as part of an excellent git tutorial):

A fast forward merge is a simple optimization for merging. Say your repository looks like this: 
                    +-- (D) -- (E)
                   /            |
    (A) -- (B) -- (C)           |
                   |            |
                current     to-merge
                   |
                  HEAD
and you run git merge to-merge. In this case, all Git needs to do is set current to point to (E). Since (C) is the common ancestor, there are no changes to actually “merge.” Hence, the resulting merged repository looks like:
                    +-- (D) -- (E)
                   /            |
    (A) -- (B) -- (C)           |
                                |
                        to-merge, current
                                     |
                                    HEAD
That is, to-merge and current both point to commit (E), and HEAD still points to current. Note an important difference: no new commit object is created for the merge. Git only shifts the head pointers around.

(emphasis mine)

In other words, the merge doesn’t appear as a merge. This isn’t normally a problem, but when you merge a branch back to master, people often do something like

$ git checkout my_branch
$ git merge master
<-- fix conflicts, etc., if any -->
$ git checkout master
$ git merge my_branch

and that merge back to master (after merging to my_branch) will be a fast-forward merge on master. You can force git to record it as a real merge with the –no-ff flag:

$ git merge --no-ff my_branch

This is useful primarily to have a record that someone actually did a merge at this point, since otherwise that fact is not really recorded in the repo.


Conflicts and “commit -m”

Sometimes when you merge, you have conflicts you have to resolve. This is a fact of life in concurrent development. (It’s also the case that rather than try to implement some tricksy merge algorithm that can solve everything, git will more readily throw its hands up in the metaphorical air and say, “You fix it” than other VCSes.) When you fix the conflicts, git prepares a really handy commit message for you that looks like this:

Merge branch 'master' into testme

* master:
  committed a conflict

Conflicts:
  this-is-a-test
#
# It looks like you may be committing a MERGE.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
#

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch testme

This message records the file(s) that had conflicts. This information can be extremely helpful in the future for finding bad merges. However, if you use git commit -m "some message" this helpful information will be overwritten. So, a helpful hint is, don’t use git commit -m when committing merges.

Apologies

If you visited the site recently you doubtless saw the lovely consequences of some script-kiddie taking advantage of my slackerly ways. My sincere apologies. :-(

I’ve taken steps to further secure the site, and I will also be a bit more active now that various job-related things have been straightened up. Some things to look forward to: Kate learns Gerrit. And Eclipse — and EGit and JGit. Oh fun. Oh, and Jenkins, too. So I will have some pithy things to say as we go along.

Code Review Tools

The problem with blogging is that you have to actually write the blog posts. Instead of blogging, I’ve been spending a lot of my time dealing with an ongoing issue at my current employers — making code reviews easier to do. Of course, it would help immensely if there was actually a good tool to use. Here’s a business opportunity for anyone looking for one! Continue reading

Let the Build Engineer Do It!

I’ve been a build engineer for most of my career, and one of the things I’ve learned is that “build engineer” really means “person who does various support tasks that no one else wants to do.” Most of those tasks are actually at least somewhat related — managing the build systems, of course; running the version control system, OK, makes sense; running the code review server, yeah, sure; running the bug-tracking system, fine, but we’re wandering….; pushing code to production (“You’re the release engineer, right?”) — but once in awhile, you get some really interesting tasks. Like:

1. Buy a safe.

Surprisingly enough, this was actually not that far afield of my job duties, since those did, indeed, include version control. The job involved some pretty high-value secrets, in the form of encryption keys, which were stored on CD-ROMs. Having the CD-ROMs stolen would not be good. Having the CD-ROMs in the Director’s office was probably not secure enough. Hence, I was tasked with speccing out and purchasing a fire-resistant safe to store them in. (This also happened to provide a convenient place to store backups of the source code repository.)

Buying a safe turns out to be an interesting exercise, by the way. The one I settled on weighed about 500 pounds and was bolted to the floor, to boot, in the name of making it difficult to carry away. It was also installed in a very small, very obscure room (a real room, though; it had a network drop!), where it kept company with a covert code repo that held some similarly valuable bits of information. Only about four people had access to the repo, the room, and the safe. (Backups of the repo were kept in the safe.) I’m sure it’s still there; I hope if the team moves out of the building that they remember to take it with them!

2. Run a Jabber server.

Nope, I don’t know what that had to do with builds, either. I think it was mostly, “Kate has a server room! Let’s get Kate to do it!” (Same place, by the way.)

3. Rewrite large chunks of Bugzilla.

Never mind that there were available bug-tracking systems that fit our model much better than Bugzilla did. They cost money! Well … yes, but I’m pretty sure it cost more for me to (1) decipher 20,000 lines of mostly uncommented Perl*, (2) learn JavaScript and how to integrate it with the aforementioned Perl, and (3) then actually code and test the whole thing, as opposed to simply buying a system that would actually do what we wanted.

* This was a decade ago. I’m sure it’s better now.

4. Rabbit wrangler.

OK, this is cheating, slightly — I volunteered for this — but I do still have some business cards that list my title as “Build Manager and Rabbit Wrangler.” Her name was Rover, may she rest in peace.

5. Break into locked pdf files.

I can’t go into the gory details for legal reasons, but I once was asked to try to unlock some password-protected pdf files. (Briefly, we had full legal rights to the contents and were being prevented from using it.) Fortunately for me — I’m not much of a cracker — I was able to actually guess two out of three of them. People use the dumbest passwords, seriously. If you’re going to try to blackmail your company, choose better passwords!

If you’re a build engineer: What’s the most tangential-to-your-job or just downright weird thing you’ve been asked to do?

Jobs I Won’t Be Applying For

Right up front: I am not currently in the market for a job!!

The job market for good, experienced build engineers is really great, for the simple reason that good, experienced build engineers are really rare. (Hint: If you’re looking for job security, become a build engineer.) So as you might imagine, I get a lot of inquiries from headhunters. Some of these are interesting enough to warrant at least a glance, but there are three kinds I’ve seen recently that I just toss.

1. The Six-Month Build Engineer Contract

Seriously, who hires a build engineer on a six-month contract? Truthfully, I think these come about because it’s so easy to find people who claim to be build engineers and so hard to find ones who really are. But I’m baffled by the fact that these are rarely “contract-to-hire” positions, which suggests that these really aren’t permanent positions — so, what do you do with a build engineer on a six-month contract?

2. The Build-and-Merge Engineer

I saw this recently from a startup, and I shuddered. Merging code is hard. You want the person who merges the code to be someone who is intimately familiar with the code. (Otherwise, a machine could do it.) I believe that this is true even in the case of this position, which wanted the build/merge engineer to be responsible for merging in code pulled from upstream (presumably open-source) repositories. While I don’t doubt that they can find someone to take this on, it suggests a seriously poorly-thought-out process to me. Thanks, but I’ll pass.

3. The Build-and-QA Engineer

This is one I see frequently from startups. It’s understandable, but short-sighted — there’s plenty for a good build engineer to do to keep them occupied. (OK, I have been known to automate myself out of a job, but that was at a company that was failing.) More to the point, while I’ve done QA — and I can still break anything within 10 minutes of installing it — I’m first and foremost a build engineer for a reason: I like build engineering more than QA. Testers test, coders code, and build engineers go around whacking people over the head when they don’t follow the processes.

My Favorite Things, Part 1: Pulse

(This is the first in a series of posts about the tools I use currently and why I chose them.)

When I started at my current company, the first task I was given was to set up an automated continuous build/integration server. Having written one myself in the past, and fooled around with early versions of Tinderbox, I decided to see if anything good was available or if I was going to have to roll my own. After hunting around with Google for awhile, I came up with some reasonable candidates for further investigation:

CruiseControl
Hudson
Bamboo
Pulse
Anthill Pro
Continue reading

Stupid Git Tricks 2

Some handy information and tips about Git branching

• Tracking branches:

“I just cloned a repository and all I see is ‘master’ — but there are many other branches in this repository, and I need to work on one. Help!”

git branch -a

iz ur frend.

When you clone a repository, it creates a local tracking branch for ‘master’ and checks that out. You do have copies of all of the remote’s branches in your clone, but there aren’t any local tracking branches (which you can modify) until you explicitly create them. (The very simple reason for this is that many repos have a lot of branches, e.g., we have one that has, um, 240 at the moment, and you really don’t need local tracking branches for all of them.)

To create a local branch that tracks the remote branch origin/foo-branch:

$ git checkout -b foo-branch origin/foo-branch 
- or -
$ git branch -b foo-branch origin/foo-branch
$ git checkout foo-branch 

Note that the local name doesn’t have to be ‘foo-branch’, but it will probably be better for your brain if it is.

Can I set up local tracking branches for all of the remote branches?”

Sure, if you really want to.

$ for b in $(git branch -r | grep -v HEAD | xargs basename); do
> git branch $b origin/$b
> done

Purely local branches:

You can create a purely local branch, that is, one in which you can work without messing up any of the “real” branches on the central repo. If you want it to branch from the head (that’s lower-case ‘head’) of the current branch you have checked out, you just

$ git branch my-new-branch-name
- or -
$ git checkout -b my-new-branch-name

depending on whether or not you want to immediately start working there.

If you want to create a branch that starts at a specific tag or commit,

$ git branch my-new-branch-name <commit-ref>

where <commit-ref> can be a branch name, a SHA1, a tag, or anything else that Git can resolve to a commit.

• Local branch -> new remote branch

If you need to take a local branch you created and actually make it publicly available, you need to push it specially:

$ git push origin local_branch_name:remote_branch_name

Note that the names don’t have to be the same. Also note that this doesn’t actually make local_branch_name a tracking branch of remote_branch_name, for some strange reason. You have to do this:

$ git config branch.<branchname>.remote origin
$ git config branch.<branchname>.merge refs/heads/<branchname>

There’s actually a handy-dandy script called “git-publish” that automates this; drop it into /usr/local/libexec/git-core (on Macs and Linux boxes; sadly, it’s a shell script so may not be adaptable to Windows) and you can then do this:

$ git publish local_branch_name origin

Even better, if you are using git 1.7.0 or later, you can just do this:

$ git branch --set-upstream <branchname> origin/<branchname>

• Forgot which remote branch is being tracked by a local branch?

git config branch.<branchname>.remote

will tell you what branch is being tracked.