Working with the LLVM git Repository ==================================== This guide provides information about how to access and interact with LLVM's git repository. Specifically, it covers how to check out the LLVM git repository, create patches for review, revise those patches as necessary and commit them to the LLVM upstream repository. Initially, this guide is a sketch of how a transition to git may be done without disrupting the current LLVM review process. It may be adapted later into a full-fledged user guide. This guide does not specifically cover interacting with Clang and other LLVM projects. However, the information here is likely to be adaptable to those projects. This guide assumes the developer only wants a single clone of LLVM. It is possible to set up complex work environments with a local shared clone of LLVM and various clones of the shared local repository, but this guide does not attempt to describe such scenarios. Such setups are highly useful for tracking independent third-paty development but they are beyond the scope of this document. Getting LLVM ------------ To check out the current LLVM sources, use git clone: git clone http://llvm.org/git/llvm.git llvm This will get you a repository that looks like this: ...-A[HEAD] where "..." is the history of the project leading up to the most recent commit A. HEAD is a reference to this most recent commit. Naming Upstream --------------- The intial clone from upstream results in a git remote reference with the rather unhelpful name of "origin." As more remote sources get added, it is easy to forget what "origin" is. Therefore, add a remote with a more descriptive name. git remote add llvm-upstream http://llvm.org/git/llvm.git master Updating LLVM - no local changes -------------------------------- To update your clone to the latest LLVM sources, use git pull: git pull llvm-upstream This may result in a dag like this ...-A-B-C[HEAD] showing two new commits made since the last pull. git pull should ONLY be used where there is no local history waiting to be sent upstream. See below for managing updates in the presence of local history. Working with LLVM ----------------- Actual code development in the workarea proceeeds much like any project, except that with git you may commit changes locally without disturbing upstream. Let us say that the curent dag looks like this: ...-A[HEAD] We want to make some changes to if conversion. First we create a local branch to hold the changes: git checkout -b ifconvert Now we edit the files and commit them. git add lib/CodeGen/IfConversion.cpp git commit git has some conventions about commit message format. The most important one is that if there is a single line separated from the rest, like this: This is the subject This patch does some really funky stuff. I hope it will work! Then "This is the subject" will become the line printed when doing --oneline log displays and will also be the subject of e-mails sent to the mailing list. Our dag now looks like this: ...-A{master} \ B{ifconvert}[HEAD] Let's make some more changes: ...-A{master} \ B-C-D{ifconvert}[HEAD] Preparing a Commit ---------------------- Let's say we want to commit the changes to if conversion, contained in revisions B and C. We don't yet want to send D for review. There are several strategies available, but the fundamental choice is whether to create a separate branch to do the merge and commit. Usually this is not necessary but for very complex situations it can help to organize things a bit more explicitly. Let's say we choose the simple strategy of merging from master. The first step is to get the identifiers of B and C: git log --oneline: 8fe2a Finish if conversion work afe3d Middle of if conversion work, something interesting to commit 44ef3 Start if conversion work (we hope subjects are more descriptive than this!) We go back to master to start the commit process: git checkout master ...-A{master}[HEAD] \ B-C-D{ifconvert} Now we choose the commits we want to send upstream: git cherry-pick 44ef3 git cherry-pick afe3d The dag looks like this: ...-A---E-F{master}[HEAD] \ / / B-C-D{ifconvert} E and F are the cherry-picked B and C. Updating LLVM - with local changes ---------------------------------- Now we have the commits we want but we should apply them against the latest upstream master. git rebase is the tool to do this: git fetch llvm-upstream master This pulls in the changes from upstream but does not yet apply them to the workarea. A local branch gets created to track this content. Now we want to take those upstream changes and apply our local changed on top of them. This maintains a linear history, making reviews much easier. git rebase llvm-upstream/master There may be conflicts from this operation. If so, resolve them in the usual way. git has some tools to help but they are beyond the scope of this guide. Now our history looks like this: ...-A-----G-H-I-E'-F'{master}[HEAD] \ / B-C-D{ifconvert} Where E' and F' are the new commits of E and F on top of the latest master. Now we are ready to begin the review process. Sending Patches for Review -------------------------- git includes a whole set of tools for managing the patch review process. We kick things off with git format-patch: git format-patch -o $HOME/patches/ifconvert --thread --src-prefix=old/ \ --dst-prefix=new/ --cover-letter HEAD~1..HEAD This places three text files in $HOME/patches/ifconvert, one for each commit, plus a cover letter to send before each patch. These will get sent to the e-mail list with the subject "[PATCH n/2] " where "n" is the patch number (0 for the cover letter) and is the first line of the commit message. Edit these files to add any commentary you desire. It is helpful for format-patch and send-email to have various bits of information pre-selected for e-mail interaction. For example, I put this in my .git/config file in the local repository: [format] numbered = auto to = llvm-commits@cs.uiuc.edu inline = "---------" thread = shallow [sendemail] smtpencryption = tls smtpserver = smtpuser = smtpserverport = 25 thread = false chainreplyto = false to = llvm-commits@cs.uiuc.edu signedoffbycc = false from = David Greene suppressfrom = true "git help format-patch" and "git help send-email" gives all te details. Now use git send-email to actually send the review request messages: git send-email --annotate $HOME/patches/ifconvery/* 2>&1 | tee email.out Your patches have been sent to llvm-commits for review. Interact over e-mail and respond to feedback. Updating Patches ---------------- Your patches will probably require some editing. git rebase -i and git add -i are your friends. For the typical case of editing your patches a bit, use git rebase -i: git rebase -i HEAD~2 This brings up an editor with a document that looks something like this: pick ef723 Start if conversion work pick 443de Middle of if conversion work, something interesting to commit This is a control file you edit to state how git-rebase should work. There are essentially three commands pick, edit and squash. "pick" tells rebase to apply that change as-is. "edit" tells rebase to suspend working immediately after applying that commit. This allows you to edit the patch as necessary. "squash" tells rebase to combine that commit with the previous one and apply them as a single change. One can also reorder commits within the file to change the order they are applied. If you delete a line, that commit disappears from the rewritten history. In this case, let's say that the second commit needs some work. We edit the control file to do that: pick ef723 Start if conversion work edit 443de Middle of if conversion work, something interesting to commit After saving and quitting, git-rebase does its work and we are left in this state, assuming no intervening upstream changes: ...-A-----G-H-I-E'-F'{master}[HEAD] \ / B-C-D{ifconvert} Note that F' is still applied. To actually change it, we need to back up one commit: git reset --soft HEAD^ This puts all the files from F' into the "changes to be committed" state. That is, they are in the index, but not in the history. You can now edit files to your heart's content. When everything is ready, you can re-commit with the original log message: git commit -a -c ORIG_HEAD ORIG_HEAD is a temporary branch created from the origin HEAD before the git reset. It is a convenient handle to refer to information from that commit. Now tell rebase to continue and finish up: git rebase --continue Splitting Patches ----------------- Sometimes reviewers request that a patch be broken up into smaller components. This is easy to do with git add -i. Let's say the first patch is too large. git rebase -i HEAD~2 pick ef723 Start if conversion work pick 443de Middle of if conversion work, something interesting to commit Edit the first patch: edit ef723 Start if conversion work pick 443de Middle of if conversion work, something interesting to commit After rebase suspends, back out the commit: git reset --mixed HEAD^ Your files are left in the "untracked files" state and will have to be added again. This is what you want because you need to add just a few files or parts of files. So decide what to add: git add -i This brings up a little menu which lets you pick which files or hunks of files to add. Going through all the options is beyond the scope of this guide. One good guide is here: http://book.git-scm.com/4_interactive_adding.html After finishing the add process, do a commit. git commit Do NOT do commit -a as that will re-add everything. Go on to do some more add -i and commits to stage everything as desired. Then tell rebase to finish up: git rebase --continue Sending to Upstream ------------------- Finally, we are ready to send the patches. First make sure we are as up-to-date as possible: git fetch llvm-upstream master git rebase llvm-upstream/master Now commit: git push llvm-upstream master Resources --------- Here are some helpful git resources. Pro Git book: http://progit.org/ This is a great book to grok git. It explains the tools in a straightforward way. Get it in paperback for a great reference! All of the other resources will make much more sense after having read this book. git fetch/merge vs. pull: http://longair.net/blog/2009/04/16/git-fetch-and-merge/ Git rebase worflow: http://mettadore.com/analysis/a-simple-git-rebase-workflow-explained/ The git manpages are pretty good once you are reasonably familiar with the tools. They contain a lot of good examples for various scenarios.