android_webview
apps
ash
base
build
build_overrides
buildtools
cc
chrome
chromecast
chromeos
clank
codelabs
components
content
courgette
crypto
dbus
device
docs
accessibility
autofill
chromeos
design
enterprise
experiments
fuchsia
gpu
images
infra
intl
ios
lacros
linux
login
mac
media
memory
memory-infra
patterns
privacy
privacy_budget
process
security
speed
speed_metrics
standards
telemetry_extension
testing
transcripts
ui
updater
webapps
website
workflow
DIR_METADATA
OWNERS
README.md
accessibility.md
ad_tagging.md
adding_to_third_party.md
android_accessing_cpp_enums_in_java.md
android_accessing_cpp_features_in_java.md
android_accessing_cpp_switches_in_java.md
android_build_instructions.md
android_cast_build_instructions.md
android_debugging_instructions.md
android_dynamic_feature_modules.md
android_emulator.md
android_isolated_splits.md
android_jni_ownership_best_practices.md
android_logging.md
android_native_libraries.md
android_studio.md
angle_in_chromium.md
api_keys.md
asan.md
atom.md
benchmark_performance_regressions.md
bitmap_pipeline.md
branch_gardener.md
building_old_revisions.md
callback.md
ccache_mac.md
chrome_os_logging.md
chrome_settings.md
chrome_untrusted.md
chromedriver_status.md
chromeos_build_instructions.md
chromeos_glossary.md
chromium_browser_vs_google_chrome.md
cipd_and_3pp.md
cl_respect.md
cl_tips.md
clang.md
clang_code_coverage_wrapper.md
clang_format.md
clang_gardening.md
clang_sheriffing.md
clang_static_analyzer.md
clang_tidy.md
clang_tool_refactoring.md
clangd.md
clion.md
closure_compilation.md
cocoa_tips_and_tricks.md
code_review_owners.md
code_reviews.md
commit_checklist.md
component_build.md
configuration.md
contributing.md
cq_fault_attribution.md
cr_respect.md
cr_user_manual.md
cross_platform_ui.md
cygwin_dll_remapping_failure.md
dangling_ptr.md
dangling_ptr_guide.md
dbus_mojo_connection_service.md
debugging_with_crash_keys.md
dependencies.md
deterministic_builds.md
disassemble_code.md
documentation_best_practices.md
documentation_guidelines.md
early-hints.md
eclipse.md
emacs.md
erc_irc.md
flag_expiry.md
flag_guarding_guidelines.md
flag_ownership.md
frame_trees.md
gardener.md
gdbinit.md
get_the_code.md
git_cookbook.md
git_submodules.md
git_tips.md
google_chrome_branded_builds.md
google_play_services.md
graphical_debugging_aid_chromium_views.md
gwp_asan.md
history_manipulation_intervention.md
how_cc_works.md
how_to_add_your_feature_flag.md
how_to_extend_web_test_framework.md
idn.md
initialize_blink_features.md
inlined_stack_traces.md
installation_at_vmware.md
ios_build_instructions.md
ios_infra.md
ios_voiceover.md
kiosk_mode.md
lacros.md
life_of_a_frame.md
lldbinit.md
mac_arm64.md
mac_build_instructions.md
mac_lld.md
modifying_session_history_serialization.md
mojo_and_services.md
mojo_ipc_conversion.md
mojo_testing.md
native_relocations.md
navbar.md
navigation-request-navigation-state.gv
navigation-request-navigation-state.png
navigation.md
navigation_concepts.md
network_traffic_annotations.md
no_sources_assignment_filter.md
optimizing_web_uis.md
origin_trials_integration.md
ozone_overview.md
parsing_test_results.md
pgo.md
piranha_plant.md
process_model_and_site_isolation.md
profiling.md
profiling_content_shell_on_android.md
proxy_auto_config.md
qtcreator.md
release_branch_guidance.md
render-frame-host-lifecycle-state.gv
render-frame-host-lifecycle-state.png
render_document.md
rust.md
seccomp_sandbox_crash_dumping.md
servicification.md
session_history.md
sheriff.md
shutdown.md
special_case_urls.md
static_initializers.md
sublime_ide.md
system_hardening_features.md
tab_helpers.md
testing_webui.md
threading_and_tasks.md
threading_and_tasks_faq.md
threading_and_tasks_testing.md
toolchain_support.md
tour_of_luci_ui.md
tpm_quick_ref.md
translation_screenshots.md
trusted_types_on_webui.md
updating_clang.md
updating_clang_format_binaries.md
use_counter_wiki.md
useful_urls.md
user_data_dir.md
user_data_storage.md
user_handle_mapping.md
vanilla_msysgit_workflow.md
vscode.md
vscode_python.md
webui_build_configuration.md
webui_explainer.md
webui_in_chrome.md
webui_in_components.md
webview_policies.md
win_cross.md
win_order_files.md
windows_build_instructions.md
windows_native_window_occlusion_tracking.md
windows_pwa_integration.md
windows_shortcut_and_taskbar_handling.md
windows_split_dll.md
windows_virtual_desktop_handling.md
wmax_tokens.md
working_remotely_with_android.md
writing_clang_plugins.md
extensions
fuchsia_web
gin
google_apis
google_update
gpu
headless
infra
internal
ios
ios_internal
ipc
media
mojo
native_client
native_client_sdk
net
pdf
ppapi
printing
remoting
rlz
sandbox
services
signing_keys
skia
sql
storage
styleguide
testing
third_party
tools
ui
url
v8
webkit
.clang-format
.clang-tidy
.clangd
.eslintrc.js
.git-blame-ignore-revs
.gitallowed
.gitattributes
.gitignore
.gitmodules
.gn
.mailmap
.rustfmt.toml
.vpython3
.yapfignore
ATL_OWNERS
AUTHORS
BUILD.gn
CODE_OF_CONDUCT.md
DEPS
DIR_METADATA
LICENSE
LICENSE.chromium_os
OWNERS
PRESUBMIT.py
PRESUBMIT_test.py
PRESUBMIT_test_mocks.py
README.md
WATCHLISTS
codereview.settings

