GitWine

Back to: HackingTips

Index

1. Using Git to maintain your patches against Wine

Welcome to the GitWine tutorial! This page describes how to manage Wine code and patches with git. Git is a fast version control system, originally written for use with large repositories, such as the Linux Kernel source. The Git Wine tree gives you fast access to the entire Wine tree and its history, and allows you to maintain a local tree or patch series and merge it easily with WineHQ.

You may wish to check the git tutorial or Jeff Garzik's Git tutorial before reading further. There's also a very comprehensive guide to advanced git usage ("branch wizardry and git grandmastery" ; ) called Git Magic available; despite the name it also addresses Basic Trickery for the beginner's needs.

A short presentation on git from WineConf2006 is also available.

2. Set up your Git repository

The first step to using Git with Wine is to set up a local Git repository.

2.1. Downloading and installing

warning: Older versions of Git will not work. You need version 1.4.1 or higher. Many distributions ship older versions, but may provide a more recent package as a back port.

If you want to install from source, you can download the latest version of Git from http://www.kernel.org/pub/software/scm/git/ . It installs into ~/bin by default. Building and running Git now requires libcurl and curl to be installed. Debian users can apt-get libcurl3-dev and curl.

warning: It is recommended to use a libcurl version >= 7.16 as older versions may contain a bug that will cause git to hang.

2.2. Cloning the Wine Git repository

Checking out from the WineHQ Git repository:

git clone git://source.winehq.org/git/wine.git ~/wine-git
cd ~/wine-git

For older versions of git, or if you are stuck behind a firewall with an uncooperative proxy, you may need to replace git: with http:.

This should leave you with a checked out Wine Git repository in the directory wine-git, which you can then build. The clone takes around 30 minutes for me on an ADSL connection, and transfers around 175MB of data, the size of the complete WineHQ repository.

If all goes well, the output of git config remote.origin.url should be:

bash-3.00$ git config remote.origin.url
git://source.winehq.org/git/wine.git

and you will have a single branch named "master", which can be revealed by running git branch.

2.3. Further configuration

If you plan on sharing or committing any patches at all, you should set your name and email address using:

git repo-config user.name "Your Name"
git repo-config user.email "me@example.com"

Most mail agents now automatically convert patches to mime-type x-diff, however this makes it impossible to quickly read or apply a patch from the wine-patches archive. The trick to work around this is setting the patch extension to .txt with the following command:

git repo-config format.suffix .txt

3. Managing your changes - the simple way

3.1. Checking a patch into your local tree

After editing the checked out tree, you can use git status to see which files have changed:

git status

Or you can examine the difference by using git diff:

git diff

To then commit all changed files to your local tree, use the git commit command:

git commit -a

If you only wish to commit some files, use:

git commit <changed-files>

You can get a list of all the commits in the tree using git whatchanged or git log:

git whatchanged
git log

3.2. Commit early, commit often

Your local git tree is yours. You should feel free to commit patches frequently, as it's not until you mail them in that they have a chance of being committed.

3.3. Reverting changes in your working copy

If you have edited some files, but decided you don't like the changes you've made and want to undo all the changes that you've made to your tree, you can use git checkout:

git checkout -f
git checkout file-name # revert one file

3.4. Undoing commit(s)

If you want to undo your most recent commit, you can use the git reset command:

git reset HEAD^         # do not touch work files - keep changes
git reset --hard HEAD^  # reset work files as well
git reset --hard HEAD~5 # go back 5 commits
git reset --hard origin # scrap all changes and start all over again

3.5. Editing commits

To edit most recent commit:

vi file.c                               # edit the file
git commit --amend file.c               # redo the commit without deleting the commit

If the commit is not the most recent one, but say 5th from the top then you can:

git checkout -b tmp HEAD~5              # rewind to the commit in question
vi file.c                               # edit the file
git commit --amend file.c               # redo the commit without deleting the commit
git rebase --onto tmp master~5 master   # replay the later changes
git branch -D tmp                       # clean up the temporary branch

Where there are a number of files to amend you are probably better off using:

git checkout -b tmp HEAD~5              # rewind to the commit in question
git reset HEAD^                         # delete the commit at the now current point
vi file1.c                              # edit
vi file2.c                              #      the files
git commit -a -c ORIG_HEAD              # redo the commit incorporating all changed files
git rebase --onto tmp master~5 master   # replay the later changes
git branch -D tmp                       # clean up the temporary branch

Where the commit is not the most recent one, but say 5th from the top and you wish to insert a new commit, then you can:

