| # Git Tips | |
| When using Git, there are a few tips that are particularly useful when working | |
| on the Chromium codebase, especially due to its size. | |
| [TOC] | |
| ## Remember the basic git convention: | |
| git COMMAND [FLAGS] [ARGUMENTS] | |
| Various git commands have underlying executable with a hyphenated name, such as | |
| `git-grep`, but these can also be called via the `git` wrapper script as | |
| `git grep` (and `man` should work either way too). | |
| ## Git references | |
| The following resources can provide background on how Git works: | |
| * [Git-SVN Crash Course](http://git-scm.com/course/svn.html) -- this crash | |
| course is useful for Subversion users switching to Git. | |
| * [Think Like (a) Git](http://think-like-a-git.net/) -- does a great job of | |
| explaining the main purpose of Git operations. | |
| * [Git User's Manual](http://schacon.github.com/git/user-manual.html) -- a | |
| great resource to learn more about ho to use Git properly. | |
| * [A Visual Git Reference](https://marklodato.github.io/visual-git-guide/index-en.html) | |
| -- a resource that explains various Git operations for visual learners. | |
| * [Git Cheat Sheet](http://cheat.errtheblog.com/s/git) -- now that you | |
| understand Git, here's a cheat sheet to quickly remind you of all the | |
| commands you need. | |
| ## Optimizing (Speeding up) Git for a Large Repository | |
| Git has numerous options, among which some are intended to optimize for large | |
| repositories. | |
| [feature.manyFiles](https://git-scm.com/docs/git-config#Documentation/git-config.txt-featuremanyFiles) | |
| is a convenient option that turns on the group of options that optimize for | |
| large repositories. Run the following inside the Chromium git repository: | |
| git config feature.manyFiles true | |
| ## Configuring the output of "git log" | |
| By default, the date that "git log" displays is the "author date." In Chromium, | |
| this generally corresponds to the date that the committed patch was last | |
| uploaded. In most cases, however, the date that is of interest is the date that | |
| the patch was committed in the tree. To configure "git log" to instead display | |
| the latter date for your Chromium checkout, execute the following command: | |
| ```shell | |
| git config format.pretty 'format:%C(auto,yellow)commit %H%C(auto)%d%nAuthor: %an <%ae>%nCommitted: %cd%n%n%w(0,4,4)%B%-%n' | |
| ``` | |
| If you want to change *all* your repos (e.g., because you have multiple Chromium | |
| checkouts and don't care about having the default for other repos), add | |
| "--global" after "config" in the above command. | |
| ## Committing changes | |
| For a simple workflow (always commit all changed files, don't keep local | |
| revisions), the following script handles check; you may wish to call it `gci` | |
| (git commit) or similar. | |
| Amending a single revision is generally easier for various reasons, notably for | |
| rebasing and for checking that CLs have been committed. However, if you don't | |
| use local revisions (a local branch with multiple revisions), you should make | |
| sure to upload revisions periodically to code review if you ever need to go to | |
| an old version of a CL. | |
| ```bash | |
| #!/bin/bash | |
| # Commit all, amending if not initial commit. | |
| if git status | grep -q "Your branch is ahead of 'origin/main' by 1 commit." | |
| then | |
| git commit --all --amend | |
| else | |
| git commit --all # initial, not amendment | |
| fi | |
| ``` | |
| ## Listing and changing branches | |
| ```shell | |
| git branch # list branches | |
| git checkout - # change to last branch | |
| ``` | |
| To quickly list the 5 most recent branches, add the following to `.gitconfig` | |
| in the `[alias]` section: | |
| ```shell | |
| last5 = "!git for-each-ref --sort=committerdate refs/heads/ \ | |
| --format='%(committerdate:short) %(refname:short)' | tail -5 | cut -c 12-" | |
| ``` | |
| A nicely color-coded list, sorted in descending order by date, can be made by | |
| the following bash function: | |
| ```bash | |
| git-list-branches-by-date() { | |
| local current_branch=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD) | |
| local normal_text=$(echo -ne '\E[0m') | |
| local yellow_text=$(echo -ne '\E[0;33m') | |
| local yellow_bg=$(echo -ne '\E[7;33m') | |
| git for-each-ref --sort=-committerdate \ | |
| --format=$' %(refname:short) \ | |
| \t%(committerdate:short)\t%(authorname)\t%(objectname:short)' \ | |
| refs/heads \ | |
| | column -t -s $'\t' -n \ | |
| | sed -E "s:^ (${current_branch}) :* ${yellow_bg}\1${normal_text} :" \ | |
| | sed -E "s:^ ([^ ]+): ${yellow_text}\1${normal_text}:" | |
| } | |
| ``` | |
| ## Searching | |
| Use `git-grep` instead of `grep` and `git-ls-files` instead of `find`, as these | |
| search only files in the index or _tracked_ files in the work tree, rather than | |
| all files in the work tree. | |
| Note that `git-ls-files` is rather simpler than `find`, so you'll often need to | |
| use `xargs` instead of `-exec` if you want to process matching files. | |
| ## Global changes | |
| To make global changes across the source tree, it's often easiest to use `sed` | |
| with `git-ls-files`, using `-i` for in-place changing (this is generally safe, | |
| as we don't use symlinks much, but there are few places that do). Remember that | |
| you don't need to use `xargs`, since sed can take multiple input files. E.g., to | |
| strip trailing whitespace from C++ and header files: | |
| sed -i -E 's/\s+$//' $(git ls-files '*.cpp' '*.h') | |
| You may also find `git-grep` useful for limiting the scope of your changes, | |
| using `-l` for listing files. | |
| sed -i -E '...' $(git grep -lw Foo '*.cpp' '*.h') | |
| Remember that you can restrict sed actions to matching (or non-matching) lines. | |
| For example, to skip lines with a line comment, use the following: | |
| '\,//, ! s/foo/bar/g' | |
| ## Diffs | |
| git diff --shortstat | |
| Displays summary statistics, such as: | |
| 2104 files changed, 9309 insertions(+), 9309 deletions(-) |