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