The following is a list of tips, dos and don'ts for working with the ScummVM Git repositories, compared to working with Subversion.
Development is done on the master branch, which is equivalent to the old Subversion trunk. Release branches are branched from, and merged to, master. Tags are always annotated (git tag -a) in order to include a timestamp.
Please keep the "official" branches on the scummvm repository to "master" and release-*. If you want to use long-lived branches for other projects, either create them on your own forked repository, or consult the team to decide if they belong in the main repository.
- Never ever use git push -f without discussing it on the mailing-list. That operation deletes commits from the server, and will cause problems to others working with the repository.
- Try to not create pointless merge commits. This will be explained in the #Workflow section. If you do make merge commits, the branch you're merging should include commits that are "bunched together" on purpose. This makes them easier to review or revert.
- Do not create additional branches on the main scummvm repository without first consulting with the rest of the team.
There are several ways to work with git. Here we'll discuss two: You could make your commits on the master branch, or you could make them on a separate branch, called a topic branch and then merge them into the master branch, before pushing. We'll cover the basics of pushing first.
How to push changes
The important thing to realize is that when pushing changes to the remote server (aka "origin"), your changes must be based on the remote repository's branch you wish to push to. Subversion allowed you, in some cases, to commit without having the most up-to-date working copy. Git doesn't.
A normal git push without any errors is one that only adds new commits, that (in their metadata) point to existing commits.
If you try to push local commits when the origin has commits you do not have, you will get an error similar to this:
To firstname.lastname@example.org:scummvm/scummvm.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'email@example.com:scummvm/scummvm.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details.
To fix this problem, we need to fetch the remote commits we do not have, and then either "put" our new commits on top of the remote repository's, or create a new "merge commit" that combines the remote repository's commit and yours.
Let's introduce several related commands:
- git fetch — Retrieves commit objects from the remote repository. You can always run this command without fear. It doesn't modify any of your local changes.
- git merge — Creates a "merge commit" from 2 or more branches. If only one branch diverges from the root, it will perform a "fast-forward" and no merge commit will be created (this is configurable).
- git rebase — Moves (i.e. reapplies) a series of commits onto a different base.
- git pull — Perform a fetch followed by a merge (the default behavior) or rebase (with a flag).
So in our case, if we made a few unrelated commits, we just want to apply them on top of the remote commits, and to do that we can use git pull --rebase which will get the remote changes, and reapply our local changes on top of the remote's. From that state, we could run gitk or any other visualization tool, see that everything is to our liking, and git push our changes up.
Configuring git pull to rebase automatically
If you like making commits on the master branch, and want git pull to always rebase your local changes on top of the fetched commits, run this configuration command to modify the repository's .git/config file:
$ git config branch.master.rebase true