Version control: best practices
blog.rainforestqa.com
blog.rainforestqa.com
All of the examples given in the image going that heading I'd say are mediocre at best.
The code changes should tell you what has changed, if I'm looking back through your commit history what I'm usually trying figure out is why you've changed something.
A ticket number is often the single most useful thing, ideally followed why a very brief what you've changed and as much information on why you've changed it as you think would be useful.
#2313 Change expected value to a float field.
django-haystack stores decimal fields as strings internally.
This means that when we order by expected value small
values (e.g '9e-08') are sorted before larger values.Some commits even feature implementation details, and those I agree with you sometimes it makes sense to include them in the code. However most implementation details replace old ones, and this is transition should be explained in a commit since this is the perfect place for it.
Here is an random example from the linux kernel, which is guaranteed to do what I described: http://goo.gl/QdKNnJ
Does anyone know of good open source project that uses Git messages extremely well that we could use as an example?
https://github.com/tomswartz07/linux-configs/commit/3684d3ad... is an example of one.
Git's commit log is probably the most detailed and informative log I've ever seen. And it's a bit fun to have a glance at Linus Torvald's old initial commits from 2005 :-)
(You might want to check the 'pu' branch rather than the 'master' branch. And there're lots of 'Merge branch...' commits that aren't super interesting.)
Ticket numbers are important context, but unless it is a one-off commit you can instead put that info in the merge commit (as if saying, all of these commits I'm merging were made as part of fixing Issue #17).
Some people like to use squash extensively for that reason, but then you don't have the same granularity when it comes to reverting individual bits of that commit without reverting the entire bugfix. (This assumes that every commit leaves the code in a working state with passing tests).
The alternative in your case (leaving it as-is, with an issue number) implies that the entire commit addresses that particular issue number, which may not be true. (It may be part of a series of commits for that issue)
I have one coworker who continually fails to put the empty line between the first line and the body of the commit message. So many of our git logs are littered with 100+ character long messages.
The other commenters hit the nail on the head with the fomatting. Short, precise, and properly formatted.
- to explain HOW it works: comment in the code, so whoever comes to change the code later knows what should be touched and what should be left alone
- to explain WHY it was changed, use the bug tracker and just supply the #ID of bug/feature request in the comment
Having single-line comments makes it much easier to browse through history and find the thing you're looking for.
Unfortunately, the powers-that-be aren't too keen on enforcing something like that in our current projects.
Plan out the tasks in your PR to communicate what still needs to be done -- I like to use GitHub Flavored Markdown task lists.
Here's a fish script I use when creating a new branch. It opens a PR before I even write a single line of code.
# Usage: git-new-branch 120-fix-foo-issue
function git-new-branch --description 'Creates a new branch and opens a Pull Request for it'
git checkout -b $argv[1]
git commit --allow-empty -m 'Empty commit to open PR'
git push origin HEAD
git pull-request # Opens your default text editor for PR title. Uses hub.
endhttp://stackoverflow.com/questions/4528869/how-do-you-attach...
Git and Github are communication channels and you should think about effectively communicating with your audience when you are using them. Very much in the same way that you are when you are writing emails.
The other interesting point about Git is that, very often, you are your own audience when you're revisiting the history of particular months after you've written the original code. You should definitely start thinking about your workflow a little more.
http://continuousdelivery.com/2011/05/make-large-scale-chang...
Is anyone making squashing part of their workflow? We seem to prefer just plain merges with rebase.
[1] http://zachholman.com/talk/how-github-uses-github-to-build-g...
I make use of squashing when there is a clear group of commits that all change the same few lines of code or are conceptually part of the same incremental change. But then each incremental change (from working state to newer working state) I leave as a separate commit.
commit1: he/she added some methods
commit2: refactored some code
commit3: he/she plugged in the methods created into the refactored code
etc.
The branch as a whole should be a finished feature. Keep the features small-ish. Try not to have a branch that living on it's own for a long time. You can merge the master branch into it, however you'll slowly be out of sync with your team b/c they don't really know what you're up to.
The only thing I absolutely detest in Git, is that is no quick method to change history on local changes. Say I add a method and make a commit - then I do a bunch of other work and 10 commits later I realize that the method I had written needed to be const. Instead of be able to edit that commit and add the const labels, I end up having to make another commit that no one cares about and no one really should have to look at. It just makes the history incredibly cluttered and make it a lot harder to find the commits I'm interested in.
The workaround is to make a new branch and cherry pick changes - but it's a huge PITA and easy to mess up
Aside:
Does anyone know what diff tool is best for working in C++? The diffs I commit (using kdiff) can sometimes be mind-boggling hideous b/c the diff program parsed things in some strange way.
I think you can use git rebase --interactive to reorder the new commit and squash it with the older: http://stackoverflow.com/questions/3921708/how-do-i-squash-t...
Of course, that requires manual labor (brrr), but that's nothing that a small script can't automate. I'd do it myself if we used git where I work.
We decided to kill our development branch and just create feature branches off of master. If multiple devs are working on the same project scheduled for the same release, we will create a release branch and they can branch features off of that.
An open pull request into master is how we initiate the QA process, and all remediations are discussed in there. When the pull request is merged and closed, we all get an email so we know to update our local code. It's been working really well so far for both our small and large projects.
There might be a point where this won't work for us anymore, it's always time to change.
Also, this is not because a branching model works for a team that it will for all teams and projects.
Like any in-house, process the branching model will evolve with the team and it's requirements to be efficient.
1. When someone merges their branch into development for QA, it's going to be there (with or without issues) for anyone else who merges for QA after that. If the first merge has bigger issues than expected, it's a bit of a pain to roll it back and re-merge the later branch. Without the development branch as a base for our QA, we just QA things one feature/release branch at a time. This lets us easily send back branches that aren't ready for production and move on to a different branch that is before any merging takes place.
2. We weren't sure how to handle pull requests with the development branch always being there. We used to set development as our "default" branch in github, so any pull requests would be automatically merged into there. That got a bit confusing, though, as most of us were so used to merged pull requests representing a change that has already been reviewed and accepted as production-ready. And as for the merge to master, should we submit another pull request? It just seemed like an unnecessary extra step in a lot of situations.
But you are absolutely right. Different flows work for different teams and projects. I'm sure as our team evolves, so will our workflow.
For merges to master, we submit other pull requests that we call "Release: ...". We can then see if CI and Rainforest tests are passing, if all is green, then we merge! :)
Can you explain me how you prevent that from happening ?
Also, once something is on develop/staging, it is about to be shipped. If there is any bug in there, they are they should be fixed ASAP.
As we grow, we might have to do things differently, we'll see, but this works really well for us right now. :)
See: http://geekblog.oneandoneis2.org/index.php/2013/04/30/please...
Also, I prefer merge over rebase.
rebase and force push are _bad_ _if_ you run those commands over commits that are already committed into remote branches that are shared by others (mainly the master branch).
You definitely can (and probably should) rebase on your own branches and be fine with force pushing into your own branches (even "remotely", like on a PR'd branch). However once you are touching shared branches, you should definitely not run rebase/force push.
The basic rule is if you are on a branch and you need to use rebase to do squashes or amendments, you are okay as long as you do `git rebase -i origin/master` (assuming origin/master is updated and that master is what you branched off of). Running a normal rebase should not affect any committed changes as it takes your parent branch (origin/master) and runs your commits on your local branch over it.