blob: d42b63da4d00df89fd65998483ee37c4523f75f9 [file] [log] [blame] [view]
andybons22afb312015-08-31 02:24:511# Git Cookbook
2
andybons3322f762015-08-24 21:37:093A collection of git recipes to do common git tasks.
4
andybons22afb312015-08-31 02:24:515See also [Git Tips](git_tips.md).
andybons3322f762015-08-24 21:37:096
andybons22afb312015-08-31 02:24:517[TOC]
andybons3322f762015-08-24 21:37:098
9## Introduction
10
andybons22afb312015-08-31 02:24:5111This is designed to be a cookbook for common command sequences/tasks relating to
12git, git-cl, and how they work with chromium development. It might be a little
13light on explanations.
andybons3322f762015-08-24 21:37:0914
andybons22afb312015-08-31 02:24:5115If you are new to git, or do not have much experience with a distributed version
16control system, you should also check out
17[The Git Community Book](http://book.git-scm.com/) for an overview of basic git
18concepts and general git usage. Knowing what git means by branches, commits,
19reverts, and resets (as opposed to what SVN means by them) will help make the
20following much more understandable.
andybons3322f762015-08-24 21:37:0921
22## Excluding file(s) from git-cl, while preserving them for later use
23
andybons22afb312015-08-31 02:24:5124Since git-cl assumes that the diff between your current branch and its tracking
25branch (defaults to the svn-trunk if there is no tracking branch) is what should
26be used for the CL, the goal is to remove the unwanted files from the current
27branch, and preserve them in another branch, or a similar.
andybons3322f762015-08-24 21:37:0928
29### Method #1: Reset your current branch, and selectively commit files.
30
andybons22afb312015-08-31 02:24:51311. `git log` See the list of your commits. Find the hash of the last commit
32 before your changes.
331. `git reset --soft abcdef` where abcdef is the hash found in the step above.
341. `git commit <files_for_this_cl> -m "files to upload"` commit the files you
35 want included in the CL here.
361. `git checkout -b new_branch_name origin/trunk` Create a new branch for the
37 files that you want to exclude.
381. `git commit -a -m "preserved files"` Commit the rest of the files.
andybons3322f762015-08-24 21:37:0939
40### Method #2: Create a new branch, reset, then commit files to preserve
andybons3322f762015-08-24 21:37:0941
andybons22afb312015-08-31 02:24:5142This method creates a new branch from your current one to preserve your changes.
43The commits on the new branch are undone, and then only the files you want to
44preserve are recommitted.
andybons3322f762015-08-24 21:37:0945
andybons22afb312015-08-31 02:24:51461. `git checkout -b new_branch_name` This preserves your old files.
471. `git log` See the list of your commits. Find the hash of the last commit
48 before your changes.
491. `git reset --soft abcdef` Where abcdef is the hash found in the step above.
501. `git commit <files_to_preserve> -m "preserved files"` Commit the found files
51 into the `new_branch_name`.
52
53Then revert your files however you'd like in your old branch. The files listed
54in step 4 will be saved in `new_branch_name`
andybons3322f762015-08-24 21:37:0955
56### Method #3: Cherry pick changes into review branches
andybons3322f762015-08-24 21:37:0957
andybons22afb312015-08-31 02:24:5158If you are systematic in creating separate local commits for independent
59changes, you can make a number of different changes in the same client and then
60cherry-pick each one into a separate review branch.
andybons3322f762015-08-24 21:37:0961
andybons22afb312015-08-31 02:24:51621. Make and commit a set of independent changes.
631. `git log` # see the hashes for each of your commits.
641. 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`
andybons3322f762015-08-24 21:37:0969
andybons22afb312015-08-31 02:24:5170If a change needs updating due to review comments, you can go back to your main
71working branch, update the commit, and re-cherry-pick it into the review branch.
72
731. `git checkout <working branch>`
741. Make changes.
751. If the commit you want to update is the most recent one:
76 1. `git commit --amend <files>`
771. 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.
811. `git log` # observe new hash for the change
821. `git checkout review-changeN`
831. `git reset --hard` # remove the previous version of the change
841. `cherry-pick <new hash of change N>`
851. `git cl upload`
andybons3322f762015-08-24 21:37:0986
87## Sharing code between multiple machines
andybons22afb312015-08-31 02:24:5188
andybons3322f762015-08-24 21:37:0989Assume Windows computer named vista, Linux one named penguin.
90Prerequisite: both machine have git clones of the main git tree.
andybons22afb312015-08-31 02:24:5191
92```shell
andybons3322f762015-08-24 21:37:0993vista$ git remote add linux ssh://penguin/path/to/git/repo
94vista$ git fetch linux
95vista$ git branch -a # should show "linux/branchname"
96vista$ git checkout -b foobar linux/foobar
97vista$ hack hack hack; git commit -a
98vista$ git push linux # push branch back to linux
99penguin$ git reset --hard # update with new stuff in branch
100```
101
andybons22afb312015-08-31 02:24:51102Note that, by default, `gclient sync` will update all remotes. If your other
103machine (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
105exclude your machine from being fetched by default:
andybons3322f762015-08-24 21:37:09106
andybons22afb312015-08-31 02:24:51107 vista$ git config --bool remote.linux.skipDefaultUpdate true
andybons3322f762015-08-24 21:37:09108
109## Reverting and undoing reverts
andybons3322f762015-08-24 21:37:09110
andybons22afb312015-08-31 02:24:51111Two commands to be familiar with:
112
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
117With that in hand, say you learned that the commit `abcdef` you just made was
118bad.
andybons3322f762015-08-24 21:37:09119
120Revert it locally:
andybons22afb312015-08-31 02:24:51121
122```shell
123git checkout origin # start with trunk
124git show abcdef # grab the svn revision that abcdef was
125git revert abcdef
andybons3322f762015-08-24 21:37:09126# an editor will pop up; be sure to replace the unhelpful git hash
127# in the commit message with the svn revision number
128```
129
130Commit the revert:
andybons22afb312015-08-31 02:24:51131
132```shell
andybons3322f762015-08-24 21:37:09133# note that since "git svn dcommit" commits each local change separately, be
andybons22afb312015-08-31 02:24:51134# 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.
136git log # double check that the commit log is *exactly* what you want
137git svn dcommit # commit to svn, bypassing all precommit checks and prompts
andybons3322f762015-08-24 21:37:09138```
139
140Roll it forward again locally:
andybons3322f762015-08-24 21:37:09141
andybons22afb312015-08-31 02:24:51142```shell
143# go back to your old branch again, and reset the branch to origin, which now
144# has your revert.
145git checkout mybranch
146git reset --hard origin
147
148
149git cherry-pick abcdef # re-apply your bad change
150git show # grab the rietveld issue number out of the old commit
151git cl issue 12345 # restore the rietveld issue that was cleared on commit
andybons3322f762015-08-24 21:37:09152```
153
andybons22afb312015-08-31 02:24:51154And now you can continue hacking where you left off, and since you're reusing
155the Reitveld issue you don't have to rewrite the commit message. (You may want
156to go manually reopen the issue on the Rietveld site -- `git cl status` will
157give you the URL.)
andybons3322f762015-08-24 21:37:09158
159## Retrieving, or diffing against an old file revision
andybons22afb312015-08-31 02:24:51160
161Git works in terms of commits, not files. Thus, working with the history of a
162single file requires modified version of the show and diff commands.
163
164```shell
165# Find the commit you want in the file's commit log.
166git log path/to/file
167# This prints out the file contents at commit 123abc.
168git show 123abc:path/to/file
169# Diff the current version against path/to/file against the version at
170# path/to/file
171git diff 123abc -- path/to/file
andybons3322f762015-08-24 21:37:09172```
173
andybons22afb312015-08-31 02:24:51174When invoking `git show` or `git diff`, the `path/to/file` is **not relative the
175the 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
177understands relative paths.
andybons3322f762015-08-24 21:37:09178
179## Checking out pristine branch from git-svn
andybons3322f762015-08-24 21:37:09180
andybons22afb312015-08-31 02:24:51181In the backend, git-svn keeps a remote tracking branch that points to the the
182commit tree representing the svn repository. The name of this branch is
183configured during `git svn init`. The git-svn remote branch is often named
184`origin/trunk` for Chromium, and `origin/master` for WebKit.
andybons3322f762015-08-24 21:37:09185
andybons22afb312015-08-31 02:24:51186If you want to checkout a "fresh" branch, you can base it directly off the
187remote branch for svn.
andybons3322f762015-08-24 21:37:09188
andybons22afb312015-08-31 02:24:51189 git checkout -b fresh origin/trunk # Replace with origin/master for webkit.
190
191
192To 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
194like this:
andybons3322f762015-08-24 21:37:09195
196```
197[svn-remote "svn"]
198 url = svn://svn.chromium.org/chrome
199 fetch = trunk/src:refs/remotes/origin/trunk
200```
201
andybons22afb312015-08-31 02:24:51202The 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.
204Which means, the name of the svn remote branch name is `origin/trunk`. You can
205use this branch name for all sorts of actions (diff, log, show, etc.)
andybons3322f762015-08-24 21:37:09206
207## Making your `git svn {fetch,rebase}` go fast
andybons22afb312015-08-31 02:24:51208
209If you are pulling changes from the git repository in Chromium (or WebKit), but
210your your `git svn` commands still seem to pull each change individually from
211svn, your repository is probably setup incorrectly. Make sure the entries in
212your `.git/config` look something like this:
andybons3322f762015-08-24 21:37:09213
214```
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
221```
222
andybons22afb312015-08-31 02:24:51223Here, `git svn fetch` will update the hash in refs/remotes/origin/trunk as per
224the `fetch =` line under `svn-remote`. Similarly, `git fetch` will update the
225**same** tag under `refs/remotes/origin`.
andybons3322f762015-08-24 21:37:09226
andybons22afb312015-08-31 02:24:51227With this setup, `git fetch` will use the faster git protocol to pull changes
228down 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
230able to skip pulling those revisions down from the svn server. Instead, it
231will 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:
andybons3322f762015-08-24 21:37:09233
234```
235commit 016d28b8c4959a3d28d2fbfb4b86c0361aad74ef
236Author: [email protected] <[email protected]@0039d316-1c4b-4281-b951-d872f2087c98>
237Date: Mon Jul 19 19:09:41 2010 +0000
238
239 Revert r42636. That hack is no longer needed now that we removed the compact
240 location bar view.
andybons22afb312015-08-31 02:24:51241
andybons3322f762015-08-24 21:37:09242 BUG=38992
andybons22afb312015-08-31 02:24:51243
andybons3322f762015-08-24 21:37:09244 Review URL: http://codereview.chromium.org/3036004
245
246 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52935 0039d316-1c4b-4281-b951-d872f2087c98
247```
248
andybons22afb312015-08-31 02:24:51249Will be parsed to map svn revision r52935 (on Google Code) to commit
250016d28b8c4959a3d28d2fbfb4b86c0361aad74ef. The parsing will generate a lot of
251lines that look like `rXXXX = 01234ABCD`. It should generally take a minute or
252so when doing an incremental update.
andybons3322f762015-08-24 21:37:09253
254For this to work, two things must be true:
255
andybons22afb312015-08-31 02:24:51256* 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`.
andybons3322f762015-08-24 21:37:09260
andybons22afb312015-08-31 02:24:51261If either of these are not true, then `git svn fetch` and friends will talk to
262svn directly, and be very slow.
andybons3322f762015-08-24 21:37:09263
264## Reusing a Git mirror
265
andybons22afb312015-08-31 02:24:51266If you have a nearby copy of a Git repo, you can quickly bootstrap your copy
267from that one then adjust it to point it at the real upstream one.
andybons3322f762015-08-24 21:37:09268
andybons22afb312015-08-31 02:24:512691. Clone a nearby copy of the code you want: `git clone coworker-machine:/path/to/repo`
2701. 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`
2721. Update your copy: `git fetch`
2731. Delete any extra branches that you picked up in the initial clone:
274 `git prune origin`