blob: d5d976f1554aa067a65f630cacba4fd8478b51e2 [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
Josip Sokcevic00eefc52023-08-27 22:11:2711IMPORTANT NOTE: Due to a bug in fsmonitor, we encourage you to disable it until
12the underlying bug is fixed. More details in https://crbug.com/1475405.
13
Josip Sokcevic79a4a542023-08-15 00:35:0814[TOC]
15
16## A quick introduction to Git submoduldes
17
18[Git submodules](https://git-scm.com/docs/gitsubmodules) are managed via the
19combination of `.gitmodules` files and gitlinks. `.gitmodules` is a text file
20that configures submodules, and each submodule entry contains the path to the
21submodule's worktree and the URL of the submodule. Gitlink is a special type of
22file in the Git database that tracks a submodule commit.
23
Josip Sokcevic703849e2023-08-16 00:13:3424You can find an example of Git dependency below. Note that gclient-condition is
25a custom property used by gclient and not git. It's identical to `condition` in
26`DEPS` and the allowed variables are defined in `vars = {` section of `DEPS`.
Josip Sokcevic79a4a542023-08-15 00:35:0827
28`.gitmodules`:
29
30```
31[submodule "third_party/catapult"]
32 path = third_party/catapult
33 url = https://chromium.googlesource.com/catapult.git
Josip Sokcevic703849e2023-08-16 00:13:3434 gclient-condition = checkout_linux
Josip Sokcevic79a4a542023-08-15 00:35:0835```
36
37gitlink entry, retrieved using `git ls-files -s -- third_party/catapult`:
38
39```
40160000 0b39a694c0b61392d1180520ed1c13e390029c41 0 third_party/catapult
41```
42
43Corresponding DEPS entry would look like:
44
45```
46 'third_party/catapult': {
Josip Sokcevic703849e2023-08-16 00:13:3447 'url': 'https://chromium.googlesource.com/catapult.git@0b39a694c0b61392d1180520ed1c13e390029c41',
48 'condition': 'checkout_linux',
Josip Sokcevic79a4a542023-08-15 00:35:0849}
50```
51
52## How to avoid accidental Git submodule updates?
53
54The simplest approach is to always run gclient sync after updated chromium
55checkout (e.g. after `git pull`, or `git checkout`). You can automate that by
56adding post-checkout hook (example below). To confirm there are no changes, run
57`git status`. If you use `git commit -a`, check the "Changes to be committed"
58section that shows up in the edit commit message.
59
60### Automatically run gclient sync after git pull / git checkout
61
62We need to have Git two hooks: post-checkout and post-merge. In chromium/src
63directory, edit `.git/hooks/post-checkout`:
64
65```
66#!/bin/sh
67
68set -u
69gclient sync
70```
71
72and set it to be executable: `chmod +x .git/hooks/post-checkout`. Repeat the
73same for `.git/hooks/post-merge`.
74
75More information about githooks can be found
76[here](https://git-scm.com/docs/githooks).
77
78### Git status shows modified dependencies. What does that mean?
79
80If a submodule is checked out at a different commit than one tracked by its
81parent, `git status` in the parent repo will show unstaged changes with "new
82commits" in parenthesis, such as:
83
84```
85modified: <git deps name> (new commits)
86```
87
88Commands like `git commit -a` or `git add *|.|-A|u` WILL include this in your
89commit and your CL (which is likely NOT what you want).
90
91Instead you can:
92
93```
94# Run gclient sync to sync dependencies
95gclient sync
96# check git status again
97
98# OR
99git add <file> # for each file you want to stage
100# Then commit your staged files
101git commit -v -m "Fix foo/bar"
102```
103
Josip Sokcevic15a05752023-08-24 17:02:20104NOTE: due to a bug in gclient (crbug.com/1475448), it's possible that gclient
105left unmanaged git repository. You may need to manually remove those unmanaged
106repositories.
107
108```
109# Inside chromium/src checkout:
110# This ensures that all managed dependencies are in sync:
111gclient sync -D
112# This moves all unused dependencies to ../unused directory in gclient root
113# (just outside of src directory). It then tells git to restore gitlink.
114for f in $( git status | grep '(new commits)' | awk '{print $2}' ); do mkdir -p "../unused/`dirname $f`" && mv $f "../unused/$f" && git checkout -- $f; done
115# inspect ../unused/ if you'd like, and remove it there's nothing useful there,
116# e.g. no non-uploaded commits.
117```
118
Josip Sokcevic79a4a542023-08-15 00:35:08119If a submodule has uncommitted changes (i.e. you made some manual changes to the
120affected submodule), running `git status` in its parent repo will show them as
121unstaged changes:
122
123```
124 modified: <git deps name> (modified content)
125
126# or
127
128 modified: <git deps name> (untracked content)
129```
130
131It's not possible to add those changes to the parent repository. You can ignore
132such status, or you can cd into submodule and address it. E.g. you may delete
133untracked files (content) or reset modified content to match HEAD.
134
135## I accidentally staged Git submodule (not yet committed)
136
137If you accidentally stage a Git submodule, you can unstage it by running `git
138restore --staged <path to submodule>`.
139
140## I accidentally committed Git submodule
141
142We will need to create either a commit that sets it back to old value, or amend
143the commit that added it. You can try to run `gclient sync` to bring the commit
144back to what is expected. If that doesn't work, you can use `gclient setdep -r
Josip Sokcevic00eefc52023-08-27 22:11:27145<path>@<old hash>`, run `gclient gitmodules` to sync all submodules commits back
Josip Sokcevic79a4a542023-08-15 00:35:08146to what is in DEPS, or check detailed instructions in [Managing
147dependencies](dependencies.md).
148
Josip Sokcevic00eefc52023-08-27 22:11:27149NOTE: setdep for chromium/src is always prefixed with src/. For example, if you
150are updating v8, the command would be `gclient setdep -r src/v8@<hash>.
151
Joanna Wang394548e782023-09-25 19:11:46152## Workflows with submodules
153
154### Submodules during `git status` and `git commit`
155Submodules that show up under `Changes not staged for commit` when you run
156`git status` can be hidden with `git -c diff.ignoreSubmodules=all status`
157
158You can also `git commit -a` your changes while excluding all submodules with
159`git -c diff.ignoreSubmodules=all commit -a`.
160
161To make these commands shorter, you can create git aliases for them by adding
162the following to your src/.git/commit file:
163```
164[alias]
165 # 's', 'c', or whatever alias you want for each command
166 s = -c diff.ignoreSubmodules=all status
167 c = -c diff.ignoreSubmodules=all commit -a
168 d = -c diff.ignoreSubmodules=all difftool --dir-diff
169```
170With the above, you can execute these commands by running `git s` and `git c`
171
172NOTE: `diff.ignoreSubmodules` is not supported with `git add`. If you are hiding
173subodules from your view with something like `git s`, running
174`git add .|--all|-A` will still stage any submodules you do not see for commit.
175Then running `git c` will still include these submodules in your commit.
176
177We recommend you use the pre-commit git hook detailed below.
178
179### Submodules during a `git rebase-update`
180While resolving merge conflicts during a `git rebase-update` you may see
181submodules show up in unexpected places.
182
183#### Submodules under "Changes not staged for commit"
184Submodules under this section can be safely ignored. This simply shows that the
185local commits of these submodules do not match the latest pinned commits fetched
186from remote. In other words, these submodules have been rolled since your last
187`git rebase-update`.
188
189If you use a diff tool like meld you can run:
190`git -c diff.ignoreSubmodules=all difftool --dir-diff`
191to prevent these submodules from showing up in your diff tool.
192
193#### Submodules under "Unmerged paths"
194If Submodules show up under this section it means that new revisions were
195committed for those submodules (either intentional or unintentionally) and these
196submodules were also rolled at remote. So now there is a conflict.
197
198If you DID NOT intentionally make any submdoules changes, you should run:
199`gclient gitmodules`. This will update the submdoules for you, to match whatever
200commits are listed in DEPS (which you have just pulled from remote).
201
202If you DID intentionally roll submodules, you can resolve this conflict just by
203resetting it:
204`gclient setdep -r {path}@{hash}`
205
Joanna Wangeda00e42023-09-20 18:51:47206## BETA: Install a hook to help detect unintentional submodule commits
207
208depot_tools provides an opt-in pre-commit hook to detect unintentional submodule
209 changes during `git commit` and remove them from the commit.
210
211To install the hook: `gclient installhooks`
212
213If there is an existing pre-commit hook, gclient will instruct you how to update
214it. If you have already installed this hook, gclient will do nothing.
215
216To uninstall the hook, in `chromium/src` `rm .git/hooks/pre-commit` if you have
217no other hooks. Otherwise update `.git/hooks/pre-commit` to remove the gclient
218provided hook.
219
220To bypass this hook run `git commit --no-verify` (which bypasses all hooks you
221 may have) OR set the following environment variable: `SKIP_GITLINK_PRECOMMIT=1`
222(which bypasses this specific hook).
223
224Note that this is currently and best effort solution and does not guarantee
225that unintentional commits will always be detected. The team will iterate
226quickly on this hook to fill in other gaps and behavior is subject to change.
227Please 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.
228
Josip Sokcevic79a4a542023-08-15 00:35:08229## FAQ
230
231### Why do we have Git dependencies in both DEPS and Git submodules?
232
233Lots of Chromium infrastructure already parse DEPS file directly. Instead of a
234massive switch, it's easier to transition to Git submodules this way. Moreover,
235unwanted Git submodule updates can be detected and developers can be warned.
236
237### How do I manually roll Git submodule?
Josip Sokcevic00eefc52023-08-27 22:11:27238
Josip Sokcevic79a4a542023-08-15 00:35:08239See the [dependencies](dependencies.md) page.
240
Josip Sokcevic00eefc52023-08-27 22:11:27241### I got a conflict on a submodule, how do I resolve it?
242
243First, you will need to determine what is the right commit hash. If you
244accidentally committed a gitlink, which got in the meantime updated, you most
245likely want to restore the original updated gitlink. You can run `gclient
246gitmodules`, which will take care of all unmerged submodule paths, and set it to
247match DEPS file.
248
249If you prefer to manually resolve it, under git status, you will see "Unmerged
250paths". If those are submodules, you want to restore them by running the
251following command:
252
253```
254git restore --staging <affected path>
255```
256
Joanna Wangb812e222023-08-31 17:43:53257### How do I see what revision is pinned?
258
259`gclient getdep` will return whatever commit is pinned for the deps in `DEPS`
260(unstaged, staged, or committed). If the repo is using git submodules only
261(and has no git deps in `DEPS`) it will return the whatever pinned commit is
262staged or committed.
263
264```
265gclient getdep -r <path>
266```
267
268
Josip Sokcevic00eefc52023-08-27 22:11:27269If you want to keep your gitlink, then run `git add <affected path>`.
270
Josip Sokcevic79a4a542023-08-15 00:35:08271### How can I provide feedback?
272
273Please file [a bug under Infra>SDK
274component](https://bugs.chromium.org/p/chromium/issues/entry?components=Infra%3ESDK).
275