I’ve collected a treasure trove of git tricks over the years, the vast majority coming from raw necessity (and a few that were just technically neat). As I’ve started work at Hacker Noon as a Full Stack Developer, I’ve shared quite a few of these tips with the team, and I’d like to share some of them with you.
This isn’t really a git problem, but I’ll answer it anyway, because git has a power tool for not screwing things up: branches. Branches are dirt cheap. Create as many as you need. If you think you’re going to screw up, branch off of your current branch, branching strategies be damned. Branching strategies are for the shared repo (Github, etc.), not your local repo — just don’t push the branches, and you’re golden. I’ll write more about branching strategies, including the flow we use here at Hacker Noon, in a future post.
The solution to this issue very much depends on whether you’ve pushed. If you have pushed, you might be screwed — skip the next paragraph to see why.
Let’s start with the simple case. If you haven’t pushed, no problem: this guide will walk you through the cherry-picking process. In a nutshell: just switch to the branch you want to commit to, and git cherry-pick $COMMIT_HASH. If you haven’t pushed, there’s a simple command you can run to delete the accidental commit. However, this command can break things. Only run it if you’re absolutely sure you can safely delete the last commit. To do this, run git reset — hard HEAD~1 on the branch you accidentally committed to.
So, how can you be absolutely sure you can safely delete your accidental commit? If you have pushed, like I said, you might be screwed. If anyone else is working on that branch, there’s nothing you can do. You can’t just rewrite history on them, after all.
That said, if you’re really sure that it won’t mess up anyone else’s work (e.g. you’re the only one working on a branch), you can run the reset above then use another dangerous command, a “force push”, to get rid of the commit. Beware! If you force-push a branch that others are working on, you’ll have different revisions on different machines, and work can be lost. This is not a good scenario.
If you’re sure, you can git push -f origin $BRANCH to force-push your branch.
The solution here is twofold: you’ll want to install tab completion for git, and there’s a neat trick for referring to the branch when pushing. For the first part, you’ll want something like oh my zsh for tab completion. As for the second part, there’s a simple shortcut I like to use. Simply git push -u origin HEAD and you’re good to go!
From then on, you can just git push and everything will “just work”. Please note, that -u switch sets the origin remote as the upstream source for that branch. Essentially, that just means that origin will be the default remote source for git pull and git push.
A related tip: you can use git checkout — to check out the last branch you were on. This is great if you need to check out a branch that a teammate’s working on, and want to switch back and forth between branches.
I hate to tell you this, but: it’s time to learn git internals. But fear not! Git isn’t that hard to learn — at its core, it’s actually a simple set of commands on top of a relatively simple data structure. It’s just a power tool — you can use it in crazy ways, because the authors decided to give you that ability. It was designed for a lot of different use cases, so specific use cases like cherry-picking from an accidentally-committed branch are not front-and-center.
I can’t explain it nearly as well as Scott Chacon did in his book, Git Internals, which is generously available for free online. Please, read that book, and I guarantee you’ll walk away with a better understanding of git.
This has a quick and useful solution: git aliases. You can configure an alias with something like git config — global alias.ci commit, then you can write git ci to run git commit.
I don’t know everything about git, by any stretch, but hopefully this helped. Do you have any git protips to share?