build: derive patches upstream-head ref from script path (#50727)

* build: derive patches upstream-head ref from script path

gclient-new-workdir.py symlinks each repo's .git/refs back to the source
checkout, so the fixed refs/patches/upstream-head was shared across all
worktrees. Parallel `e sync` runs in different worktrees clobbered each
other's upstream-head, breaking `e patches` and check-patch-diff.

Suffix the ref with an md5 of the script directory so each worktree writes
a distinct ref into the shared refs dir. Fall back to the legacy ref name
in guess_base_commit so existing checkouts keep working until next sync.

* fixup: also write legacy upstream-head ref and note it in docs
This commit is contained in:
Samuel Attard
2026-04-06 12:42:08 -04:00
committed by GitHub
parent e66e4ca02c
commit 9f3cc9122c
2 changed files with 27 additions and 15 deletions

View File

@@ -79,7 +79,7 @@ $ ../../electron/script/git-import-patches ../../electron/patches/node
$ ../../electron/script/git-export-patches -o ../../electron/patches/node
```
Note that `git-import-patches` will mark the commit that was `HEAD` when it was run as `refs/patches/upstream-head`. This lets you keep track of which commits are from Electron patches (those that come after `refs/patches/upstream-head`) and which commits are in upstream (those before `refs/patches/upstream-head`).
Note that `git-import-patches` will mark the commit that was `HEAD` when it was run as `refs/patches/upstream-head` (and a checkout-specific `refs/patches/upstream-head-<hash>` so that gclient worktrees sharing a `.git/refs` directory don't clobber each other). This lets you keep track of which commits are from Electron patches (those that come after `refs/patches/upstream-head`) and which commits are in upstream (those before `refs/patches/upstream-head`).
#### Resolving conflicts

View File

@@ -6,6 +6,7 @@ Everything here should be project agnostic: it shouldn't rely on project's
structure, or make assumptions about the passed arguments or calls' outcomes.
"""
import hashlib
import io
import os
import posixpath
@@ -19,7 +20,14 @@ sys.path.append(SCRIPT_DIR)
from patches import PATCH_FILENAME_PREFIX, is_patch_location_line
UPSTREAM_HEAD='refs/patches/upstream-head'
# In gclient-new-workdir worktrees, .git/refs is symlinked back to the source
# checkout, so a single fixed ref name would be shared (and clobbered) across
# worktrees. Derive a per-checkout suffix from this script's absolute path so
# each worktree records its own upstream head in the shared refs directory.
_LEGACY_UPSTREAM_HEAD = 'refs/patches/upstream-head'
UPSTREAM_HEAD = (
_LEGACY_UPSTREAM_HEAD + '-' + hashlib.md5(SCRIPT_DIR.encode()).hexdigest()[:8]
)
def is_repo_root(path):
path_exists = os.path.exists(path)
@@ -118,6 +126,8 @@ def import_patches(repo, ref=UPSTREAM_HEAD, **kwargs):
"""same as am(), but we save the upstream HEAD so we can refer to it when we
later export patches"""
update_ref(repo=repo, ref=ref, newvalue='HEAD')
if ref != _LEGACY_UPSTREAM_HEAD:
update_ref(repo=repo, ref=_LEGACY_UPSTREAM_HEAD, newvalue='HEAD')
# Upgrade to index v4 before applying so every intermediate index write
# during am benefits from path-prefix compression (roughly halves index
# size in large repos).
@@ -143,19 +153,21 @@ def get_commit_count(repo, commit_range):
def guess_base_commit(repo, ref):
"""Guess which commit the patches might be based on"""
try:
upstream_head = get_commit_for_ref(repo, ref)
num_commits = get_commit_count(repo, upstream_head + '..')
return [upstream_head, num_commits]
except subprocess.CalledProcessError:
args = [
'git',
'-C',
repo,
'describe',
'--tags',
]
return subprocess.check_output(args).decode('utf-8').rsplit('-', 2)[0:2]
for candidate in (ref, _LEGACY_UPSTREAM_HEAD):
try:
upstream_head = get_commit_for_ref(repo, candidate)
num_commits = get_commit_count(repo, upstream_head + '..')
return [upstream_head, num_commits]
except subprocess.CalledProcessError:
continue
args = [
'git',
'-C',
repo,
'describe',
'--tags',
]
return subprocess.check_output(args).decode('utf-8').rsplit('-', 2)[0:2]
def format_patch(repo, since):