On today’s issue of “one hour hacks”, I’ll show you how you can stop your git drive-by’s to git master from breaking your CI tests… Let’s continue!
The problem:
Sometimes I’ve got a shitty one-line patch that I want to push to git master
. I’m usually right, and everything tests out fine, but usually isn’t always, and then I look silly while I frantically try to fix git master
on a project that I maintain. Let’s use tools to hide our human flaws!
How you’re really supposed to do it:
Good hackers know that you’re supposed to:
- checkout a new feature branch for your patch
checkout -b feat/foo
- write the patch and commit it
git add -p && git commit -m 'my foo'
- push that branch up to origin
git push origin feat/foo
- wait for the tests to succeed
hub ci-status && sleep 1m && ...
- merge and push to git master
git checkout master && git merge feat/foo && git push
- delete your local branch
git branch -d feat/foo
- delete the remote branch
git push origin :feat/foo
- mourn all the lost time it took to push this patch
cat && drink && sleep 8h
If it happens to fail, you have to remember what the safe git reset
command is, and then you have to start all over!
How do we make this easy?
I write tools, so I sat down and wrote a cheap little bash script to do it for me! Sharing is caring, so please enjoy a copy!
How does it work?
It actually just does all of the above for you automatically, and it automatically cleans up all of the temporary branches when it’s done! Here are two example runs to help show you the tool in action:
A failure scenario:
Here I add a patch with some trailing whitespace, which will easily get caught by the automatic test suite. You’ll note that I actually had to force the commit locally with git commit -n
, because the pre-commit
hook actually caught this first. You could extend this script to run your test suite locally before you push the patch, but that defeats the idea of a drive-by.
james@computer:~/code/mgmt$ git add -p diff --git a/README.md b/README.md index 277aa73..2c31356 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Please get involved by working on one of these items or by suggesting something Please grab one of the straightforward [#mgmtlove](https://github.com/purpleidea/mgmt/labels/mgmtlove) issues if you're a first time contributor. ## Bugs: +Some bugs are caused by bad drive-by patches to git master! Please set the `DEBUG` constant in [main.go](https://github.com/purpleidea/mgmt/blob/master/main.go) to `true`, and post the logs when you report the [issue](https://github.com/purpleidea/mgmt/issues). Bonus points if you provide a [shell](https://github.com/purpleidea/mgmt/tree/master/test/shell) or [OMV](https://github.com/purpleidea/mgmt/tree/master/test/omv) reproducible test case. Stage this hunk [y,n,q,a,d,/,e,?]? y <stdin>:9: trailing whitespace. Some bugs are caused by bad drive-by patches to git master! warning: 1 line adds whitespace errors. james@computer:~/code/mgmt$ git commit -m 'XXX this is a bad patch' README.md:37: trailing whitespace. +Some bugs are caused by bad drive-by patches to git master! james@computer:~/code/mgmt$ git commit -nm 'XXX this is a bad patch' [master 8b29fb3] XXX this is a bad patch 1 file changed, 1 insertion(+) james@computer:~/code/mgmt$ git tpush tpush branch is: tpush/test-0 Switched to a new branch 'tpush/test-0' Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 357 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@github.com:purpleidea/mgmt.git * [new branch] tpush/test-0 -> tpush/test-0 Switched to branch 'master' Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) - CI is starting... / Waiting for CI... - Waiting for CI... \ Waiting for CI... | Waiting for CI... Deleted branch tpush/test-0 (was 8b29fb3). To git@github.com:purpleidea/mgmt.git - [deleted] tpush/test-0 Upstream CI failed with: failure: https://travis-ci.org/purpleidea/mgmt/builds/109472293 Fix branch 'master' with: git commit --amend or: git reset --soft HEAD^ Happy hacking!
A successful scenario:
In this example, I amended the previous patch in my local copy of git master
(which never got pushed to the public git master!) and then I ran git tpush
again.
james@computer:~/code/mgmt$ git commit --amend [master 1186d63] Add a link to my article about debugging golang Date: Mon Feb 15 17:28:01 2016 -0500 1 file changed, 1 insertion(+) james@computer:~/code/mgmt$ git tpush tpush branch is: tpush/test-0 Switched to a new branch 'tpush/test-0' Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 397 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@github.com:purpleidea/mgmt.git * [new branch] tpush/test-0 -> tpush/test-0 Switched to branch 'master' Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) - CI is starting... / Waiting for CI... - Waiting for CI... \ Waiting for CI... | Waiting for CI... Deleted branch tpush/test-0 (was 1186d63). To git@github.com:purpleidea/mgmt.git - [deleted] tpush/test-0 Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 397 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@github.com:purpleidea/mgmt.git 6e68d6d..1186d63 master -> master Done!
Please take note of the “Waiting for CI…” text. This is actually a spinner which updates itself. Run this tool yourself to get the full effect! This avoids having 200 line scrollback in your terminal while you wait for your CI to complete.
Lastly, you’ll note that I run git tpush
instead of git-tpush
. This is because I added an alias to my ~/.gitconfig. It’s quite easy, just add:
tpush = !git-tpush
under the [alias]
section, and ensure the git-tpush
shell script is in your ~/bin/
folder and is executable.
Pre-requisites:
This actually depends on the hub command line tool which knows how to ask our CI about the test status. It sucks using a distributed tool like git with a centralized thing like github, but it’s still pretty easy for me to move away if they go bad. You’ll also want the tput
installed if you want the fancy spinner, but that comes with most GNU/Linux distros by default.
The code:
Happy hacking,
James
PS: No, I couldn’t think of a better name than git-tpush, if you don’t like it feel free to rename it yourself!