Jeremy's answer (+1) is already quite comprehensive. Some additional more practical-oriented advice follows in *no particular order*.
***Disclaimer:*** this is stuff that works for me. Others might have other suggestion or even disagree. If this is the case I would be superhappy to hear feedback and alternate/better proposals!
1. **Make a point that every team member should start his/her session by updating the code AND database.** You can easily script all of that with a combination of `ssh` and `rsync` commands. I at times create a single script (`update-project.sh`) that updates the code from the repository and download and import the latest DB from the master server at once.
2. **Never forget to call `http://example.com/update.php` every time you update the code.** Run this command on your staging site, after every commit, and on your local machine after every update/pull/checkout.
3. **Do any change to the DB via SQL query, rather than with a GUI.** That way you will simply have to wrap that query into an [`hook_update_N()`][1] implementation in your *yourmodule.install* file, and you are safe and sound (if you abide to point #2!) [some gui tool output the equivalent... that's handy too!].
4. **Whenever possible, include in [`hook_update_N()`][2] also changes to module settings.** This is not possible all the times. When not possible: see point #7 and #8.
5. **When creating or modifying a view, export it to a file when finished.** Same principle that point #3 but applied to views. This approach has incidentally also the benefit of providing a rollback mechanism in case you later realise you made a mistake.
6. **Use a master repository.** Don't go for a too much distributed versioning system. Pull and push your code always from the same central repo.
7. **Always include a comment in your commit.** Especially if some code change change some functionality / API / common logic, make a point to include a warning in your commit message. Detailed info can be put in a changelog.txt file, if needed.
8. **When committing, immediately reproduce on the master DB any hand-made DB changes that you haven't managed to include in your `hook_update_N()` implementation.** This is a must if your team members start their sessions like described in #1.
9. **Be selective in what you put under versioning.** For example: exclude the `sites/default/settings.php` but evaluate what (if anything at all) need to be versioned from in `sites/default/files` (are images needed for development? and attachments?).
10. **There are some useful contributed modules that can help.** Like [import/export][3], which allows you to manage in a repository your CCK and Views or [node export][4] that allows you to export nodes and then import them back in another drupal installation.
11. **Use the [simpletest module][5] extensively.** That is a **good** idea anyhow, but when working in team is a **great** idea: that way you will be sure your changes haven't broken anybody else's work.
12. **Have fun!** I love to work in team and I believe one should try to do that everytime he/she can. It's more fun, more learning and above all... better code! :)
Bonus point (does not refer to team development specifically):
- **Try not to use your staging server for real content insertion.** Ideally you should start creating content only when the code is somehow freezed or use an import routing/module: drupal scatters information across tables a lot, and the system of hooks makes very difficult to track which modules have stored what information where: if you develop on a DB with real data, you will inevitably end up breaking some tables at some point, and you might realise that only the day before going into production. :(
[1]:
[To see links please register here]
[2]:
[To see links please register here]
[3]:
[To see links please register here]
[4]:
[To see links please register here]
[5]:
[To see links please register here]