jmtd → log → git worktrees
I work on OpenJDK backports: taking a patch that was committed to a current version of JDK, and adapting it to an older one. There are four main OpenJDK versions that I am concerned with: the current version ("jdk"), 8, 11 and 17. These are all maintained in separate Git(Hub) repositories.
It's very useful to have access to the other JDKs when working on any
particular version. For example, to backport a patch from the latest version to
17, where the delta is not too big, a lot of the time you can cherry-pick the
patch unmodified. To do git cherry-pick <some-commit>
in a git repository
tracking JDK17, where <some-commit>
is in "jdk", I need the "jdk" repository
configured as a remote for my local jdk17 repository.
Maintaining completely separate local git repositories for all four JDK versions, with each of them having a subset of the others added as remotes, adds up to a lot of duplicated data on local storage.
For a little while I was exploring using shared clones: a local clone of another local git repository which share some local metadata. This saves on some disc space, but it does not share the configuration for remotes: so I still have to add any other JDK versions I want as remotes in each shared clone (even if the underlying objects already exist in the shared metadata)
Then I discovered git worktree. The git repositories that I've used up until now have had exactly zero (for a bare clone) or one worktree: in other words, the check-out, the actual source code files. Git does actually support having more than one worktree, which can be achieved like so:
git worktree add --checkout \
-b jdk8u-master \
../jdk.worktree.jdk8u \
jdk8u-dev/master
The result (in this example) is a new checkout, in this case of a new local
branch named jdk8u-master
at the sibling directory path jdk.worktree.jdk8u
,
tracking the remote branch jdk8u-dev/master
. Within that checkout, there is a
file .git
which contains a pointer to (indirectly) the main local repository
path:
gitdir: /home/jon/rh/git/jdk/.git/worktrees/jdk.worktree.jdk8u-dev
The directory itself behaves exactly like the real one, in that I can see all the configured remotes, and other checked out branches in other worktree paths:
$ git branch
JDK-8214520-11u + 8284977-jdk11u-dev
JDK-8268362-11u + master
8231111-jdk11u-merged * 8237479-jdk8u-dev
Above, you can see that the current worktree is the branch 8237479-jdk8u-dev
,
marked (as usual) by the prefix *
, and two other branches are checked out
in other worktrees, marked by the prefix +
.
I only need to configure one local git repository with all of the remotes
I am concerned about; I can inspect, compare, cherry-pick, check out, etc.
any objects from any of those branches from any of my work trees; there's
only one .git
directory with all the configuration and storage for the
git blobs across all the versions.
Comments
gh
cli inside a worktree without providing the base branch you want to merge it back to.Also, if you have branch X in a worktree in /X, trying to do checkout that branch in the original place/repo will just tell you "already checked out at /X" and refuse to work. Can break tooling, this.