Gentoo git workflow

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)

Atomicity

 * commits in git are cheap and local, so use them often
 * don't do version bumps and ebuild cleanup in one commit (makes reverting ebuild removals more difficult)

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 primarily a single package, prepend "CATEGORY/PN: " to the first line
 * if CATEGORY/PN is very long and you can't reasonable stick to the 75 char limit, just exceed it in that case
 * for commits that affect primarily the profile directory, prepend "profiles: " to the first line
 * for commits that affect primarily the eclass directory, prepend "ECLASSNAME.eclass: " to the first line
 * for commits that affect primarily licenses directory, prepend "licenses: " to the first line
 * for commits that affect primarily metadata directory, prepend "metadata: " to the first line
 * if the change affects multiple directories, but is mostly related to a particular subsystem, then prepend the subsystem which best reflects the intention (e.g. you add a new license, but also modify profiles/license_groups)
 * mass commits that affect a whole category (or large parts of it) may prepend "CATEGORY: " to the first line
 * for referencing bug reports, use "Gentoo-Bug: 123934" in the description of the commit message (usually at the end). It is also encouraged to use other formats such as "Acked-by:", "Suggested-by:" and so on, also see the kernel patch guideline

Example
app-misc/foo: version bump to 0.5

This does also fix the security bug 93829 and introduces the new USE flag 'bar'.

Acked-by: Hans Wurst Reported-by: Alice Wonderland Gentoo-Bug: 123456, 93829

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 rebase --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

 * do not ever commit implicit merges done by git pull. You may want to set git config pull.ff only to avoid git implicitly creating those
 * 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 when merging local branches back to master (e.g. information is not useful), you may try to force a fast-forward merge by first rebasing the local 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)

Cloning
Clone the repository. This will make a shallow clone and speed up clone time:

If you want the full history, just omit --depth=50 from the above command.

Configuration
All developers should at least have the following configuration settings in their local dev repository. These setting will be written to '.git/config' and can also be edited manually. Run these from within the repository you've just cloned in the step above:

In addition, you need to tell repoman which key to use, in case you use repoman for committing.

Workflow Walkthrough
These are just examples and people may choose different local workflows (especially in terms of when to stage/commit) as long as the end result works and is repoman-checked. These examples try to be very safe, but basic.

Common Ebuild Work

 * 1) pull in the latest changeset, before starting your work:
 * 2) do the work (including removing files)
 * 3) make sure you are in the ebuild directory
 * 4) create the manifest
 * 5) stage files (including removed ones), if any
 * 6) check for errors
 * 7) if errors occur, fix them and continue from point 4
 * 8) commit the files
 * 9) push to the dev repository
 * 10) if updates were rejected because of non-fast-forward push, try  first, then run  and continue from point 8.
 * 11) if the rebase fails, but the conflicts are trivial and don't contain useful information (such as keyword stabilization), fix the conflicts and finish the rebase via  and continue from point 4
 * 12) if the rebase fails and the conflicts are complicated or you think the information is useful, continue with a regular merge:
 * 13) if merge conflicts occur, fix them via  and continue from point 4
 * 14) if no merge conflicts occur, run  and continue from point 8

Pull Requests

 * 1) identify the remote url and the branch to be merged
 * 2) add a new remote
 * 3) fetch the changes
 * 4) you may review the changes manually first
 * 5) checkout the remote branch  (you are now in detached HEAD mode)
 * 6) test the ebuilds and run repoman
 * 7) if everything is fine, switch back to master
 * 8) now merge the changes with an enforced merge commit (both for the info and for gpg signature checking to work)
 * 9) 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