[RFC] Branches with --recurse-submodules

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Original Submodule UX RFC/Discussion:
https://lore.kernel.org/git/YHofmWcIAidkvJiD@xxxxxxxxxx/

Contributor Summit submodules Notes:
https://lore.kernel.org/git/nycvar.QRO.7.76.6.2110211148060.56@xxxxxxxxxxxxxxxxx/

Submodule UX overhaul updates:
https://lore.kernel.org/git/?q=Submodule+UX+overhaul+update

Hi all! Building on Emily’s original RFC, here is a more fleshed out
vision of how `git {switch,checkout,branch}` will work with
submodule-native branches.

The "Background" section reframes the justification and mental model
behind our proposed workflow in more explicit terms (see "Submodule UX
RFC:Overview"). The "Design" section presents the rules we are using to
implement "Submodule UX RFC:Detailed Design", and how certain corner
cases should be handled.

I’d appreciate any and all feedback :) In particular, readers may be
interested in the "dirty worktree" approach behind `git switch`. If
anything stands out as good, bad or missing, do let us know. Thanks!

== Background

The purpose of this effort is to bring the benefits of branches to
superprojects. In Git, branches are used to name and track progress;
submodules are used to incorporate other repos. However, because of how
submodules are tracked by superprojects, submodules usually operate in
detached HEAD and the benefits of branches are lost. For users
uncomfortable with detached HEAD, this workflow seems risky and
unintuitive. Other users may still prefer branches because they can have
branch reflog and they can be confident that submodule work is being
tracked by some branch and won’t be gc-ed.

The main ideas are:

* there is a single set of branch names that are used throughout the
  repo tree
* progress can be made on submodules and/or the superproject without
  requiring a gitlink update on the superproject
* the user can switch between branches like they would for a
  non-submodule-using repo.

We do not require the branches to move in lockstep, thus this UX may be
suboptimal for logical monorepos that are implemented as submodules.

== Design

This design uses the same branch name in the superproject and
submodules; a user who sees the branch `topic` in the superproject and
submodules knows that they are the same logical thing. Commands with
--recurse-submodules maintain the invariant that branches in the
superproject and submodules are {read,created,modified,deleted}
together.

e.g.

* `git branch --recurse-submodules topic` should create the branch
  `topic` in each of the repositories.
* `git switch --recurse-submodules topic` should checkout the branch
  `topic` in each of the repositories

In a superproject-submodule relationship there is some ambiguity in what
‘checkout the branch `topic`’ should mean (does the submodule use its
topic branch, or the version recorded in the superproject’s gitlink?).
Our approach is to preserve existing semantics where reasonable - the
ref name refers to the superproject’s ref, just as it does without
--recurse-submodules.

One wrinkle is that a user can act on submodules _without_ going through
the superproject (e.g. by cd-ing into the submodule), thus the branch
tips may not match the expected commits in the superproject or the set
of submodules branches may not match the set of superproject branches.
As such, submodule branch names are resolved on a best-effort basis:

* If the submodule branch commit matches the one in the superproject, we
  can safely use the submodule branch.
* If the branch is in an unexpected state, we either:
** Fallback to the version that the user would expect (if it is safe to
    do so).
** Reject the operation (if it is not safe).

As we expand submodule branches to other commands (merge, rebase,
reset), the notions of ‘unexpected state’ and ‘safety’ become
increasingly nebulous and difficult to define because they depend on the
command being run. To manage this, we will start by supporting submodule
branching under a limited set of circumstances and try to loosen them in
the future. We will manage the user’s expectations by warning them if
Git detects an unexpected state.

The proposed rules for submodule branching are as follows:

=== Switching _from_ a branch `topic`, i.e. `git {switch,checkout}`

Check `topic` if each submodule’s worktree is clean (except for
gitlinks), and has one of the following checked out:

* `topic`
* the commit id in the superproject gitlink

This allows the user to switch with a dirty worktree (with respect to
the superproject). We consider this acceptable because the submodule
commits are tracked by the submodule branch. This is helpful when a user
needs to switch branches before they are ready to commit to the
superproject.

=== Switching _to_ a branch `topic`, i.e. `git {switch,checkout} topic`

Switch to `topic` in the superproject. Then in each submodule, switch to:

* `topic`, if it exists
* Otherwise, the commit id in the superproject gitlink (and warn the
  user that HEAD is detached)

If the submodule `topic` points to a different commit from the
superproject gitlink, this will leave the superproject with a dirty
worktree with respect to the gitlinks. This allows a user to recover
work if they had previously switched _away from_ "topic".

If a dirty worktree is unacceptable, we may need an option that is
guaranteed to check out the superproject’s `topic`.

=== Creating a branch `topic`, i.e. `git branch topic start-point`

Check each submodule at the superproject’s `start-point` (not the
submodule’s `start-point`) for the following:

* The submodule is initialized (in .git/modules)
* `topic` is a valid branch name

If so, create `topic` in the superproject and submodules based on the
superproject’s `start-point`. Else, do not create any `topic` branches
and guide the user towards a possible fix:

* A --force option that will move the branch tip to the commit in the
  superproject. This will let the user overwrite the history of `topic`.
* An --ignore option that ignores the existing `topic` branch. If used,
  `git switch topic` would result in a dirty worktree.
* (If needed) An --adopt option that creates a new superproject commit
  that points to the existing submodule `topic` branch. This will let
  the user checkout `topic` without ending up with a dirty worktree.
* For uninitialized submodules, prompt them to initialize it via git
  checkout start-point && git submodule update (we are working to
  eliminate manual initialization in the long run, so this will become
  obsolete eventually).




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux