Committed to the wrong branch? -, @{upstream}, and @{-1} to the rescue
Last Updated
A version of this article appeared on viget.com
I get into this situation sometimes. Maybe you do too. I merge feature work into a branch used to collect features, and then continue development but on that branch instead of back on the feature branch
and have to move those commits to the feature branch they belong in and take them out of the throwaway accumulator branch. For example
That works. But it’d be nicer if we didn’t have to type or even remember the branches’ names and the remote’s name. They are what is keeping this from being a context-independent string of commands you run any time this mistake happens. That’s what we’re going to solve here.
Shorthands for longevity
I like to use all possible natively supported shorthands. There are two broad motivations for that.
- Fingers have a limited number of movements in them. Save as many as possible for later in life.
- Current research suggests that multitasking has detrimental effects on memory. Development tends to be very heavy on multitasking. Maybe relieving some of the pressure on quick-access short term memory (like knowing all relevant branch names) add up to leave a healthier memory down the line.
First up for our scenario: the -
shorthand, which refers to the previously checked out branch. There are a few places we can’t use it, but it helps a lot: (🎉 marks wins from -
)
That’s as far as -
gets us. We cannot use it when cherry-picking a range
and even if we could we’d still have provide the remote’s name (here, origin
).
And doesn’t apply in the later reset --hard
command. And we cannot use it in the branch -D && checkout
approach either, since branch -D
does not support the -
shorthand and once the branch is deleted checkout
can’t reach it with -
:
So we have to remember the remote’s name (we know it’s origin
because we are devoting memory space to knowing that this isn’t one of those times it’s something else), the remote tracking branch’s name, the local branch’s name, and we’re typing those all out. No good! Let’s figure out some more shorthands.
@{-} is hard to say but easy to fall in love with
We can do a little better by using @{-<n>}
(you’ll also sometimes see it referred to be the older @{-N}
). It is a special construct for referring to the nth previously checked out ref.
Back in our scenario, we’re on qa-environment
, we switch to feature
, and then want to refer to qa-environment
. That’s @{-1}
! So instead of
We can do
Here’s where we are
Do @{u} @
One down, two to go: we’re still relying on memory for the remote’s name and the remote branch’s name, and we’re still typing both out in full. Can we replace those with generic shorthands?
@{-1}
is the ref itself, not the ref’s name, we can’t do
because there is no branch origin/@{-1}
. For the same reason, @{-1}
does not give us a generalized shorthand for the scenario’s later git reset --hard origin/qa-environment
command.
But good news!
@{upstream}
or its shorthand @{u}
is the remote branch a that would be pulled from if git pull
were run. @{push}
is the remote branch that would be pushed to if git push
was run.
we can
Tacking either onto a branch name will give that branch’s @{upstream}
or @{push}
. For example
is the branch branch-a
pulls from.
In the common workflow where a branch pulls from and pushes to the same branch, @{upstream}
and @{push}
will be the same, leaving @{u}
as preferable for its terseness. @{push}
shines in triangular workflows where you pull from one remote and push to another (see the external links below).
Going back to our scenario, it means short, portable commands with a minimum human memory footprint.
Make the things you repeat the easiest to do
Because these commands are generalized, we can run some series of them once, maybe
or
and then those will be in the shell history just waiting to be retrieved and run again the next time, whether with CtrlR incremental search, or history substring searching bound to the up arrow, or however your interactive shell is configured. Or make it an alias, or even better an abbreviation if your interactive shell supports them. Save the body wear and tear, give memory a break, and level up in Git.
And keep going
The GitHub blog has a good primer on triangular workflows and how they can polish your process of contributing to external projects.
The FreeBSD Wiki has a more in-depth article on triangular workflow process (though it doesn’t know about @{push}
and @{upstream}
).
The construct @{-<n>}
and the suffixes @{push}
and @{upstream}
are all part of the gitrevisions spec. Direct links to each:
Articles You Might Enjoy
-
-
Hometown: A Dynamic, Highly Configurable Git-Focused Zsh Theme
A fast zsh prompt that packs in a lot of Git status info
-
Git Prompt Kit: Configurable, Fast Git Status Components For Custom Zsh Themes
A collection of components for displaying Git information in your prompt