|  | # Git Cookbook | 
|  |  | 
|  | A collection of git recipes to do common git tasks. | 
|  |  | 
|  | See also [Git Tips](git_tips.md). | 
|  |  | 
|  | [TOC] | 
|  |  | 
|  | ## Introduction | 
|  |  | 
|  | 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. | 
|  |  | 
|  | 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. Knowing 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. | 
|  |  | 
|  | ## Chromium-specific Git Extensions | 
|  |  | 
|  | Chromium ships a large number of git extensions in depot_tools. Some (like | 
|  | `git cl`) are required for the Chromium development workflow, while others | 
|  | (like `git map-branches`) are simple utilities to make your life easier. | 
|  | Please take a look at the full | 
|  | [depot_tools tutorial](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html), | 
|  | and at the extensive | 
|  | [man pages](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools.html) | 
|  | for all the extensions. | 
|  |  | 
|  | ## Excluding file(s) from git-cl, while preserving them for later use | 
|  |  | 
|  | Since git-cl assumes that the diff between your current branch and its tracking | 
|  | branch is what should be used for the CL, the goal is to remove the unwanted | 
|  | files from the current branch, and preserve them in another branch. | 
|  |  | 
|  | ### Method #1: Reset your current branch, and selectively commit files | 
|  |  | 
|  | 1.  `git log`  See the list of your commits. Find the hash of the last commit | 
|  | before your changes. | 
|  | 1.  `git reset --soft abcdef` where abcdef is the hash found in the step above. | 
|  | 1.  `git commit <files_for_this_cl> -m "files to upload"` commit the files you | 
|  | want included in the CL here. | 
|  | 1.  `git new-branch new_branch_name` Create a new branch for the | 
|  | files that you want to exclude. | 
|  | 1.  `git commit -a -m "preserved files"` Commit the rest of the files. | 
|  |  | 
|  | ### Method #2: Create a new branch, reset, then commit files to preserve | 
|  |  | 
|  | 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. | 
|  |  | 
|  | 1.  `git checkout -b new_branch_name` This preserves your old files. | 
|  | 1.  `git log` See the list of your commits. Find the hash of the last commit | 
|  | before your changes. | 
|  | 1.  `git reset --soft abcdef` Where abcdef is the hash found in the step above. | 
|  | 1.  `git commit <files_to_preserve> -m "preserved files"` Commit the found files | 
|  | into the `new_branch_name`. | 
|  |  | 
|  | 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` | 
|  |  | 
|  | ### Method #3: Cherry-pick changes into review branches | 
|  |  | 
|  | 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. | 
|  |  | 
|  | 1.  Make and commit a set of independent changes. | 
|  | 1.  `git log`  # see the hashes for each of your commits. | 
|  | 1.  repeat checkout, cherry-pick, upload steps for each change1..n | 
|  | 1.  `git new-branch review-changeN` Create a new review branch | 
|  | tracking origin | 
|  | 1.  `git cherry-pick <hash of change N>` | 
|  | 1.  `git cl upload` | 
|  |  | 
|  | 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. | 
|  |  | 
|  | 1.  `git checkout <working branch>` | 
|  | 1.  Make changes. | 
|  | 1.  If the commit you want to update is the most recent one: | 
|  | 1.  `git commit --amend <files>` | 
|  | 1.  If not: | 
|  | 1.  `git commit <files>` | 
|  | 1.  `git rebase -i origin`  # use interactive rebase to squash the new | 
|  | commit into the old one. | 
|  | 1.  `git log`  # observe new hash for the change | 
|  | 1.  `git checkout review-changeN` | 
|  | 1.  `git reset --hard`  # remove the previous version of the change | 
|  | 1.  `cherry-pick <new hash of change N>` | 
|  | 1.  `git cl upload` | 
|  |  | 
|  | ## Sharing code between multiple machines | 
|  |  | 
|  | Assume Windows computer named vista, and a Linux one named penguin. | 
|  | Prerequisite: both machines have git clones of the main git tree. | 
|  |  | 
|  | ```shell | 
|  | vista$ git remote add linux ssh://penguin/path/to/git/repo | 
|  | vista$ git fetch linux | 
|  | vista$ git branch -a   # should show "linux/branchname" | 
|  | vista$ git checkout -b foobar linux/foobar | 
|  | vista$ hack hack hack; git commit -a | 
|  | vista$ git push linux  # push branch back to linux | 
|  | penguin$ git reset --hard  # update with new stuff in branch | 
|  | ``` | 
|  |  | 
|  | Note that, by default, `gclient sync` will update all remotes. If your other | 
|  | machine (i.e., `penguin` in the above example) is not always available, | 
|  | `gclient sync` will timeout and fail trying to reach it. To fix this, you may | 
|  | exclude your machine from being fetched by default: | 
|  |  | 
|  | vista$ git config --bool remote.linux.skipDefaultUpdate true | 
|  |  | 
|  | ## Reverting commits | 
|  |  | 
|  | The command `git revert X` patches in the inverse of a particular commit. | 
|  | Using this command is one way of making a revert: | 
|  |  | 
|  | ```shell | 
|  | git checkout origin   # start with trunk | 
|  | git revert abcdef | 
|  | git cl upload | 
|  | ``` | 
|  |  | 
|  | ## Retrieving, or diffing against an old file revision | 
|  |  | 
|  | Git works in terms of commits, not files. Thus, working with the history of a | 
|  | single file requires modified version of the show and diff commands. | 
|  |  | 
|  | ```shell | 
|  | # Find the commit you want in the file's commit log. | 
|  | git log path/to/file | 
|  | # This prints out the file contents at commit 123abc. | 
|  | git show 123abc:path/to/file | 
|  | # Diff the current version against path/to/file against the version at | 
|  | # path/to/file | 
|  | git diff 123abc -- path/to/file | 
|  | ``` | 
|  |  | 
|  | 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 | 
|  | understands relative paths. | 
|  |  | 
|  | ## Reusing a Git mirror | 
|  |  | 
|  | If you have a nearby copy of a Git repo, you can quickly bootstrap your copy | 
|  | from that one then adjust it to point it at the real upstream one. | 
|  |  | 
|  | 1.  Clone a nearby copy of the code you want: `git clone coworker-machine:/path/to/repo` | 
|  | 1.  Change the URL your copy fetches from to point at the real git repo: | 
|  | `git set-url origin https://chromium.googlesource.com/chromium/src.git` | 
|  | 1.  Update your copy: `git fetch` | 
|  | 1.  Delete any extra branches that you picked up in the initial clone: | 
|  | `git prune origin` |