blob: 934763961afba585623da7b737fd400bf5c4fd47 [file] [log] [blame] [view]
Josip Sokcevic79a4a542023-08-15 00:35:081# Git submodules
2
3A Git submodule is a Git repository inside another Git repository. Chromium
4project doesn't rely on Git submodules directly. Instead, gclient sync is used
5to manage Git dependencies.
6
7In 2023Q3, we started to move source of Git dependencies from DEPS files to Git
8submodules. While we do our best to hide complexities of submodules, some will
9be exposed.
10
11[TOC]
12
13## A quick introduction to Git submoduldes
14
15[Git submodules](https://git-scm.com/docs/gitsubmodules) are managed via the
16combination of `.gitmodules` files and gitlinks. `.gitmodules` is a text file
17that configures submodules, and each submodule entry contains the path to the
18submodule's worktree and the URL of the submodule. Gitlink is a special type of
19file in the Git database that tracks a submodule commit.
20
Josip Sokcevic703849e2023-08-16 00:13:3421You can find an example of Git dependency below. Note that gclient-condition is
22a custom property used by gclient and not git. It's identical to `condition` in
23`DEPS` and the allowed variables are defined in `vars = {` section of `DEPS`.
Josip Sokcevic79a4a542023-08-15 00:35:0824
25`.gitmodules`:
26
27```
28[submodule "third_party/catapult"]
29 path = third_party/catapult
30 url = https://chromium.googlesource.com/catapult.git
Josip Sokcevic703849e2023-08-16 00:13:3431 gclient-condition = checkout_linux
Josip Sokcevic79a4a542023-08-15 00:35:0832```
33
34gitlink entry, retrieved using `git ls-files -s -- third_party/catapult`:
35
36```
37160000 0b39a694c0b61392d1180520ed1c13e390029c41 0 third_party/catapult
38```
39
40Corresponding DEPS entry would look like:
41
42```
43 'third_party/catapult': {
Josip Sokcevic703849e2023-08-16 00:13:3444 'url': 'https://chromium.googlesource.com/catapult.git@0b39a694c0b61392d1180520ed1c13e390029c41',
45 'condition': 'checkout_linux',
Josip Sokcevic79a4a542023-08-15 00:35:0846}
47```
48
49## How to avoid accidental Git submodule updates?
50
André Bianchessifa2af2772024-10-03 14:50:1951The simplest approach is to always run gclient sync after updating chromium
Josip Sokcevic79a4a542023-08-15 00:35:0852checkout (e.g. after `git pull`, or `git checkout`). You can automate that by
53adding post-checkout hook (example below). To confirm there are no changes, run
54`git status`. If you use `git commit -a`, check the "Changes to be committed"
55section that shows up in the edit commit message.
56
57### Automatically run gclient sync after git pull / git checkout
58
59We need to have Git two hooks: post-checkout and post-merge. In chromium/src
60directory, edit `.git/hooks/post-checkout`:
61
62```
63#!/bin/sh
64
65set -u
66gclient sync
67```
68
69and set it to be executable: `chmod +x .git/hooks/post-checkout`. Repeat the
70same for `.git/hooks/post-merge`.
71
72More information about githooks can be found
73[here](https://git-scm.com/docs/githooks).
74
75### Git status shows modified dependencies. What does that mean?
76
77If a submodule is checked out at a different commit than one tracked by its
78parent, `git status` in the parent repo will show unstaged changes with "new
79commits" in parenthesis, such as:
80
81```
82modified: <git deps name> (new commits)
83```
84
85Commands like `git commit -a` or `git add *|.|-A|u` WILL include this in your
86commit and your CL (which is likely NOT what you want).
87
88Instead you can:
89
90```
91# Run gclient sync to sync dependencies
92gclient sync
93# check git status again
94
95# OR
96git add <file> # for each file you want to stage
97# Then commit your staged files
98git commit -v -m "Fix foo/bar"
99```
100
Josip Sokcevic79a4a542023-08-15 00:35:08101If a submodule has uncommitted changes (i.e. you made some manual changes to the
102affected submodule), running `git status` in its parent repo will show them as
103unstaged changes:
104
105```
106 modified: <git deps name> (modified content)
107
108# or
109
110 modified: <git deps name> (untracked content)
111```
112
113It's not possible to add those changes to the parent repository. You can ignore
114such status, or you can cd into submodule and address it. E.g. you may delete
115untracked files (content) or reset modified content to match HEAD.
116
117## I accidentally staged Git submodule (not yet committed)
118
119If you accidentally stage a Git submodule, you can unstage it by running `git
120restore --staged <path to submodule>`.
121
122## I accidentally committed Git submodule
123
124We will need to create either a commit that sets it back to old value, or amend
125the commit that added it. You can try to run `gclient sync` to bring the commit
126back to what is expected. If that doesn't work, you can use `gclient setdep -r
Josip Sokcevic00eefc52023-08-27 22:11:27127<path>@<old hash>`, run `gclient gitmodules` to sync all submodules commits back
Josip Sokcevic79a4a542023-08-15 00:35:08128to what is in DEPS, or check detailed instructions in [Managing
129dependencies](dependencies.md).
130
Josip Sokcevic00eefc52023-08-27 22:11:27131NOTE: setdep for chromium/src is always prefixed with src/. For example, if you
132are updating v8, the command would be `gclient setdep -r src/v8@<hash>.
133
Joanna Wang394548e782023-09-25 19:11:46134## Workflows with submodules
135
Joanna Wange26842a2024-01-19 04:42:57136### Submodules during 'git status', 'git commit', and 'git add'
Joanna Wang394548e782023-09-25 19:11:46137
Joanna Wange26842a2024-01-19 04:42:57138For `git status`, submodules that show up under `Changes not staged for commit`
139can be hidden with `git -c diff.ignoreSubmodules=all status`
140
141For `git commit -a` you can exclude all submodules with
Joanna Wang394548e782023-09-25 19:11:46142`git -c diff.ignoreSubmodules=all commit -a`.
143
Joanna Wange26842a2024-01-19 04:42:57144`git add` does NOT support `diff.ignoreSubmodules`. Submodules that were
145hidden from you with `git -c diff.ignoreSubmodules=all status` would still
146be staged with `git add .|--all|-A` and therefore committed with
147`git -c diff.ignoreSubmodules=all commit`.
148
149Instead you can run `git add ':(exclude,attr:builtin_objectmode=160000)'` which
150will stage all changes except for submodules.
151
152(git assigns `160000` as the objectmode submodules. You can read more about
153[`builtin_objectmode`](https://kernel.googlesource.com/pub/scm/git/git/+/refs/heads/next/Documentation/gitattributes.txt#110)
154and magic [pathspecs](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec))
155
Joanna Wang394548e782023-09-25 19:11:46156To make these commands shorter, you can create git aliases for them by adding
Josip Sokcevic1fc80672024-01-24 00:19:38157the following to your $HOME/.gitconfig (globally) or src/.git/config file (just
158chromium/src):
Joanna Wang394548e782023-09-25 19:11:46159```
160[alias]
161 # 's', 'c', or whatever alias you want for each command
162 s = -c diff.ignoreSubmodules=all status
163 c = -c diff.ignoreSubmodules=all commit -a
164 d = -c diff.ignoreSubmodules=all difftool --dir-diff
Joanna Wange26842a2024-01-19 04:42:57165 a = add ':(exclude,attr:builtin_objectmode=160000)'
Joanna Wang394548e782023-09-25 19:11:46166```
Joanna Wange26842a2024-01-19 04:42:57167With the above, you can execute these commands by running `git s`, `git c`, etc.
168Or you may also use the pre-commit git hook detailed below.
Joanna Wang394548e782023-09-25 19:11:46169
Helmut Januschka5f8cfb72024-09-09 16:39:26170### Understanding diff.ignoreSubmodules
171
172`git config diff.ignoreSubmodules` sets a default behavior for `diff`, `status`,
173and several other git subcommands, using one of the [supported values of
174`--ignore-submodules`](https://www.git-scm.com/docs/git-diff/#Documentation/git-diff.txt---ignore-submodulesltwhengt).
175
176By default, `gclient sync` sets this to `dirty` as a local config in the
177chromium checkout. This elides submodule output for `git status` in a clean
178checkout, but will show submodules as modified when developers locally touch
179them.
180
181Manually setting this to `all` elides such output in all cases. This also omits
182submodule changes from `git commit -a`, which can decrease the likelihood of
183accidental submodule commits. However, it does not omit such changes from
184`git add -A`, meaning developers who use this flow are actually _more_ likely to
185commit accidental changes, since they'll be invisible beforehand unless
186developers manually set `--ignore-submodules=dirty` or use a lower-level command
187such as `git diff-tree`.
188
189Because `all` can result in misleading output and doesn't fully prevent
190accidental submodule commits, typical developers are likely better-served by
191leaving this configured to `dirty` and installing the
192[commit hook described below](#install-hook) to prevent such commits.
193Accordingly, `gclient sync` will warn if it detects a different setting locally;
194developers who understand the consequences can silence the warning via the
195`GCLIENT_SUPPRESS_SUBMODULE_WARNING` environment variable.
196
Joanna Wange0c72ee9d2023-09-25 20:57:40197### Submodules during a 'git rebase-update'
Joanna Wang394548e782023-09-25 19:11:46198While resolving merge conflicts during a `git rebase-update` you may see
199submodules show up in unexpected places.
200
201#### Submodules under "Changes not staged for commit"
202Submodules under this section can be safely ignored. This simply shows that the
203local commits of these submodules do not match the latest pinned commits fetched
204from remote. In other words, these submodules have been rolled since your last
205`git rebase-update`.
206
207If you use a diff tool like meld you can run:
208`git -c diff.ignoreSubmodules=all difftool --dir-diff`
209to prevent these submodules from showing up in your diff tool.
210
211#### Submodules under "Unmerged paths"
212If Submodules show up under this section it means that new revisions were
213committed for those submodules (either intentional or unintentionally) and these
214submodules were also rolled at remote. So now there is a conflict.
215
216If you DID NOT intentionally make any submdoules changes, you should run:
217`gclient gitmodules`. This will update the submdoules for you, to match whatever
218commits are listed in DEPS (which you have just pulled from remote).
219
220If you DID intentionally roll submodules, you can resolve this conflict just by
221resetting it:
222`gclient setdep -r {path}@{hash}`
223
Helmut Januschka5f8cfb72024-09-09 16:39:26224## Install a hook to help detect unintentional submodule commits {#install-hook}
Joanna Wangeda00e42023-09-20 18:51:47225
226depot_tools provides an opt-in pre-commit hook to detect unintentional submodule
227 changes during `git commit` and remove them from the commit.
228
229To install the hook: `gclient installhooks`
230
231If there is an existing pre-commit hook, gclient will instruct you how to update
232it. If you have already installed this hook, gclient will do nothing.
233
234To uninstall the hook, in `chromium/src` `rm .git/hooks/pre-commit` if you have
235no other hooks. Otherwise update `.git/hooks/pre-commit` to remove the gclient
236provided hook.
237
238To bypass this hook run `git commit --no-verify` (which bypasses all hooks you
239 may have) OR set the following environment variable: `SKIP_GITLINK_PRECOMMIT=1`
240(which bypasses this specific hook).
241
242Note that this is currently and best effort solution and does not guarantee
243that unintentional commits will always be detected. The team will iterate
244quickly on this hook to fill in other gaps and behavior is subject to change.
245Please file an [issue](https://bugs.chromium.org/p/chromium/issues/entry?components=Infra%3ESDK&labels=submodules-feedback&[email protected],[email protected]&description=Please%20steps%20to%20reproduce%20the%20problem:%0A%0ADo%20you%20have%20any%20custom%20environment%20setups%20like%20git%20hooks%20or%20git%20configs%20that%20you%20have%20set%20yourself%0A%0APlease%20attach%20output%20of:%0Agit%20config%20-l%0Agit%20map-branches%20-vv%0A%0AIf%20this%20is%20an%20issue%20with%20git%20cl%20upload%20please%20include%20the%20git%20trace%20file%20for%20the%20problematic%20run%20found%20in:%0A%3Cdepot_tools_path%3E/traces/%3Clatest%20trace%3E) for any feedback.
246
Josip Sokcevic79a4a542023-08-15 00:35:08247## FAQ
248
249### Why do we have Git dependencies in both DEPS and Git submodules?
250
251Lots of Chromium infrastructure already parse DEPS file directly. Instead of a
252massive switch, it's easier to transition to Git submodules this way. Moreover,
253unwanted Git submodule updates can be detected and developers can be warned.
254
255### How do I manually roll Git submodule?
Josip Sokcevic00eefc52023-08-27 22:11:27256
Josip Sokcevic79a4a542023-08-15 00:35:08257See the [dependencies](dependencies.md) page.
258
Josip Sokcevic00eefc52023-08-27 22:11:27259### I got a conflict on a submodule, how do I resolve it?
260
261First, you will need to determine what is the right commit hash. If you
262accidentally committed a gitlink, which got in the meantime updated, you most
263likely want to restore the original updated gitlink. You can run `gclient
264gitmodules`, which will take care of all unmerged submodule paths, and set it to
265match DEPS file.
266
267If you prefer to manually resolve it, under git status, you will see "Unmerged
268paths". If those are submodules, you want to restore them by running the
269following command:
270
271```
272git restore --staging <affected path>
273```
274
Joanna Wangb812e222023-08-31 17:43:53275### How do I see what revision is pinned?
276
277`gclient getdep` will return whatever commit is pinned for the deps in `DEPS`
278(unstaged, staged, or committed). If the repo is using git submodules only
279(and has no git deps in `DEPS`) it will return the whatever pinned commit is
280staged or committed.
281
282```
283gclient getdep -r <path>
284```
285
286
Josip Sokcevic00eefc52023-08-27 22:11:27287If you want to keep your gitlink, then run `git add <affected path>`.
288
Josip Sokcevic79a4a542023-08-15 00:35:08289### How can I provide feedback?
290
291Please file [a bug under Infra>SDK
292component](https://bugs.chromium.org/p/chromium/issues/entry?components=Infra%3ESDK).