git checkout -b tmp HEAD~5              # rewind to the commit in question
vi new_file.c                           # create the new file
git commit -m "New commit of file new_file.c" new-file.c # create a new commit or a series of commits
git rebase --onto tmp master~5 master   # replay the later changes
git branch -D tmp                       # clean up the temporary branch

Likewise if you want to delete a commit that is not the most recent one, then you can:

git checkout -b tmp HEAD~5              # rewind to the commit in question
git reset HEAD^                         # delete the commit at the now current point
git checkout path/file1 path/file2 etc  # delete the changed files
git rebase --onto tmp master~5 master   # replay the later changes
git branch -D tmp                       # clean up the temporary branch

and the commit is gone. You need to checkout all the changed files though and the rebase may throw some errors for you to resolve as it applies later commits.

See git rebase for more information.

3.6. Generating a patchset to submit

After checking in your local changes (in multiple small commits), you can generate a list of the patches you need to send upstream (i.e. to wine-patches) with the following command:

git format-patch -o out origin

"origin" is the name of the WineHQ branch which git uses by default. One file per patch will be created in the directory "out", which you can then load into your mailer and send to wine-patches.

As of Git 1.3.0, you should be able to dump patches directly into an IMAP drafts folder using "git-imap-send".

git format-patch --stdout --attach --keep-subject origin | git-imap-send

(Older git versions use --keep instead of --keep-subject.)

Set up the imap server by editing wine/.git/config and adding entries something like this:

[user]
        Name = "Your Name Here"
        email = "your@email.here.com"
[imap]
        folder = "INBOX.Drafts"
        tunnel = "ssh -C -q user@imapserver.net /usr/bin/imapd ./Maildir 2> /dev/null"
[format]
        headers = "To: wine-patches <wine-patches@winehq.org>\n"

The above works for Courier imap; for Dovecot, try something like this:

[imap]
        folder = "Drafts"
        tunnel = "ssh user@dovecotserver.net /usr/sbin/dovecot --exec-mail imap  2> /dev/null"

Using Mozilla, sending patches is then just a matter of clicking on "Edit Draft", reviewing the mail and then clicking "Send". If you're using Evolution, you can drag and drop the .patch files into your drafts folder.

  • Important note: If you are using Thunderbird, be sure to specify --attach on git-format-patch. Otherwise you will likely fall prey to this bug Thunderbird Bug 435020.

Setting up ssh simplifies the patch generation by removing the need to enter a password. Use ssh-keygen to create your keys and copy ~/.ssh/id_rsa.pub to ~/.ssh/authorized_keys to allow the tunnel to be created without entering a password.

Using local KMail folders, you can use the following approach:

git format-patch --stdout --attach --keep-subject origin | formail -s procmail

Assuming you don't already use procmail to sort your email, you can use the following .procmailrc

:0
/home/username/.maildir/

Now, all you need to do is to set up a new receiving account in KMail that collects mail from /home/username/.maildir and filter emails coming in on that account to your drafts folder.

3.7. Rebasing your branch

When you send patches, inevitably, some of your patches will be rejected, while others will be accepted. If you have written a series of patches, but only some of those are rejected, it can be annoying to reorder them, fix one or two problems and resumbit.

The main git tool that you can use to help solve the problem is git rebase, the other is git cherry-pick. They are discussed separately here.

git rebase creates a new branch on 'origin' and reapplies all the patches in your current HEAD, then changes HEAD to the new branch. With the master tree checked out, you can use git rebase like this:

git branch master-2005xxxx
git rebase origin

The result will be a new master branch based off the WineHQ head containing all the uncommitted patches that were in your old master branch, which is saved as master-2005xxxx. The current branch will be reset to origin and only patches in your HEAD but not in origin will be reapplied to the current branch.

If you have not committed any patches to your tree, and you do a fetch and rebase, rebase will deceptively tell you "Nothing to do.". This is means "there are no patches to apply to your new tree", not that the tree has not been changed. The rebase was successful. Note: this is fixed in v1.4.2+.

3.8. Resolving merge conflicts

If there is a conflict you will see something like this:

Applying <patchname>
error: patch failed: <file>:<line>
error: <file>: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merged <file>
CONFLICT (content): Merge conflict in <file>
Failed to merge in the changes.
Patch failed at <msgnum>.

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To restore the original branch and stop rebasing run "git rebase --abort".

There are two choices now: resolving the conflict or skipping the patch. The file in question will contain conflict markers where the patch failed:

<<<<<<<
[code that caused patch not to be applied]
=======
[what would have been here if the patch had been applied]
>>>>>>>

