This post is from the CollabNet VersionOne blog and has not been updated since the original publish date.
Tips on Git: De-fanging ‘Git Push’
Ever had Git commit a branch you didn’t intend?
% git co branch-1
% (workee workee workee)
% git ci -am”Half the change of the primary task”
% git co branch-2
% (workee workee workee)
% git ci -am”The whole change of the interrupt
% git push
babble babble babble
9e7f6d7..35935af branch-1 -> branch-1
ccb352f..66c8c36 branch-2 -> branch-2
Oh no! Not branch1! It’s not finished yet!!!
What Git has just done is technically called “push by matching”: any branches in your repo that have names matching branches in the origin repo get pushed.
The confusing thing here is that some Git commands operate on just the files you have checked out, but others operate on the whole repository. This is particularly confusing (and can be particularly unfortunate) because the very common “checkout,” “pull,” and “commit” commands all operate on “just the checkouts,” but the also very common “push” command is “whole-repository.”
There are reasons for this, some of them good, and with enough practice you can get used to it, and soon you, too, can blithely call stuff like this “the simplest option”:
But if you’d like your “simplest options” a bit simpler, or maybe if you think it’s the job of the tool to accommodate the user, not vice versa, then you’re in luck: after a lot of discussion, the git developers have come around to your way of thinking! Git is now being changed to do, by default, what you meant all along.
Since Git was originally released with different behavior — and, indeed, since the original behavior actually does make sense for some users and situations — the conversion process is rather gradual. With any version of Git after 1.6.3, there’s a new configuration option to control this behavior, and some new messages that hopefully lead you to a resolution. The configuration options are:
Before git version 1.6.3: there are no options, git push does ‘matching’
Beginning in version 1.6.3: You have your choice of nothing, matching (the default), tracking (recommended), or current
Beginning in version 126.96.36.199: nothing, matching (default), upstream (recommended), tracking (deprecated), or current
Beginning in version 1.7.11: nothing, matching (default), upstream (recommended #1), simple (recommended #2), or current
Beginning in version 2.0: nothing, matching, upstream, simple (default, recommended), or current
What do those options mean?
nothing: Don’t do anything for “git push”; make the user explicitly say what they want pushed
matching: Do that branch-name-matching trick
tracking (later renamed to upstream): push the current branch to its upstream branch
simple: like upstream, but only if the local and upstream branches have the same name
current: push the current branch to a central branch of the same name (even if they aren’t marked as tracking/upstream)
Which do you use? Most likely either “matching” or “simple”:
If you like the “all branches with matching names” behavior, do “git config –global push.default matching”, and you’ll safely keep doing that even when you upgrade to git version 2.0 (which will have a different default).
If you want to begin living in the brave new world of 2.0, do “git config –global push.default simple”. If you get the error “error: Malformed value for push.default: simple”, your Git is kinda old. The best thing would be to upgrade Git, if you can; otherwise use “upstream” (or even, if you still get the error, “tracking”).
Personally, I’m a simple guy, and “push.default simple” is just what I need. I’m delighted that the community now sees things my way, and I’ve already set this default.
How about you? If you prefer one of the other options, can you explain why? It would be particularly interesting if you can (concisely!) describe a situation that really demands one of the other behaviors. Sound off below.