Change-Id: I582cf06dcac91e16db641147a0f5a9e7481b53ee Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5232037 Auto-Submit: Josip Sokcevic <sokcevic@chromium.org> Reviewed-by: Joanna Wang <jojwang@chromium.org> Commit-Queue: Joanna Wang <jojwang@chromium.org> Cr-Commit-Position: refs/heads/main@{#1251144}
282 lines
11 KiB
Markdown
282 lines
11 KiB
Markdown
# Git submodules
|
|
|
|
A Git submodule is a Git repository inside another Git repository. Chromium
|
|
project doesn't rely on Git submodules directly. Instead, gclient sync is used
|
|
to manage Git dependencies.
|
|
|
|
In 2023Q3, we started to move source of Git dependencies from DEPS files to Git
|
|
submodules. While we do our best to hide complexities of submodules, some will
|
|
be exposed.
|
|
|
|
[TOC]
|
|
|
|
## A quick introduction to Git submoduldes
|
|
|
|
[Git submodules](https://git-scm.com/docs/gitsubmodules) are managed via the
|
|
combination of `.gitmodules` files and gitlinks. `.gitmodules` is a text file
|
|
that configures submodules, and each submodule entry contains the path to the
|
|
submodule's worktree and the URL of the submodule. Gitlink is a special type of
|
|
file in the Git database that tracks a submodule commit.
|
|
|
|
You can find an example of Git dependency below. Note that gclient-condition is
|
|
a custom property used by gclient and not git. It's identical to `condition` in
|
|
`DEPS` and the allowed variables are defined in `vars = {` section of `DEPS`.
|
|
|
|
`.gitmodules`:
|
|
|
|
```
|
|
[submodule "third_party/catapult"]
|
|
path = third_party/catapult
|
|
url = https://chromium.googlesource.com/catapult.git
|
|
gclient-condition = checkout_linux
|
|
```
|
|
|
|
gitlink entry, retrieved using `git ls-files -s -- third_party/catapult`:
|
|
|
|
```
|
|
160000 0b39a694c0b61392d1180520ed1c13e390029c41 0 third_party/catapult
|
|
```
|
|
|
|
Corresponding DEPS entry would look like:
|
|
|
|
```
|
|
'third_party/catapult': {
|
|
'url': 'https://chromium.googlesource.com/catapult.git@0b39a694c0b61392d1180520ed1c13e390029c41',
|
|
'condition': 'checkout_linux',
|
|
}
|
|
```
|
|
|
|
## How to avoid accidental Git submodule updates?
|
|
|
|
The simplest approach is to always run gclient sync after updated chromium
|
|
checkout (e.g. after `git pull`, or `git checkout`). You can automate that by
|
|
adding post-checkout hook (example below). To confirm there are no changes, run
|
|
`git status`. If you use `git commit -a`, check the "Changes to be committed"
|
|
section that shows up in the edit commit message.
|
|
|
|
### Automatically run gclient sync after git pull / git checkout
|
|
|
|
We need to have Git two hooks: post-checkout and post-merge. In chromium/src
|
|
directory, edit `.git/hooks/post-checkout`:
|
|
|
|
```
|
|
#!/bin/sh
|
|
|
|
set -u
|
|
gclient sync
|
|
```
|
|
|
|
and set it to be executable: `chmod +x .git/hooks/post-checkout`. Repeat the
|
|
same for `.git/hooks/post-merge`.
|
|
|
|
More information about githooks can be found
|
|
[here](https://git-scm.com/docs/githooks).
|
|
|
|
### Git status shows modified dependencies. What does that mean?
|
|
|
|
If a submodule is checked out at a different commit than one tracked by its
|
|
parent, `git status` in the parent repo will show unstaged changes with "new
|
|
commits" in parenthesis, such as:
|
|
|
|
```
|
|
modified: <git deps name> (new commits)
|
|
```
|
|
|
|
Commands like `git commit -a` or `git add *|.|-A|u` WILL include this in your
|
|
commit and your CL (which is likely NOT what you want).
|
|
|
|
Instead you can:
|
|
|
|
```
|
|
# Run gclient sync to sync dependencies
|
|
gclient sync
|
|
# check git status again
|
|
|
|
# OR
|
|
git add <file> # for each file you want to stage
|
|
# Then commit your staged files
|
|
git commit -v -m "Fix foo/bar"
|
|
```
|
|
|
|
NOTE: due to a bug in gclient (crbug.com/1475448), it's possible that gclient
|
|
left unmanaged git repository. You may need to manually remove those unmanaged
|
|
repositories.
|
|
|
|
```
|
|
# Inside chromium/src checkout:
|
|
# This ensures that all managed dependencies are in sync:
|
|
gclient sync -D
|
|
# This moves all unused dependencies to ../unused directory in gclient root
|
|
# (just outside of src directory). It then tells git to restore gitlink.
|
|
for f in $( git status | grep '(new commits)' | awk '{print $2}' ); do mkdir -p "../unused/`dirname $f`" && mv $f "../unused/$f" && git checkout -- $f; done
|
|
# inspect ../unused/ if you'd like, and remove it there's nothing useful there,
|
|
# e.g. no non-uploaded commits.
|
|
```
|
|
|
|
If a submodule has uncommitted changes (i.e. you made some manual changes to the
|
|
affected submodule), running `git status` in its parent repo will show them as
|
|
unstaged changes:
|
|
|
|
```
|
|
modified: <git deps name> (modified content)
|
|
|
|
# or
|
|
|
|
modified: <git deps name> (untracked content)
|
|
```
|
|
|
|
It's not possible to add those changes to the parent repository. You can ignore
|
|
such status, or you can cd into submodule and address it. E.g. you may delete
|
|
untracked files (content) or reset modified content to match HEAD.
|
|
|
|
## I accidentally staged Git submodule (not yet committed)
|
|
|
|
If you accidentally stage a Git submodule, you can unstage it by running `git
|
|
restore --staged <path to submodule>`.
|
|
|
|
## I accidentally committed Git submodule
|
|
|
|
We will need to create either a commit that sets it back to old value, or amend
|
|
the commit that added it. You can try to run `gclient sync` to bring the commit
|
|
back to what is expected. If that doesn't work, you can use `gclient setdep -r
|
|
<path>@<old hash>`, run `gclient gitmodules` to sync all submodules commits back
|
|
to what is in DEPS, or check detailed instructions in [Managing
|
|
dependencies](dependencies.md).
|
|
|
|
NOTE: setdep for chromium/src is always prefixed with src/. For example, if you
|
|
are updating v8, the command would be `gclient setdep -r src/v8@<hash>.
|
|
|
|
## Workflows with submodules
|
|
|
|
### Submodules during 'git status', 'git commit', and 'git add'
|
|
|
|
For `git status`, submodules that show up under `Changes not staged for commit`
|
|
can be hidden with `git -c diff.ignoreSubmodules=all status`
|
|
|
|
For `git commit -a` you can exclude all submodules with
|
|
`git -c diff.ignoreSubmodules=all commit -a`.
|
|
|
|
`git add` does NOT support `diff.ignoreSubmodules`. Submodules that were
|
|
hidden from you with `git -c diff.ignoreSubmodules=all status` would still
|
|
be staged with `git add .|--all|-A` and therefore committed with
|
|
`git -c diff.ignoreSubmodules=all commit`.
|
|
|
|
Instead you can run `git add ':(exclude,attr:builtin_objectmode=160000)'` which
|
|
will stage all changes except for submodules.
|
|
|
|
(git assigns `160000` as the objectmode submodules. You can read more about
|
|
[`builtin_objectmode`](https://kernel.googlesource.com/pub/scm/git/git/+/refs/heads/next/Documentation/gitattributes.txt#110)
|
|
and magic [pathspecs](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec))
|
|
|
|
To make these commands shorter, you can create git aliases for them by adding
|
|
the following to your $HOME/.gitconfig (globally) or src/.git/config file (just
|
|
chromium/src):
|
|
```
|
|
[alias]
|
|
# 's', 'c', or whatever alias you want for each command
|
|
s = -c diff.ignoreSubmodules=all status
|
|
c = -c diff.ignoreSubmodules=all commit -a
|
|
d = -c diff.ignoreSubmodules=all difftool --dir-diff
|
|
a = add ':(exclude,attr:builtin_objectmode=160000)'
|
|
```
|
|
With the above, you can execute these commands by running `git s`, `git c`, etc.
|
|
Or you may also use the pre-commit git hook detailed below.
|
|
|
|
### Submodules during a 'git rebase-update'
|
|
While resolving merge conflicts during a `git rebase-update` you may see
|
|
submodules show up in unexpected places.
|
|
|
|
#### Submodules under "Changes not staged for commit"
|
|
Submodules under this section can be safely ignored. This simply shows that the
|
|
local commits of these submodules do not match the latest pinned commits fetched
|
|
from remote. In other words, these submodules have been rolled since your last
|
|
`git rebase-update`.
|
|
|
|
If you use a diff tool like meld you can run:
|
|
`git -c diff.ignoreSubmodules=all difftool --dir-diff`
|
|
to prevent these submodules from showing up in your diff tool.
|
|
|
|
#### Submodules under "Unmerged paths"
|
|
If Submodules show up under this section it means that new revisions were
|
|
committed for those submodules (either intentional or unintentionally) and these
|
|
submodules were also rolled at remote. So now there is a conflict.
|
|
|
|
If you DID NOT intentionally make any submdoules changes, you should run:
|
|
`gclient gitmodules`. This will update the submdoules for you, to match whatever
|
|
commits are listed in DEPS (which you have just pulled from remote).
|
|
|
|
If you DID intentionally roll submodules, you can resolve this conflict just by
|
|
resetting it:
|
|
`gclient setdep -r {path}@{hash}`
|
|
|
|
## BETA: Install a hook to help detect unintentional submodule commits
|
|
|
|
depot_tools provides an opt-in pre-commit hook to detect unintentional submodule
|
|
changes during `git commit` and remove them from the commit.
|
|
|
|
To install the hook: `gclient installhooks`
|
|
|
|
If there is an existing pre-commit hook, gclient will instruct you how to update
|
|
it. If you have already installed this hook, gclient will do nothing.
|
|
|
|
To uninstall the hook, in `chromium/src` `rm .git/hooks/pre-commit` if you have
|
|
no other hooks. Otherwise update `.git/hooks/pre-commit` to remove the gclient
|
|
provided hook.
|
|
|
|
To bypass this hook run `git commit --no-verify` (which bypasses all hooks you
|
|
may have) OR set the following environment variable: `SKIP_GITLINK_PRECOMMIT=1`
|
|
(which bypasses this specific hook).
|
|
|
|
Note that this is currently and best effort solution and does not guarantee
|
|
that unintentional commits will always be detected. The team will iterate
|
|
quickly on this hook to fill in other gaps and behavior is subject to change.
|
|
Please file an [issue](https://bugs.chromium.org/p/chromium/issues/entry?components=Infra%3ESDK&labels=submodules-feedback&cc=sokcevic@chromium.org,jojwang@chromium.org&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.
|
|
|
|
## FAQ
|
|
|
|
### Why do we have Git dependencies in both DEPS and Git submodules?
|
|
|
|
Lots of Chromium infrastructure already parse DEPS file directly. Instead of a
|
|
massive switch, it's easier to transition to Git submodules this way. Moreover,
|
|
unwanted Git submodule updates can be detected and developers can be warned.
|
|
|
|
### How do I manually roll Git submodule?
|
|
|
|
See the [dependencies](dependencies.md) page.
|
|
|
|
### I got a conflict on a submodule, how do I resolve it?
|
|
|
|
First, you will need to determine what is the right commit hash. If you
|
|
accidentally committed a gitlink, which got in the meantime updated, you most
|
|
likely want to restore the original updated gitlink. You can run `gclient
|
|
gitmodules`, which will take care of all unmerged submodule paths, and set it to
|
|
match DEPS file.
|
|
|
|
If you prefer to manually resolve it, under git status, you will see "Unmerged
|
|
paths". If those are submodules, you want to restore them by running the
|
|
following command:
|
|
|
|
```
|
|
git restore --staging <affected path>
|
|
```
|
|
|
|
### How do I see what revision is pinned?
|
|
|
|
`gclient getdep` will return whatever commit is pinned for the deps in `DEPS`
|
|
(unstaged, staged, or committed). If the repo is using git submodules only
|
|
(and has no git deps in `DEPS`) it will return the whatever pinned commit is
|
|
staged or committed.
|
|
|
|
```
|
|
gclient getdep -r <path>
|
|
```
|
|
|
|
|
|
If you want to keep your gitlink, then run `git add <affected path>`.
|
|
|
|
### How can I provide feedback?
|
|
|
|
Please file [a bug under Infra>SDK
|
|
component](https://bugs.chromium.org/p/chromium/issues/entry?components=Infra%3ESDK).
|
|
|