blob: 141db65fba59dc5d354d1a9fa059ed86db2ffeac [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
qyearsleyc0dc6f42016-12-02 22:13:3912git, git-cl, and how they work with Chromium development. It might be a little
andybons22afb312015-08-31 02:24:5113light 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
Aaron Gablebbc51dc2017-05-17 18:45:5422## Chromium-specific Git Extensions
23
24Chromium ships a large number of git extensions in depot_tools. Some (like
25`git cl`) are required for the Chromium development workflow, while others
26(like `git map-branches`) are simple utilities to make your life easier.
27Please take a look at the full
28[depot_tools tutorial](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html),
29and at the extensive
30[man pages](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools.html)
31for all the extensions.
32
andybons3322f762015-08-24 21:37:0933## Excluding file(s) from git-cl, while preserving them for later use
34
andybons22afb312015-08-31 02:24:5135Since git-cl assumes that the diff between your current branch and its tracking
36branch (defaults to the svn-trunk if there is no tracking branch) is what should
37be used for the CL, the goal is to remove the unwanted files from the current
38branch, and preserve them in another branch, or a similar.
andybons3322f762015-08-24 21:37:0939
40### Method #1: Reset your current branch, and selectively commit files.
41
andybons22afb312015-08-31 02:24:51421. `git log` See the list of your commits. Find the hash of the last commit
43 before your changes.
441. `git reset --soft abcdef` where abcdef is the hash found in the step above.
451. `git commit <files_for_this_cl> -m "files to upload"` commit the files you
46 want included in the CL here.
471. `git checkout -b new_branch_name origin/trunk` Create a new branch for the
48 files that you want to exclude.
491. `git commit -a -m "preserved files"` Commit the rest of the files.
andybons3322f762015-08-24 21:37:0950
51### Method #2: Create a new branch, reset, then commit files to preserve
andybons3322f762015-08-24 21:37:0952
andybons22afb312015-08-31 02:24:5153This method creates a new branch from your current one to preserve your changes.
54The commits on the new branch are undone, and then only the files you want to
55preserve are recommitted.
andybons3322f762015-08-24 21:37:0956
andybons22afb312015-08-31 02:24:51571. `git checkout -b new_branch_name` This preserves your old files.
581. `git log` See the list of your commits. Find the hash of the last commit
59 before your changes.
601. `git reset --soft abcdef` Where abcdef is the hash found in the step above.
611. `git commit <files_to_preserve> -m "preserved files"` Commit the found files
62 into the `new_branch_name`.
63
64Then revert your files however you'd like in your old branch. The files listed
65in step 4 will be saved in `new_branch_name`
andybons3322f762015-08-24 21:37:0966
67### Method #3: Cherry pick changes into review branches
andybons3322f762015-08-24 21:37:0968
andybons22afb312015-08-31 02:24:5169If you are systematic in creating separate local commits for independent
70changes, you can make a number of different changes in the same client and then
71cherry-pick each one into a separate review branch.
andybons3322f762015-08-24 21:37:0972
andybons22afb312015-08-31 02:24:51731. Make and commit a set of independent changes.
741. `git log` # see the hashes for each of your commits.
751. repeat checkout, cherry-pick, upload steps for each change1..n
76 1. `git checkout -b review-changeN origin` Create a new review branch
77 tracking origin
78 1. `git cherry-pick <hash of change N>`
79 1. `git cl upload`
andybons3322f762015-08-24 21:37:0980
andybons22afb312015-08-31 02:24:5181If a change needs updating due to review comments, you can go back to your main
82working branch, update the commit, and re-cherry-pick it into the review branch.
83
841. `git checkout <working branch>`
851. Make changes.
861. If the commit you want to update is the most recent one:
87 1. `git commit --amend <files>`
881. If not:
89 1. `git commit <files>`
90 1. `git rebase -i origin` # use interactive rebase to squash the new
91 commit into the old one.
921. `git log` # observe new hash for the change
931. `git checkout review-changeN`
941. `git reset --hard` # remove the previous version of the change
951. `cherry-pick <new hash of change N>`
961. `git cl upload`
andybons3322f762015-08-24 21:37:0997
98## Sharing code between multiple machines
andybons22afb312015-08-31 02:24:5199
andybons3322f762015-08-24 21:37:09100Assume Windows computer named vista, Linux one named penguin.
101Prerequisite: both machine have git clones of the main git tree.
andybons22afb312015-08-31 02:24:51102
103```shell
andybons3322f762015-08-24 21:37:09104vista$ git remote add linux ssh://penguin/path/to/git/repo
105vista$ git fetch linux
106vista$ git branch -a # should show "linux/branchname"
107vista$ git checkout -b foobar linux/foobar
108vista$ hack hack hack; git commit -a
109vista$ git push linux # push branch back to linux
110penguin$ git reset --hard # update with new stuff in branch
111```
112
andybons22afb312015-08-31 02:24:51113Note that, by default, `gclient sync` will update all remotes. If your other
114machine (i.e., `penguin` in the above example) is not always available,
115`gclient sync` will timeout and fail trying to reach it. To fix this, you may
116exclude your machine from being fetched by default:
andybons3322f762015-08-24 21:37:09117
andybons22afb312015-08-31 02:24:51118 vista$ git config --bool remote.linux.skipDefaultUpdate true
andybons3322f762015-08-24 21:37:09119
120## Reverting and undoing reverts
andybons3322f762015-08-24 21:37:09121
andybons22afb312015-08-31 02:24:51122Two commands to be familiar with:
123
124* `git cherry-pick X` -- patch in the change made in revision X (where X is a
125 hash, or HEAD~2, or whatever).
126* `git revert X` -- patch in the **inverse** of the change made.
127
128With that in hand, say you learned that the commit `abcdef` you just made was
129bad.
andybons3322f762015-08-24 21:37:09130
131Revert it locally:
andybons22afb312015-08-31 02:24:51132
133```shell
134git checkout origin # start with trunk
135git show abcdef # grab the svn revision that abcdef was
136git revert abcdef
andybons3322f762015-08-24 21:37:09137# an editor will pop up; be sure to replace the unhelpful git hash
138# in the commit message with the svn revision number
139```
140
141Commit the revert:
andybons22afb312015-08-31 02:24:51142
143```shell
andybons3322f762015-08-24 21:37:09144# note that since "git svn dcommit" commits each local change separately, be
andybons22afb312015-08-31 02:24:51145# extra sure that your commit log looks exactly like what you want the tree's
146# commit log to look like before you do this.
147git log # double check that the commit log is *exactly* what you want
148git svn dcommit # commit to svn, bypassing all precommit checks and prompts
andybons3322f762015-08-24 21:37:09149```
150
151Roll it forward again locally:
andybons3322f762015-08-24 21:37:09152
andybons22afb312015-08-31 02:24:51153```shell
154# go back to your old branch again, and reset the branch to origin, which now
155# has your revert.
156git checkout mybranch
157git reset --hard origin
158
159
160git cherry-pick abcdef # re-apply your bad change
161git show # grab the rietveld issue number out of the old commit
162git cl issue 12345 # restore the rietveld issue that was cleared on commit
andybons3322f762015-08-24 21:37:09163```
164
andybons22afb312015-08-31 02:24:51165And now you can continue hacking where you left off, and since you're reusing
qyearsleyc0dc6f42016-12-02 22:13:39166the Rietveld issue you don't have to rewrite the commit message. (You may want
andybons22afb312015-08-31 02:24:51167to go manually reopen the issue on the Rietveld site -- `git cl status` will
168give you the URL.)
andybons3322f762015-08-24 21:37:09169
170## Retrieving, or diffing against an old file revision
andybons22afb312015-08-31 02:24:51171
172Git works in terms of commits, not files. Thus, working with the history of a
173single file requires modified version of the show and diff commands.
174
175```shell
176# Find the commit you want in the file's commit log.
177git log path/to/file
178# This prints out the file contents at commit 123abc.
179git show 123abc:path/to/file
180# Diff the current version against path/to/file against the version at
181# path/to/file
182git diff 123abc -- path/to/file
andybons3322f762015-08-24 21:37:09183```
184
andybons22afb312015-08-31 02:24:51185When invoking `git show` or `git diff`, the `path/to/file` is **not relative the
186the current directory**. It must be the full path from the directory where the
187.git directory lives. This is different from invoking `git log` which
188understands relative paths.
andybons3322f762015-08-24 21:37:09189
190## Checking out pristine branch from git-svn
andybons3322f762015-08-24 21:37:09191
qyearsleyc0dc6f42016-12-02 22:13:39192In the backend, git-svn keeps a remote tracking branch that points to the
andybons22afb312015-08-31 02:24:51193commit tree representing the svn repository. The name of this branch is
194configured during `git svn init`. The git-svn remote branch is often named
195`origin/trunk` for Chromium, and `origin/master` for WebKit.
andybons3322f762015-08-24 21:37:09196
andybons22afb312015-08-31 02:24:51197If you want to checkout a "fresh" branch, you can base it directly off the
198remote branch for svn.
andybons3322f762015-08-24 21:37:09199
andybons22afb312015-08-31 02:24:51200 git checkout -b fresh origin/trunk # Replace with origin/master for webkit.
201
202
203To find out what your git-svn remote branch name is, you can examine your
204`.git/config` file and look for the `svn-remote` entry. It will look something
205like this:
andybons3322f762015-08-24 21:37:09206
207```
208[svn-remote "svn"]
209 url = svn://svn.chromium.org/chrome
210 fetch = trunk/src:refs/remotes/origin/trunk
211```
212
andybons22afb312015-08-31 02:24:51213The last line (`fetch = trunk/src:refs/remotes/origin/trunk`), says to make
214`trunk/src` on svn into `refs/remote/origin/trunk` in the local git checkout.
215Which means, the name of the svn remote branch name is `origin/trunk`. You can
216use this branch name for all sorts of actions (diff, log, show, etc.)
andybons3322f762015-08-24 21:37:09217
218## Making your `git svn {fetch,rebase}` go fast
andybons22afb312015-08-31 02:24:51219
220If you are pulling changes from the git repository in Chromium (or WebKit), but
221your your `git svn` commands still seem to pull each change individually from
222svn, your repository is probably setup incorrectly. Make sure the entries in
223your `.git/config` look something like this:
andybons3322f762015-08-24 21:37:09224
225```
226[remote "origin"]
227 url = https://chromium.googlesource.com/chromium/src.git
228 fetch = +refs/heads/*:refs/remotes/origin/*
229[svn-remote "svn"]
230 url = svn://svn.chromium.org/chrome
231 fetch = trunk/src:refs/remotes/origin/trunk
232```
233
andybons22afb312015-08-31 02:24:51234Here, `git svn fetch` will update the hash in refs/remotes/origin/trunk as per
235the `fetch =` line under `svn-remote`. Similarly, `git fetch` will update the
236**same** tag under `refs/remotes/origin`.
andybons3322f762015-08-24 21:37:09237
andybons22afb312015-08-31 02:24:51238With this setup, `git fetch` will use the faster git protocol to pull changes
239down into `origin/trunk`. This effectively updates the high-water mark for
240`git-svn`. Later invocations of `git svn {find-rev, fetch, rebase}` will be be
241able to skip pulling those revisions down from the svn server. Instead, it
242will just run a regex over the commit log in `origin/trunk` and parse all the
243`git-svn-id` lines. To rebuild the mapping. Example:
andybons3322f762015-08-24 21:37:09244
245```
246commit 016d28b8c4959a3d28d2fbfb4b86c0361aad74ef
247Author: mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
248Date: Mon Jul 19 19:09:41 2010 +0000
249
250 Revert r42636. That hack is no longer needed now that we removed the compact
251 location bar view.
andybons22afb312015-08-31 02:24:51252
andybons3322f762015-08-24 21:37:09253 BUG=38992
andybons22afb312015-08-31 02:24:51254
xiaoyin.l1003c0b2016-12-06 02:51:17255 Review URL: https://codereview.chromium.org/3036004
andybons3322f762015-08-24 21:37:09256
257 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52935 0039d316-1c4b-4281-b951-d872f2087c98
258```
259
andybons22afb312015-08-31 02:24:51260Will be parsed to map svn revision r52935 (on Google Code) to commit
261016d28b8c4959a3d28d2fbfb4b86c0361aad74ef. The parsing will generate a lot of
262lines that look like `rXXXX = 01234ABCD`. It should generally take a minute or
263so when doing an incremental update.
andybons3322f762015-08-24 21:37:09264
265For this to work, two things must be true:
266
andybons22afb312015-08-31 02:24:51267* The svn url in the `svn-remote` clause must exactly match the url in the
268 git-svn-id pulled form the server.
269* The fetch from origin must write into the exact same branch that specified
270 in the fetch line of `svn-remote`.
andybons3322f762015-08-24 21:37:09271
andybons22afb312015-08-31 02:24:51272If either of these are not true, then `git svn fetch` and friends will talk to
273svn directly, and be very slow.
andybons3322f762015-08-24 21:37:09274
275## Reusing a Git mirror
276
andybons22afb312015-08-31 02:24:51277If you have a nearby copy of a Git repo, you can quickly bootstrap your copy
278from that one then adjust it to point it at the real upstream one.
andybons3322f762015-08-24 21:37:09279
andybons22afb312015-08-31 02:24:512801. Clone a nearby copy of the code you want: `git clone coworker-machine:/path/to/repo`
2811. Change the URL your copy fetches from to point at the real git repo:
xiaoyin.l1003c0b2016-12-06 02:51:17282 `git set-url origin https://src.chromium.org/git/chromium.git`
andybons22afb312015-08-31 02:24:512831. Update your copy: `git fetch`
2841. Delete any extra branches that you picked up in the initial clone:
285 `git prune origin`