Gentoo git workflow

This is a draft! Nothing of this is really decided upon. It may also be incomplete and contain wrong information.

commit policy

 * atomic commits (one logical change)
 * commits may span across multiple ebuilds/directories if it's one logical change
 * every commit on the left-most line of the history (that is, all the commits following the first parent of each commit) must be gpg signed by a gentoo dev
 * repoman must be run from all related ebuild directories (or related category directories or top-level directory) on the tip of the local master branch (as in: right before you push and also after resolving push-conflicts)

commit message format

 * all lines max 70-75 chars
 * first line brief explanation
 * second line always empty
 * optional detailed multiline explanation must start at the third line
 * for commits that affect only a single package, prepend "CATEGORY/PN: " to the first line
 * for commits that affect only a single package, but also modify eclasses/profiles/licenses as part of a logical change, also prepend "CATEGORY/PN: " to the first line
 * for commits that affect only the profile directory, prepend "profiles: " to the first line
 * for commits that affect only the eclass directory, prepend "ECLASSNAME.eclass: " to the first line
 * for commits that affect only licenses directory, prepend "licenses: " to the first line
 * for commits that affect only metadata directory, prepend "metadata: " to the first line
 * mass commits that affect a whole category (or large parts of it) may prepend "CATEGORY: " to the first line

branching model

 * the primary production-ready branch is master (users will pull from here), there are no non-fast-forward pushes allowed
 * there may be developer-specific, task-specific, project-specific branches etc

naming convention

 * developer branches: dev/
 * project branches: project/
 * if in doubt or if the branch could be useful to others, discuss the naming on-list beforehand

about rebasing

 * primary use case: in case of a non-fast-forward push conflict to remote master, try 'git pull --rebase=preserve' first; if that yields complicated conflicts, abort the rebase and continue with a regular merge (if the conflicts are trivial or even expected, e.g. arch teams keywording/stabilizing stuff, then stick to the rebase)
 * to preserve merges during a rebase use 'git merge --preserve-merges ...' (if appropriate, e.g. for user branches)
 * don't use --preserve-merges if you do an interactive rebase (see BUGS in git-rebase manpage)
 * commits that are not on the remote master branch yet may be rewritten/squashed/splitted etc via interactive rebase, however the rebase must never span beyond those commits
 * never rebase on already pushed commits
 * there are no particular rules for rebasing on non-master remote branches, but be aware that others might base their work on them
 * there are no particular rules for rebasing non-remote branches, as long as they don't clutter the history when merged back into master
 * don't do complicated rebases to avoid a merge commit at all cost (it may even cause losing information, e.g. user signatures)

about merging

 * if a rebase fails or is too complicated, do a regular merge instead
 * do a merge if the information is useful (e.g. pulled from a foreign remote user branch or merged a non-trivial eclass conversion back into master) and force a merge commit (non-fast-forward merge via '--no-ff')
 * to avoid a merge commit (e.g. information is not useful), you may try to force a fast-forward merge by first rebasing the feature branch against master and then merging it into master, see here
 * extend merge commit messages with useful information, e.g. how conflicts were solved
 * keep in mind that all commits of the first parent of the history must be gpg signed by a gentoo dev, so you may want to force merge commits especially for user branches

remote model
We have a main developer repo where developers work & commit (every developer has direct push access). For every push into developer repo, automated magic thingie merges stuff into user sync repo and updates the metadata cache there.

User sync repo is for power users than want to fetch via git. It's quite fast and efficient for frequent updates, and also saves space by being free of ChangeLogs.

On top of user sync repo rsync is propagated. The rsync tree is populated with all old ChangeLogs copied from CVS (stored in 30M git repo), new ChangeLogs are generated from git logs and Manifests are expanded.

best practices

 * before starting work on your local master, it's good to first pull the latest changeset (if any) from remote master
 * it might be a good idea for projects/developers to accumulate changes either in their own branch or a separate repository and only push to remote master in intervals (that decreases the push rate and potential conflicts)
 * git is not CVS, so if you need to modify stuff in profiles/ as part of a version bump, there is not really a reason to split that up in 3+ commits, as long as everything is one logical contained change
 * when initially cloning the dev repository, it is reasonable to make it a shallow clone to speed up common operations and the cloning time itself, e.g.

common ebuild work

 * 1) do the work (including removing files)
 * 2) make sure you are in the ebuild directory
 * 3) create the manifest
 * 4) stage files (including removed ones), if any
 * 5) check for errors
 * 6) if errors occur, fix them and continue from point 3
 * 7) commit the files
 * 8) push to the dev repository
 * 9) if updates were rejected because of non-fast-forward push, try  first, then run  and continue from point 7.
 * 10) if the rebase fails or yields complicated conflicts, continue with a regular merge:
 * 11) if merge conflicts occur, fix them via  and continue from point 3
 * 12) if no merge conflicts occur, run  and continue from point 7

pull requests

 * 1) identify the remote and the branch to be merged
 * 2) add a new remote
 * 3) fetch the changes
 * 4) checkout the remote branch  (you are now in detached HEAD mode)
 * 5) test the ebuilds and run repoman
 * 6) if everything is fine, switch back to master
 * 7) now merge the changes with an enforced merge commit (both for the info and for gpg signature checking to work)
 * 8) push to the dev repository (same as in the previous section)

tips and tricks

 * Especially staging files can be tedious on the CLI. So you may want to use the graphical clients 'gitk' (for browsing history) and 'git gui' (for staging/unstaging changes etc.). You have to enable the 'tk' USE flag for.

External resources

 * Git Tutorial by Lars Vogel
 * Tips and Tricks on gitready