To resolve the conflict you have to manually merge the code between the conflict markers leaving the file in a compilable state; After that issue

git update-index <file>
git rebase --continue

to remove the merge-conflict state and continue with the operation.

Patches can be skipped as follows:

(git reset --hard  # removes the patch)
git rebase --skip  # for older Git version use "am" instead of "rebase" here

3.9. Keeping up to date with the Wine Git repository

So now you have a Wine Git tree, you need to get the patches Alexandre commits to it. You do this using :

git fetch ; git rebase origin

git fetch retrieves new files from the Wine Git repository; this should always be a safe operation as it does not change your local file system.

git rebase reapplies any local commits you have made onto the latest WineHQ branch. Please see the section "Rebasing your branch" below for more information on git rebase.

A common mistake is to use git fetch by itself. It will only download updates but will not apply them. Another common problem is that it may be because you have uncommitted changes. To fix this you need to

git commit -a ; git rebase origin ; git reset HEAD^

to commit the changes, run the rebase and then uncommit the changes again.

4. Managing branches

4.1. Picking patches from another branch

You can pick a patch from another branch into your current branch using:

git cherry-pick -r [commit-id]

For information on managing branches in git, see the GitBranches page.

5. Other common operations

5.1. Getting rid of timestamp changes

Git considers a file changed if its date is different from that in the Git index file. "git diff-index HEAD" may show files have changed if you have edited them and reverted the changes (or even just touched the file). You can remove this difference using:

git reset

6. Other Git features

6.1. Regression testing

Regression testing is really easy with Git. It's done with the help of git bisect that does all the magic. So all that's left to do is to compile and test. Since even non Wine developers can do it, we keep an entire page on regression testing.

6.2. Viewing the Git tree

You can browse the WineHQ Git repository at http://source.winehq.org/git.

Finally, there's a nice (but a bit slow) tool to view your Git repository named gitk. It gives you a view of the repository that looks like the screenshot below.

qgit also provides similar functionality, but in a Qt based interface. It appears to be faster than gitk and has additional features such as an annotation facility to identify which change introduced each line of a file.

Alexandre says: "if you do something like 'gitk wine-0.9..' you only get commits after 0.9, and it's quite fast" ... "the trailing .. is important".

gitk

7. Patch stack

Stacked Git is similar to Quilt, just on top of Git. It manages a stack of applied and unapplied patches on top of a Git branch. Patches can be pushed on the applied stack or poped off the applied stack onto the unapplied stack. The topmost applied patch can be edited and the stack can be "rebase"-ed to an updated branch. This makes keeping around and refining local changesets (changeset->patch) until they are applied upstream much easier. The history of changes to a patch are also kept in Git.

8. Annoyances

  • Git does not handle conflicts in the working copy well - if a file has any changes in the working copy, and the same file has changed upstream, you do not seem to be able to update the working copy.
    • Comment: This happens when you build git yourself, or your package manager is broken, 'merge' from rcs tools is missing. See http://www.gnu.org/software/rcs/rcs.html

    • Comment: Since version 1.5.0 (which you really, really should have upgraded to since long), Git has a builtin RCS merge replacement. So, no more annoyance.
  • Older Git versions do not support the new version numbering system and thus fail to build. Git 1.1.3 is broken for sure, Git 1.4 works.
  • It can be quite hard to get a real understanding of the underlying concepts of Git, and if you are a git newb you are almost certain to run into in a situation where things break and you have no idea how to get out of the mess. At this point: don't panic! You might be tempted to just trash your repository and manually remerge your patches, but it is very probable you will run into the same situation again so you'd be better of making sure you have understood how Git works. You can find a very helpful article about Branching and merging with git over at LWN.

9. Other git repositories

9.1. Publicly Accessible GIT Repositories

Branch URL

Branch Description

http://source.winehq.org/git/wine.git

The standard Wine repository - if you want the official version, use this

http://repo.or.cz/w/wine.git?a=forks (weblink)

All Wine repositories from repo.or.gz

http://wine-git.corvu.com/

Contains versions of Wine used by CorVu for porting some of its products to Linux

http://repo.or.cz/w/wine/hacks.git (weblink)

useful hacks and other patches not (yet) suitable for mainline by JanZerebecki

9.2. Uploading a branch to repo.or.cz

You can upload your own branch to the repo.or.cz repository collection here, it will show up in the list of wine forks.

Remember to use the project name wine all in underscores.

GitWine (last edited 2008-07-02 16:15:34 by AdamPetaccia)