1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151

docs / git_tips.md [blame]

# 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(-)