CARVIEW |
|
Back to: HackingTips Index Contents
1. Using Git to maintain your patches against WineWelcome 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.
2. Set up your Git repositoryThe first step to using Git with Wine is to set up a local Git repository.
2.1. Downloading and installingwarning: 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 https://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 repositoryChecking 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 configurationIf 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 treeAfter 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 oftenYour 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 copyIf 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 commitsTo 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 submitAfter 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 --keep-subject -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 --keep-subject origin | git-imap-send (Older git versions use --keep instead of --keep-subject.)
3.6.1. Sending the patches using imapSet 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>\nReply-To: wine-devel <wine-devel@winehq.org>\n" The above works for Courier imap; for Dovecot, try something like this: [imap] host = dummy 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. Patches in the Drafts folder will have the date and time of the timestamp of the commit, hence if you generate multiple times you will have many copies of the same patch with the same date and time. This will be the case until you amend the commit and get a new commit timestamp.
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 Thunderbird folders, you can use the following approach to add your patches to the Drafts folder (without using imap): git format-patch --stdout --attach --keep-subject origin | formail -ds >>"/home/username/.thunderbird/12345678.default/Mail/Local Folders/Drafts" note: Sometimes you have to rebuild the index of the Drafts folder in Thunderbird to see the mails added this way. Using local KMail folders, you can use the following approach: git format-patch --stdout --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.6.2. Sending the patches using smtpTo reduce the number of arguements you need to provide to the command git send-email you can add an configuration entry: [sendemail] from=user@example.org to = wine-patches <wine-patches@winehq.org> smtpserver = smtp.example.org smtpuser = userName chainreplyto = false thead = true You can then send the patches in the folder out with the command: git send-email out If you have written an introductional message then you can make the patches a reply to it, by using the following command instead of the first one: git send-email out --in-reply-to "<message id of your introductional email>" If you get an error message "relay not permitted" it may help to upgrade to a newer git version.
3.7. Rebasing your branchWhen 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 conflictsIf 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 repositorySo 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 branchYou 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 changesGit 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 testingRegression 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 treeYou can browse the WineHQ Git repository at https://source.winehq.org/git. Finally, there's a nice tool to view your Git repository named gitk. 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".
7. Patch stackStacked 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
9. Other git repositories
9.1. Publicly Accessible GIT Repositories
9.2. Uploading a branch to repo.or.czYou 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 2009-04-01 20:03:41 by Rico) |