Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / docs / git_cookbook.md
blobd42b63da4d00df89fd65998483ee37c4523f75f9
1 # Git Cookbook
3 A collection of git recipes to do common git tasks.
5 See also [Git Tips](git_tips.md).
7 [TOC]
9 ## Introduction
11 This is designed to be a cookbook for common command sequences/tasks relating to
12 git, git-cl, and how they work with chromium development. It might be a little
13 light on explanations.
15 If you are new to git, or do not have much experience with a distributed version
16 control system, you should also check out
17 [The Git Community Book](http://book.git-scm.com/) for an overview of basic git
18 concepts and general git usage. Knowing what git means by branches, commits,
19 reverts, and resets (as opposed to what SVN means by them) will help make the
20 following much more understandable.
22 ## Excluding file(s) from git-cl, while preserving them for later use
24 Since git-cl assumes that the diff between your current branch and its tracking
25 branch (defaults to the svn-trunk if there is no tracking branch) is what should
26 be used for the CL, the goal is to remove the unwanted files from the current
27 branch, and preserve them in another branch, or a similar.
29 ### Method #1: Reset your current branch, and selectively commit files.
31 1.  `git log`  See the list of your commits. Find the hash of the last commit
32      before your changes.
33 1.  `git reset --soft abcdef` where abcdef is the hash found in the step above.
34 1.  `git commit <files_for_this_cl> -m "files to upload"` commit the files you
35      want included in the CL here.
36 1.  `git checkout -b new_branch_name origin/trunk` Create a new branch for the
37     files that you want to exclude.
38 1.  `git commit -a -m "preserved files"` Commit the rest of the files.
40 ### Method #2: Create a new branch, reset, then commit files to preserve
42 This method creates a new branch from your current one to preserve your changes.
43 The commits on the new branch are undone, and then only the files you want to
44 preserve are recommitted.
46 1.  `git checkout -b new_branch_name` This preserves your old files.
47 1.  `git log` See the list of your commits. Find the hash of the last commit
48     before your changes.
49 1.  `git reset --soft abcdef` Where abcdef is the hash found in the step above.
50 1.  `git commit <files_to_preserve> -m "preserved files"` Commit the found files
51     into the `new_branch_name`.
53 Then revert your files however you'd like in your old branch. The files listed
54 in step 4 will be saved in `new_branch_name`
56 ### Method #3: Cherry pick changes into review branches
58 If you are systematic in creating separate local commits for independent
59 changes, you can make a number of different changes in the same client and then
60 cherry-pick each one into a separate review branch.
62 1.  Make and commit a set of independent changes.
63 1.  `git log`  # see the hashes for each of your commits.
64 1.  repeat checkout, cherry-pick, upload steps for each change1..n
65     1.  `git checkout -b review-changeN origin` Create a new review branch
66         tracking origin
67     1.  `git cherry-pick <hash of change N>`
68     1.  `git cl upload`
70 If a change needs updating due to review comments, you can go back to your main
71 working branch, update the commit, and re-cherry-pick it into the review branch.
73 1.  `git checkout <working branch>`
74 1.  Make changes.
75 1.  If the commit you want to update is the most recent one:
76     1.  `git commit --amend <files>`
77 1.  If not:
78     1.  `git commit <files>`
79     1.  `git rebase -i origin`  # use interactive rebase to squash the new
80         commit into the old one.
81 1.  `git log`  # observe new hash for the change
82 1.  `git checkout review-changeN`
83 1.  `git reset --hard`  # remove the previous version of the change
84 1.  `cherry-pick <new hash of change N>`
85 1.  `git cl upload`
87 ## Sharing code between multiple machines
89 Assume Windows computer named vista, Linux one named penguin.
90 Prerequisite: both machine have git clones of the main git tree.
92 ```shell
93 vista$ git remote add linux ssh://penguin/path/to/git/repo
94 vista$ git fetch linux
95 vista$ git branch -a   # should show "linux/branchname"
96 vista$ git checkout -b foobar linux/foobar
97 vista$ hack hack hack; git commit -a
98 vista$ git push linux  # push branch back to linux
99 penguin$ git reset --hard  # update with new stuff in branch
102 Note that, by default, `gclient sync` will update all remotes. If your other
103 machine (i.e., `penguin` in the above example) is not always available,
104 `gclient sync` will timeout and fail trying to reach it. To fix this, you may
105 exclude your machine from being fetched by default:
107     vista$ git config --bool remote.linux.skipDefaultUpdate true
109 ## Reverting and undoing reverts
111 Two commands to be familiar with:
113 *   `git cherry-pick X` -- patch in the change made in revision X (where X is a
114     hash, or HEAD~2, or whatever).
115 *   `git revert X` -- patch in the **inverse** of the change made.
117 With that in hand, say you learned that the commit `abcdef` you just made was
118 bad.
120 Revert it locally:
122 ```shell
123 git checkout origin   # start with trunk
124 git show abcdef       # grab the svn revision that abcdef was
125 git revert abcdef
126 # an editor will pop up; be sure to replace the unhelpful git hash
127 # in the commit message with the svn revision number
130 Commit the revert:
132 ```shell
133 # note that since "git svn dcommit" commits each local change separately, be
134 # extra sure that your commit log looks exactly like what you want the tree's
135 # commit log to look like before you do this.
136 git log          # double check that the commit log is *exactly* what you want
137 git svn dcommit  # commit to svn, bypassing all precommit checks and prompts
140 Roll it forward again locally:
142 ```shell
143 # go back to your old branch again, and reset the branch to origin, which now
144 # has your revert.
145 git checkout mybranch
146 git reset --hard origin
149 git cherry-pick abcdef  # re-apply your bad change
150 git show                # grab the rietveld issue number out of the old commit
151 git cl issue 12345      # restore the rietveld issue that was cleared on commit
154 And now you can continue hacking where you left off, and since you're reusing
155 the Reitveld issue you don't have to rewrite the commit message. (You may want
156 to go manually reopen the issue on the Rietveld site -- `git cl status` will
157 give you the URL.)
159 ## Retrieving, or diffing against an old file revision
161 Git works in terms of commits, not files. Thus, working with the history of a
162 single file requires modified version of the show and diff commands.
164 ```shell
165 # Find the commit you want in the file's commit log.
166 git log path/to/file
167 # This prints out the file contents at commit 123abc.
168 git show 123abc:path/to/file
169 # Diff the current version against path/to/file against the version at
170 # path/to/file
171 git diff 123abc -- path/to/file
174 When invoking `git show` or `git diff`, the `path/to/file` is **not relative the
175 the current directory**. It must be the full path from the directory where the
176 .git directory lives. This is different from invoking `git log` which
177 understands relative paths.
179 ## Checking out pristine branch from git-svn
181 In the backend, git-svn keeps a remote tracking branch that points to the the
182 commit tree representing the svn repository. The name of this branch is
183 configured during `git svn init`. The git-svn remote branch is often named
184 `origin/trunk` for Chromium, and `origin/master` for WebKit.
186 If you want to checkout a "fresh" branch, you can base it directly off the
187 remote branch for svn.
189     git checkout -b fresh origin/trunk  # Replace with origin/master for webkit.
192 To find out what your git-svn remote branch name is, you can examine your
193 `.git/config` file and look for the `svn-remote` entry. It will look something
194 like this:
197 [svn-remote "svn"]
198         url = svn://svn.chromium.org/chrome
199         fetch = trunk/src:refs/remotes/origin/trunk
202 The last line (`fetch = trunk/src:refs/remotes/origin/trunk`), says to make
203 `trunk/src` on svn into `refs/remote/origin/trunk` in the local git checkout.
204 Which means, the name of the svn remote branch name is `origin/trunk`. You can
205 use this branch name for all sorts of actions (diff, log, show, etc.)
207 ## Making your `git svn {fetch,rebase}` go fast
209 If you are pulling changes from the git repository in Chromium (or WebKit), but
210 your your `git svn` commands still seem to pull each change individually from
211 svn, your repository is probably setup incorrectly. Make sure the entries in
212 your `.git/config` look something like this:
215 [remote "origin"]
216         url = https://chromium.googlesource.com/chromium/src.git
217         fetch = +refs/heads/*:refs/remotes/origin/*
218 [svn-remote "svn"]
219         url = svn://svn.chromium.org/chrome
220         fetch = trunk/src:refs/remotes/origin/trunk
223 Here, `git svn fetch` will update the hash in refs/remotes/origin/trunk as per
224 the `fetch =` line under `svn-remote`. Similarly, `git fetch` will update the
225 **same** tag under `refs/remotes/origin`.
227 With this setup, `git fetch` will use the faster git protocol to pull changes
228 down into `origin/trunk`. This effectively updates the high-water mark for
229 `git-svn`. Later invocations of `git svn {find-rev, fetch, rebase}` will be be
230 able to skip pulling those revisions down from the svn server. Instead, it
231 will just run a regex over the commit log in `origin/trunk` and parse all the
232 `git-svn-id` lines. To rebuild the mapping. Example:
235 commit 016d28b8c4959a3d28d2fbfb4b86c0361aad74ef
236 Author: mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
237 Date:   Mon Jul 19 19:09:41 2010 +0000
239     Revert r42636. That hack is no longer needed now that we removed the compact
240     location bar view.
242     BUG=38992
244     Review URL: http://codereview.chromium.org/3036004
246     git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52935 0039d316-1c4b-4281-b951-d872f2087c98
249 Will be parsed to map svn revision r52935 (on Google Code) to commit
250 016d28b8c4959a3d28d2fbfb4b86c0361aad74ef. The parsing will generate a lot of
251 lines that look like `rXXXX = 01234ABCD`. It should generally take a minute or
252 so when doing an incremental update.
254 For this to work, two things must be true:
256 *   The svn url in the `svn-remote` clause must exactly match the url in the
257     git-svn-id pulled form the server.
258 *   The fetch from origin must write into the exact same branch that specified
259     in the fetch line of `svn-remote`.
261 If either of these are not true, then `git svn fetch` and friends will talk to
262 svn directly, and be very slow.
264 ## Reusing a Git mirror
266 If you have a nearby copy of a Git repo, you can quickly bootstrap your copy
267 from that one then adjust it to point it at the real upstream one.
269 1.  Clone a nearby copy of the code you want: `git clone coworker-machine:/path/to/repo`
270 1.  Change the URL your copy fetches from to point at the real git repo:
271     `git set-url origin http://src.chromium.org/git/chromium.git`
272 1.  Update your copy: `git fetch`
273 1.  Delete any extra branches that you picked up in the initial clone:
274     `git prune origin`