just playing with tangled
at gvimdiff 292 lines 9.9 kB view raw view rendered
1# Using Jujutsu with GitHub and GitLab Projects 2 3This guide assumes a basic understanding of either Git or Mercurial. 4 5## Set up an SSH key 6 7As of October 2023 it's recommended to set up an SSH key to work with GitHub 8projects. See [GitHub's Tutorial][gh]. This restriction may be lifted in the 9future, see [issue #469][http-auth] for more information and progress on 10authenticated HTTP. 11 12## Basic workflow 13 14The simplest way to start with Jujutsu is to create a stack of commits first. 15You will only need to create a bookmark when you need to push the stack to a 16remote. There are two primary workflows: using a generated bookmark name or 17naming a bookmark. 18 19### Using a generated bookmark name 20 21In this example we're letting Jujutsu auto-create a bookmark. 22 23```shell 24# Start a new commit off of the default bookmark. 25$ jj new main 26# Refactor some files, then add a description and start a new commit 27$ jj commit -m 'refactor(foo): restructure foo()' 28# Add a feature, then add a description and start a new commit 29$ jj commit -m 'feat(bar): add support for bar' 30# Let Jujutsu generate a bookmark name and push that to GitHub. Note that we 31# push the working-copy commit's *parent* because the working-copy commit 32# itself is empty. 33$ jj git push -c @- 34``` 35 36### Using a named bookmark 37 38In this example, we create a bookmark named `bar` and then push it to the remote. 39 40```shell 41# Start a new commit off of the default bookmark. 42$ jj new main 43# Refactor some files, then add a description and start a new commit 44$ jj commit -m 'refactor(foo): restructure foo()' 45# Add a feature, then add a description and start a new commit 46$ jj commit -m 'feat(bar): add support for bar' 47# Create a bookmark so we can push it to GitHub. Note that we created the bookmark 48# on the working-copy commit's *parent* because the working copy itself is empty. 49$ jj bookmark create bar -r @- # `bar` now contains the previous two commits. 50# Push the bookmark to GitHub (pushes only `bar`) 51$ jj git push --allow-new 52``` 53 54While it's possible to create a bookmark in advance and commit on top of it in a 55Git-like manner, you will then need to move the bookmark manually when you create 56a new commits. Unlike Git, Jujutsu will not do it automatically. 57 58## Updating the repository 59 60As of October 2023, Jujutsu has no equivalent to a `git pull` command (see 61[issue #1039][sync-issue]). Until such a command is added, you need to use 62`jj git fetch` followed by a `jj rebase -d $main_bookmark` to update your 63changes. 64 65[sync-issue]: https://github.com/jj-vcs/jj/issues/1039 66 67## Working in a Git co-located repository 68 69After doing `jj git init --colocate`, Git will be in a [detached HEAD 70state][detached], which is unusual, as Git mainly works with named branches; jj 71does not. 72 73In a co-located repository, every `jj` command will automatically synchronize 74Jujutsu's view of the repo with Git's view. For example, `jj commit` updates the 75HEAD of the Git repository, enabling an incremental migration. 76 77```shell 78$ nvim docs/tutorial.md 79$ # Do some more work. 80$ jj commit -m "Update tutorial" 81# Create a bookmark on the working-copy commit's parent 82$ jj bookmark create doc-update -r @- 83$ jj git push --allow-new 84``` 85 86## Working in a Jujutsu repository 87 88In a Jujutsu repository, the workflow is simplified. If there's no need for 89explicitly named bookmarks, you can just generate one for a change. As Jujutsu is 90able to create a bookmark for a revision. 91 92```shell 93$ # Do your work 94$ jj commit 95$ # Push change "mw", letting Jujutsu automatically create a bookmark called 96$ # "push-mwmpwkwknuz" 97$ jj git push --change mw 98``` 99 100## Addressing review comments 101 102There are two workflows for addressing review comments, depending on your 103project's preference. Many projects prefer that you address comments by adding 104commits to your bookmark[^1]. Some projects (such as Jujutsu and LLVM) instead 105prefer that you keep your commits clean by rewriting them and then 106force-pushing[^2]. 107 108### Adding new commits 109 110If your project prefers that you address review comments by adding commits on 111top, you can do that by doing something like this: 112 113```shell 114$ # Create a new commit on top of the `your-feature` bookmark from above. 115$ jj new your-feature 116$ # Address the comments by updating the code. Then review the changes. 117$ jj diff 118$ # Give the fix a description and create a new working-copy on top. 119$ jj commit -m 'address pr comments' 120$ # Update the bookmark to point to the new commit. 121$ jj bookmark move your-feature --to @- 122$ # Push it to your remote 123$ jj git push 124``` 125 126Notably, the above workflow creates a new commit for you. The same can be 127achieved without creating a new commit. 128 129!!! warning 130 131 We strongly suggest to `jj new` after the example below, as all further edits 132 still get amended to the previous commit. 133 134```shell 135$ # Create a new commit on top of the `your-feature` bookmark from above. 136$ jj new your-feature 137$ # Address the comments by updating the code. Then review the changes. 138$ jj diff 139$ # Give the fix a description. 140$ jj describe -m 'address pr comments' 141$ # Update the bookmark to point to the current commit. 142$ jj bookmark move your-feature --to @ 143$ # Push it to your remote 144$ jj git push 145``` 146 147### Rewriting commits 148 149If your project prefers that you keep commits clean, you can do that by doing 150something like this: 151 152```shell 153$ # Create a new commit on top of the second-to-last commit in `your-feature`, 154$ # as reviewers requested a fix there. 155$ jj new your-feature- # NOTE: the trailing hyphen is not a typo! 156$ # Address the comments by updating the code. Then review the changes. 157$ jj diff 158$ # Squash the changes into the parent commit 159$ jj squash 160$ # Push the updated bookmark to the remote. Jujutsu automatically makes it a 161$ # force push 162$ jj git push --bookmark your-feature 163``` 164 165The hyphen after `your-feature` comes from the 166[revset](https://github.com/jj-vcs/jj/blob/main/docs/revsets.md) syntax. 167 168## Working with other people's bookmarks 169 170By default, `jj git clone` imports the default remote bookmark (which is usually 171`main` or `master`), but `jj git fetch` doesn't import new remote bookmarks to 172local bookmarks. This means that if you want to iterate or test another 173contributor's bookmark, you'll need to do `jj new <bookmark>@<remote>` onto it. 174 175If you want to import all remote bookmarks including inactive ones, set 176`git.auto-local-bookmark = true` in the config file. Then you can specify a 177contributor's bookmark as `jj new <bookmark>` instead of `jj new <bookmark>@<remote>`. 178 179You can find more information on that setting [here][auto-bookmark]. 180 181## Using GitHub CLI 182 183GitHub CLI will have trouble finding the proper Git repository path in jj repos 184that aren't [co-located](./git-compatibility.md#co-located-jujutsugit-repos) 185(see [issue #1008]). You can configure the `$GIT_DIR` environment variable to 186point it to the right path: 187 188```shell 189$ GIT_DIR=.jj/repo/store/git gh issue list 190``` 191 192You can make that automatic by installing [direnv](https://direnv.net) and 193defining hooks in a `.envrc` file in the repository root to configure `$GIT_DIR`. 194Just add this line into `.envrc`: 195 196```shell 197export GIT_DIR=$PWD/.jj/repo/store/git 198``` 199 200and run `direnv allow` to approve it for direnv to run. Then GitHub CLI will 201work automatically even in repos that aren't co-located so you can execute 202commands like `gh issue list` normally. 203 204[issue #1008]: https://github.com/jj-vcs/jj/issues/1008 205 206## Useful Revsets 207 208Log all revisions across all local bookmarks that aren't on the main bookmark nor 209on any remote: 210 211```shell 212$ jj log -r 'bookmarks() & ~(main | remote_bookmarks())' 213``` 214 215Log all revisions that you authored, across all bookmarks that aren't on any 216remote: 217 218```shell 219$ jj log -r 'mine() & bookmarks() & ~remote_bookmarks()' 220``` 221 222Log all remote bookmarks that you authored or committed to: 223 224```shell 225$ jj log -r 'remote_bookmarks() & (mine() | committer(your@email.com))' 226``` 227 228Log all ancestors of the current working copy that aren't on any remote: 229 230```shell 231$ jj log -r 'remote_bookmarks()..@' 232``` 233 234## Merge conflicts 235 236For a detailed overview, how Jujutsu handles conflicts, revisit 237the [tutorial][tut]. 238 239[^1]: 240 This is a GitHub-style review, as GitHub currently only is able to compare 241 bookmarks. 242 243[^2]: 244 If you're wondering why we prefer clean commits in this project, see 245 e.g. [this blog post][stacked] 246 247[auto-bookmark]: config.md#automatic-local-bookmark-creation 248[detached]: https://git-scm.com/docs/git-checkout#_detached_head 249[gh]: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent 250[http-auth]: https://github.com/jj-vcs/jj/issues/469 251[tut]: tutorial.md#conflicts 252[stacked]: https://jg.gg/2018/09/29/stacked-diffs-versus-pull-requests/ 253 254## Using several remotes 255 256It is common to use several remotes when contributing to a shared repository. 257For example, "upstream" can designate the remote where the changes will be 258merged through a pull-request while "origin" is your private fork of the 259project. 260 261```shell 262$ jj git clone --remote upstream https://github.com/upstream-org/repo 263$ cd repo 264$ jj git remote add origin git@github.com:your-org/your-repo-fork 265``` 266 267This will automatically setup your repository to track the main 268bookmark from the upstream repository, typically `main@upstream` 269or `master@upstream`. 270 271You might want to `jj git fetch` from "upstream" and to `jj git push` 272to "origin". You can configure the default remotes to fetch from and 273push to in your configuration file (for example, 274`.jj/repo/config.toml`): 275 276```toml 277[git] 278fetch = "upstream" 279push = "origin" 280``` 281 282The default for both `git.fetch` and `git.push` is "origin". 283 284If you usually work on a project from several computers, you may 285configure `jj` to fetch from both repositories by default, in order to 286keep your own bookmarks synchronized through your `origin` repository: 287 288```toml 289[git] 290fetch = ["upstream", "origin"] 291push = "origin" 292```