git-p4son 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {git_p4son-0.6.0 → git_p4son-0.7.0}/PKG-INFO +448 -101
- {git_p4son-0.6.0 → git_p4son-0.7.0}/README.md +446 -99
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/__init__.py +2 -2
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/alias.py +25 -4
- git_p4son-0.7.0/git_p4son/backend.py +136 -0
- git_p4son-0.7.0/git_p4son/changelist_store.py +299 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/cli.py +171 -139
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/common.py +89 -21
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/complete.py +78 -40
- git_p4son-0.7.0/git_p4son/completions/git-p4son-jj.bash +53 -0
- git_p4son-0.7.0/git_p4son/completions/git-p4son-jj.ps1 +73 -0
- git_p4son-0.7.0/git_p4son/completions/git-p4son-jj.zsh +40 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/completions/git-p4son.bash +7 -2
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/config.py +13 -48
- git_p4son-0.7.0/git_p4son/git.py +643 -0
- git_p4son-0.7.0/git_p4son/git_backend.py +191 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/hooks.py +5 -5
- git_p4son-0.7.0/git_p4son/included.py +131 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/init.py +86 -11
- git_p4son-0.7.0/git_p4son/jj.py +548 -0
- git_p4son-0.7.0/git_p4son/jj_backend.py +262 -0
- git_p4son-0.7.0/git_p4son/jj_lock.py +95 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/lib.py +82 -35
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/list_changes.py +4 -2
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/log.py +19 -4
- git_p4son-0.7.0/git_p4son/new.py +112 -0
- git_p4son-0.7.0/git_p4son/per_commit.py +122 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/perforce.py +34 -26
- git_p4son-0.7.0/git_p4son/skill/SKILL.md +10 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/skill/git-p4son.md +95 -42
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/sync.py +92 -82
- git_p4son-0.7.0/git_p4son/sync_branch.py +28 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/sync_merge.py +5 -2
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/sync_split_users.py +13 -12
- git_p4son-0.7.0/git_p4son/toml_writer.py +54 -0
- git_p4son-0.7.0/git_p4son/update.py +181 -0
- git_p4son-0.7.0/git_p4son/words.py +27 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/writable.py +10 -9
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son.egg-info/PKG-INFO +448 -101
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son.egg-info/SOURCES.txt +20 -4
- {git_p4son-0.6.0 → git_p4son-0.7.0}/pyproject.toml +22 -2
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_alias.py +44 -2
- git_p4son-0.7.0/tests/test_catch_up.py +264 -0
- git_p4son-0.7.0/tests/test_changelist_store.py +387 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_cli.py +186 -91
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_common.py +21 -3
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_complete.py +32 -12
- git_p4son-0.7.0/tests/test_completion_scripts.py +199 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_config.py +2 -1
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_git.py +173 -60
- git_p4son-0.7.0/tests/test_git_backend.py +188 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_hooks.py +13 -12
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_init.py +270 -12
- git_p4son-0.7.0/tests/test_isolation.py +39 -0
- git_p4son-0.7.0/tests/test_jj.py +944 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_lib.py +122 -17
- git_p4son-0.7.0/tests/test_list_changes.py +50 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_log.py +22 -2
- git_p4son-0.7.0/tests/test_new.py +379 -0
- git_p4son-0.7.0/tests/test_per_commit.py +187 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_perforce.py +31 -24
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_sync.py +206 -161
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_sync_merge.py +8 -8
- git_p4son-0.7.0/tests/test_toml_writer.py +35 -0
- git_p4son-0.7.0/tests/test_update.py +513 -0
- git_p4son-0.6.0/git_p4son/changelist_store.py +0 -130
- git_p4son-0.6.0/git_p4son/git.py +0 -396
- git_p4son-0.6.0/git_p4son/new.py +0 -38
- git_p4son-0.6.0/git_p4son/rebase_todo.py +0 -158
- git_p4son-0.6.0/git_p4son/review.py +0 -36
- git_p4son-0.6.0/git_p4son/skill/SKILL.md +0 -8
- git_p4son-0.6.0/git_p4son/update.py +0 -59
- git_p4son-0.6.0/tests/test_changelist_store.py +0 -190
- git_p4son-0.6.0/tests/test_list_changes.py +0 -31
- git_p4son-0.6.0/tests/test_new.py +0 -131
- git_p4son-0.6.0/tests/test_rebase_todo.py +0 -219
- git_p4son-0.6.0/tests/test_review.py +0 -111
- git_p4son-0.6.0/tests/test_update.py +0 -211
- {git_p4son-0.6.0 → git_p4son-0.7.0}/LICENSE +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/__main__.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/completions/_git-p4son +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/completions/git-p4son.ps1 +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/depot.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/description.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/processes.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son/skill.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son.egg-info/dependency_links.txt +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son.egg-info/entry_points.txt +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/git_p4son.egg-info/top_level.txt +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/setup.cfg +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_depot.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_description.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_processes.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_skill.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_sync_split_users.py +0 -0
- {git_p4son-0.6.0 → git_p4son-0.7.0}/tests/test_writable.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-p4son
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Utility for keeping a Perforce workspace and local git repo in sync
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: Utility for keeping a Perforce workspace and local git or jj repo in sync
|
|
5
5
|
Author-email: Andreas Andersson <andreas@neoboid.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/neoboid/git-p4son
|
|
@@ -23,21 +23,20 @@ Dynamic: license-file
|
|
|
23
23
|
|
|
24
24
|
# Git Perforcesson
|
|
25
25
|
|
|
26
|
-
`git-p4son`
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
`git-p4son` lets you work in a Perforce workspace with a local git repository, or a colocated
|
|
27
|
+
[Jujutsu (jj)](#jujutsu-jj) one, so you can use the familiar local development flow even though your project uses
|
|
28
|
+
Perforce for source control.
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
A `main` branch (a bookmark in jj) is kept in sync with your Perforce workspace, one commit per changelist. You work
|
|
31
|
+
on feature branches or jj changes and rebase them onto `main` after a sync; with jj, `sync` rebases the change you
|
|
32
|
+
sync from for you.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
to the pull request worfkflow on github.
|
|
34
|
+
When your changes are ready, `git-p4son` creates the changelist and shelves it for a Swarm review. It can post each
|
|
35
|
+
commit as a patch of its own, so reviewers see the changes in the order you made them, much like a pull request.
|
|
36
|
+
Updates fold in only the new commits.
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
With jj, `git-p4son` works on the jj change: the changelist's alias follows the change through rewrites, the message
|
|
39
|
+
comes from its description, and `jj p4son` runs every command.
|
|
41
40
|
|
|
42
41
|
## On big workspaces
|
|
43
42
|
Sometimes git struggles to keep entire perforce workspaces in the repo, like when working
|
|
@@ -74,8 +73,8 @@ git add .
|
|
|
74
73
|
git commit -m "Feature part2"
|
|
75
74
|
|
|
76
75
|
# Create a Swarm review with all commits since main in one go.
|
|
77
|
-
#
|
|
78
|
-
#
|
|
76
|
+
# Each commit is checked out in turn and gets a shelf of its own in the
|
|
77
|
+
# review, then you are back on your branch.
|
|
79
78
|
# An alias called "my-fancy-feature" (derived from the branch name) is
|
|
80
79
|
# saved so you can refer to this CL by name in follow-up commands.
|
|
81
80
|
git p4son review -m "My fancy feature" -b main
|
|
@@ -104,6 +103,44 @@ git p4son alias delete my-fancy-feature
|
|
|
104
103
|
git checkout -b my-next-fancy-feature
|
|
105
104
|
```
|
|
106
105
|
|
|
106
|
+
### With jj
|
|
107
|
+
|
|
108
|
+
The same workflow in a [colocated jj workspace](#jujutsu-jj), with the [`jj p4son` alias](#the-jj-p4son-alias):
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
# Start work on a new feature
|
|
112
|
+
jj new main -m "Feature part1"
|
|
113
|
+
# Change some code, which jj snapshots into the change
|
|
114
|
+
|
|
115
|
+
# Sync main from any change: the change you are on is rebased onto it
|
|
116
|
+
jj p4son sync
|
|
117
|
+
|
|
118
|
+
# Change even more code in a change of its own
|
|
119
|
+
jj new -m "Feature part2"
|
|
120
|
+
jj bookmark create my-fancy-feature
|
|
121
|
+
|
|
122
|
+
# Create a Swarm review with every change since main, one shelf each.
|
|
123
|
+
# The alias is named after the bookmark and records the jj change.
|
|
124
|
+
jj p4son review -m "My fancy feature" -b main
|
|
125
|
+
|
|
126
|
+
# After review feedback, add a change and move the bookmark to it
|
|
127
|
+
jj new -m "Address review feedback"
|
|
128
|
+
jj bookmark set my-fancy-feature -r @
|
|
129
|
+
jj p4son update --shelve
|
|
130
|
+
|
|
131
|
+
# After approval, submit in p4v, then abandon the submitted changes before
|
|
132
|
+
# syncing, which deletes the bookmark too
|
|
133
|
+
jj abandon main..my-fancy-feature
|
|
134
|
+
jj p4son alias delete my-fancy-feature
|
|
135
|
+
jj p4son sync
|
|
136
|
+
|
|
137
|
+
# Start working on the next feature
|
|
138
|
+
jj new main -m "Next fancy feature"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`sync` only rebases the change you sync from, and the stack above it. Bring other bookmarks up to date with
|
|
142
|
+
`jj rebase -b <bookmark> -d main`.
|
|
143
|
+
|
|
107
144
|
## Installation
|
|
108
145
|
|
|
109
146
|
```sh
|
|
@@ -161,19 +198,13 @@ cloning.
|
|
|
161
198
|
|
|
162
199
|
These steps set up git-p4son in an existing Perforce workspace. You only need to do this once.
|
|
163
200
|
|
|
164
|
-
1. **
|
|
165
|
-
editor. If you haven't configured one, set it with:
|
|
166
|
-
```sh
|
|
167
|
-
git config --global core.editor <editor> # e.g. vim, nano, code --wait
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
2. **Sync your workspace to a known changelist.** Pick a changelist to use as the starting point for your git
|
|
201
|
+
1. **Sync your workspace to a known changelist.** Pick a changelist to use as the starting point for your git
|
|
171
202
|
history:
|
|
172
203
|
```sh
|
|
173
204
|
p4 sync //...@12345
|
|
174
205
|
```
|
|
175
206
|
|
|
176
|
-
|
|
207
|
+
2. **Run `git p4son init`.** This can be anywhere inside your Perforce workspace - it doesn't have to be at the
|
|
177
208
|
root:
|
|
178
209
|
```sh
|
|
179
210
|
cd /path/to/your/workspace # or a subdirectory of it
|
|
@@ -182,16 +213,18 @@ These steps set up git-p4son in an existing Perforce workspace. You only need to
|
|
|
182
213
|
The command verifies that you are inside a P4 workspace, prompts you to select a depot
|
|
183
214
|
root (entire workspace or current directory subtree), runs `git init`, sets up `.gitignore` (copying from
|
|
184
215
|
`.p4ignore` if available), and creates an initial commit.
|
|
216
|
+
With jj 0.41 or newer installed, it also offers to colocate jj and to add the `jj p4son` alias, see
|
|
217
|
+
[Jujutsu (jj)](#jujutsu-jj).
|
|
185
218
|
|
|
186
|
-
|
|
219
|
+
3. **Review `.gitignore`.** Edit the file to ensure build artifacts and other unwanted files are excluded.
|
|
187
220
|
|
|
188
|
-
|
|
221
|
+
4. **Add and commit all files manually the first time**
|
|
189
222
|
```sh
|
|
190
223
|
git add .
|
|
191
224
|
git commit -m "Initial submit all files"
|
|
192
225
|
```
|
|
193
226
|
|
|
194
|
-
|
|
227
|
+
5. **Run `git p4son sync`** to get your first official sync commit
|
|
195
228
|
```sh
|
|
196
229
|
git p4son sync
|
|
197
230
|
```
|
|
@@ -256,6 +289,10 @@ write most of them; the rest you edit by hand.
|
|
|
256
289
|
`//$(workspace)/Engine`. See [Init Command](#init-command)
|
|
257
290
|
- `[core] writable` (`true` or `false`, default `false`): [writable mode](#writable-command), which keeps
|
|
258
291
|
git-tracked files writable
|
|
292
|
+
- `[core] backend` (`"auto"`, `"git"` or `"jj"`, default `"auto"`): the tool git-p4son follows for the change, the
|
|
293
|
+
base and the branch. `auto` means jj in a [jj workspace](#jujutsu-jj) and git otherwise
|
|
294
|
+
- `[sync] branch` (string, set by `init`): the sync branch, which `sync` commits onto from whatever branch you are
|
|
295
|
+
on. Without it, `sync` uses `main`. See [Sync Command](#sync-command)
|
|
259
296
|
- `[sync] split-users` (list of strings, default empty): the users whose changelists `sync` gives a commit each;
|
|
260
297
|
`$(user)` stands for you. See [Split users](#split-users)
|
|
261
298
|
- `[sync] blocking-processes` (list of strings, default empty): processes that stop a sync while they run. See
|
|
@@ -308,9 +345,9 @@ Initialize a git repository inside a Perforce workspace:
|
|
|
308
345
|
git p4son init
|
|
309
346
|
```
|
|
310
347
|
|
|
311
|
-
This command checks that it runs in a Perforce workspace, then asks for the depot root, writable mode, split users
|
|
312
|
-
|
|
313
|
-
`.gitignore`. It ends by listing the next steps
|
|
348
|
+
This command checks that it runs in a Perforce workspace, then asks for the depot root, writable mode, split users,
|
|
349
|
+
the Claude Code skill and jj. It then sets up `.gitignore`, runs `git init` and creates a first commit holding only
|
|
350
|
+
`.gitignore`. It ends by listing the next steps.
|
|
314
351
|
|
|
315
352
|
The depot root determines which part of the Perforce workspace git-p4son syncs. You can choose to sync the entire
|
|
316
353
|
workspace or just the directory's subtree where the git root is placed. The selection is saved in
|
|
@@ -336,17 +373,45 @@ saves the answer; run `git p4son writable apply` once your files are committed t
|
|
|
336
373
|
The default is the current setting. Yes adds a `$(user)` entry to the split users and no removes it; other split
|
|
337
374
|
users are left alone.
|
|
338
375
|
|
|
376
|
+
`init` records the [sync branch](#sync-command) as `[sync] branch`. In a repository it creates, that's the branch
|
|
377
|
+
`HEAD` is on. In an existing one, it's `main` if there is one, else the branch `HEAD` is on, else one you pick from
|
|
378
|
+
the local branches. It keeps a branch already set.
|
|
379
|
+
|
|
339
380
|
If Claude Code is installed, `init` offers to install the [Claude Code skill](#claude-code-skill). An
|
|
340
381
|
already installed skill is refreshed without asking.
|
|
341
382
|
|
|
383
|
+
With jj 0.41 or newer installed, `init` offers two things for [jj](#jujutsu-jj):
|
|
384
|
+
|
|
385
|
+
- **Colocating jj**, when the workspace has no `.jj` folder: "Use jj in this workspace too (colocated)?", default
|
|
386
|
+
no. On yes, in an existing repository it runs `jj git init --colocate` as its last step, so jj imports the branch
|
|
387
|
+
as a bookmark. It sets jj's [line endings](#line-endings) to match git's from jj's first snapshot on. In a
|
|
388
|
+
repository it creates, it lists the same commands as next steps after your initial commit instead, since jj would
|
|
389
|
+
otherwise snapshot every file before you have reviewed `.gitignore`.
|
|
390
|
+
- **The [`jj p4son` alias](#the-jj-p4son-alias)**, when the workspace has a `.jj` folder, or is to get one, and
|
|
391
|
+
jj's config has no `aliases.p4son`: default yes. It adds the alias to jj's user config.
|
|
392
|
+
|
|
393
|
+
Running `init` again asks neither once they are done.
|
|
394
|
+
|
|
342
395
|
### Sync Command
|
|
343
396
|
|
|
344
397
|
Sync local git repository with a Perforce workspace:
|
|
345
398
|
|
|
346
399
|
```sh
|
|
347
|
-
git p4son sync [changelist ...] [--force] [--dry-run] [--split-user NAME ...] [--no-split]
|
|
400
|
+
git p4son sync [changelist ...] [--branch BRANCH] [--force] [--dry-run] [--split-user NAME ...] [--no-split]
|
|
401
|
+
[--ignore-blocking-processes]
|
|
348
402
|
```
|
|
349
403
|
|
|
404
|
+
`sync` commits onto the sync branch, `[sync] branch` in `.git-p4son/config.toml`, which `init` sets and which
|
|
405
|
+
defaults to `main`. From another branch, it checks the sync branch out, syncs and commits, then returns you to
|
|
406
|
+
where you started, telling you to `git rebase` your branch onto the sync branch; it doesn't rebase for you. The
|
|
407
|
+
pre-sync and post-sync hooks run on the sync branch. You stay on the sync branch when:
|
|
408
|
+
|
|
409
|
+
- local changes were [merged back](#how-sync-handles-writable-files) into the work tree, for you to review and
|
|
410
|
+
commit there
|
|
411
|
+
- a sync fails partway, with the files as Perforce left them and the commits so far kept
|
|
412
|
+
|
|
413
|
+
A failing pre-sync hook, or anything else that stops `sync` before it syncs, returns you to where you started.
|
|
414
|
+
|
|
350
415
|
**Arguments:**
|
|
351
416
|
- `changelist` (optional): Changelist number, `last-synced` to re-sync the last synced changelist, or `head`
|
|
352
417
|
to sync to the latest changelist. Omit to sync to the latest changelist affecting the workspace. Several
|
|
@@ -358,6 +423,10 @@ git-tracked files opened in Perforce. It checks them after any [blocking process
|
|
|
358
423
|
the [pre-sync hooks](#pre-sync-hook).
|
|
359
424
|
|
|
360
425
|
**Options:**
|
|
426
|
+
- `--branch BRANCH`: Commit onto this branch instead of `[sync] branch`. With the jj backend, the bookmark to move
|
|
427
|
+
to each sync commit
|
|
428
|
+
- `--no-rebase`: With the jj backend, leave the changes you started from where they are, instead of rebasing them
|
|
429
|
+
onto the [sync bookmark](#syncing-a-bookmark)
|
|
361
430
|
- `-f, --force`: Allow syncing to changelists older than the current one
|
|
362
431
|
- `-n, --dry-run`: Print the resolved sync sequence without syncing. The arguments are validated as for a
|
|
363
432
|
real sync, but nothing else runs: no clean-workspace checks, no hooks, and no prompts. Ends with
|
|
@@ -380,6 +449,7 @@ git p4son sync 12345 --force
|
|
|
380
449
|
git p4son sync --dry-run # show the changelists a sync to latest would visit
|
|
381
450
|
git p4son sync -u alice # also split out alice's changelists
|
|
382
451
|
git p4son sync --no-split # sync without splitting out the configured split users
|
|
452
|
+
git p4son sync --branch p4 # commit onto the p4 branch this time
|
|
383
453
|
```
|
|
384
454
|
|
|
385
455
|
#### Blocking processes
|
|
@@ -426,10 +496,12 @@ visits `101 102 103 104 105 106`.
|
|
|
426
496
|
Splitting only moves forward from a previous sync. The first sync, `last-synced`, and syncing to an older changelist
|
|
427
497
|
with `--force` are never split. Without any split users, `sync` makes no extra Perforce queries.
|
|
428
498
|
|
|
429
|
-
Finding the split users' changelists costs one
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
499
|
+
Finding the split users' changelists costs one Perforce query per split user, listing their changelists in the range
|
|
500
|
+
being synced, then one batched query that checks each changelist found touched the workspace and finds the one before
|
|
501
|
+
it. None of them scans the files of every changelist in the range, which on a large range can exceed the server's
|
|
502
|
+
`maxscanrows`. They run after the blocking processes check, the clean-workspace checks and the pre-sync hooks, so a
|
|
503
|
+
running blocking process, a dirty workspace or a hook that aborts the sync says so before that work. `--dry-run` skips
|
|
504
|
+
the checks and hooks but still shows the resulting sequence.
|
|
433
505
|
|
|
434
506
|
#### Hooks
|
|
435
507
|
|
|
@@ -467,8 +539,8 @@ is skipped with `--no-edit`. After opening files, unchanged ones are reverted (s
|
|
|
467
539
|
[Keeping the changelist in sync with git](#keeping-the-changelist-in-sync-with-git)).
|
|
468
540
|
|
|
469
541
|
```sh
|
|
470
|
-
git p4son new [-m <message> | -F <file>] [alias] [--
|
|
471
|
-
[--no-alias] [--no-commit-list] [--shelve] [--review]
|
|
542
|
+
git p4son new -b BASE_BRANCH [-m <message> | -F <file>] [alias] [--force] [--dry-run] [--no-edit]
|
|
543
|
+
[--no-alias] [--no-commit-list] [--shelve] [--review] [--per-commit]
|
|
472
544
|
```
|
|
473
545
|
|
|
474
546
|
**Arguments:**
|
|
@@ -480,44 +552,92 @@ git p4son new [-m <message> | -F <file>] [alias] [--base-branch BASE_BRANCH] [--
|
|
|
480
552
|
multiple lines
|
|
481
553
|
- `--no-commit-list`: Leave the enumerated commit list out of the changelist description, so it holds only the
|
|
482
554
|
message
|
|
483
|
-
- `-b, --base-branch BASE_BRANCH`:
|
|
484
|
-
|
|
555
|
+
- `-b, --base-branch BASE_BRANCH`: Required. The base the change starts from, for enumerating commits and finding
|
|
556
|
+
changed files: a branch or bookmark, or a commit exactly one points at. The alias records it by name, as a commit
|
|
557
|
+
would go stale after a sync and rebase, along with the commits since it the changelist includes, so `update`
|
|
558
|
+
knows where the next ones start. With `--no-alias` any commit will do
|
|
485
559
|
- `-f, --force`: Overwrite an existing alias file
|
|
486
560
|
- `-n, --dry-run`: Pretend and print what would be done, but do not execute. Ends with `Dry run, nothing changed`
|
|
487
561
|
- `--no-edit`: Skip opening changed files for edit in Perforce
|
|
488
562
|
- `--no-alias`: Skip saving a changelist alias
|
|
489
563
|
- `--shelve`: Shelve the changelist after creating it
|
|
490
564
|
- `--review`: Add `#review` keyword and shelve to create a Swarm review
|
|
565
|
+
- `--per-commit`: Create the changelist on the first commit since the base branch, then update it once per later
|
|
566
|
+
commit, as described below. Refuses `--no-edit` and `--no-alias`
|
|
567
|
+
|
|
568
|
+
With `--per-commit`, `new` checks out the first commit since the base branch and runs `git p4son new` on it, then
|
|
569
|
+
checks out each later commit and runs `git p4son update` on it, and finally returns to where you started. With
|
|
570
|
+
`--shelve` or `--review`, every step shelves, so each commit shows up as its own patch in the Swarm review, and every
|
|
571
|
+
step but the last sleeps 5 seconds to give Perforce/Swarm time to process the shelf. It needs a clean git
|
|
572
|
+
workspace even with `--dry-run`. [`review`](#review-command) is `new --review --per-commit`, and describes the steps,
|
|
573
|
+
the dry run and resuming after a failed step.
|
|
491
574
|
|
|
492
575
|
**Examples:**
|
|
493
576
|
```sh
|
|
494
|
-
git p4son new -m "Fix login bug"
|
|
495
577
|
git p4son new -m "Add feature" -b main
|
|
496
|
-
git p4son new -m "Fix bug" myalias
|
|
497
|
-
git p4son new -m "Fix bug" --no-alias
|
|
578
|
+
git p4son new -m "Fix bug" myalias -b main
|
|
579
|
+
git p4son new -m "Fix bug" --no-alias -b HEAD~1
|
|
498
580
|
git p4son new -m "New feature" --review -b main
|
|
581
|
+
git p4son new -m "New feature" --shelve --per-commit -b main # a shelf per commit, without a Swarm review
|
|
499
582
|
```
|
|
500
583
|
|
|
501
584
|
### Update Command
|
|
502
585
|
|
|
503
|
-
Update an existing Perforce changelist
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
it, while `update -b HEAD~3` only refreshes the last three entries. The message above the list is kept unless `-m`
|
|
507
|
-
or `-F` replaces it. By default also opens changed files for
|
|
508
|
-
edit, and reverts files that are no longer part of the git change (see
|
|
586
|
+
Update an existing Perforce changelist with the commits it doesn't include yet. The message above the commit list
|
|
587
|
+
is kept unless `-m` or `-F` replaces it. By default also opens changed files for edit, and reverts files that are no
|
|
588
|
+
longer part of the git change (see
|
|
509
589
|
[Keeping the changelist in sync with git](#keeping-the-changelist-in-sync-with-git)). Opening files requires a
|
|
510
590
|
clean git workspace, untracked files included; `update` refuses to run otherwise. The check is skipped with
|
|
511
591
|
`--no-edit`.
|
|
512
592
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
`
|
|
593
|
+
**Changelists made by `new` or `review`.** Their alias records the base, by name, and the commits since it the
|
|
594
|
+
changelist includes, by their jj change IDs or, with git, their author dates, which survive rebases and amends.
|
|
595
|
+
`update` folds in the commits it doesn't know: it appends their subjects to the commit list, opens their files, and
|
|
596
|
+
records them. The entries the list already has are left as they are, so an entry you reworded in the changelist
|
|
597
|
+
stays as you wrote it. Every update counts, shelved or not.
|
|
598
|
+
|
|
599
|
+
- `-b` only chooses which files to open, from that commit on, for example `-b main` to open them all again after a
|
|
600
|
+
manual `p4 revert`. The commit list is still only appended to. A `-b` above the last included commit is refused,
|
|
601
|
+
as the commits it skips would be counted without being opened.
|
|
602
|
+
- An included commit that is gone from the branch, dropped or squashed into another, gets a warning, and the update
|
|
603
|
+
goes on with the new commits. Its patch stays in the review: to undo a shelved commit, revert it in a new commit.
|
|
604
|
+
- A new commit below included ones is refused, as its own patch would undo the included commits above it. Move it
|
|
605
|
+
after them, then update again.
|
|
606
|
+
- An amend, or a squash into an included commit, keeps the commit's identity, so `update` sees no new commit. With
|
|
607
|
+
nothing new, `update` opens every file since the base, which takes in what the amend added. With new commits as
|
|
608
|
+
well, run `update -b main` to open them.
|
|
609
|
+
|
|
610
|
+
**After a sync.** A shelf holds whole files, so once a sync has changed files the changelist touches, its next shelf
|
|
611
|
+
would mix those changes into the next commit's patch. So when `update --shelve` finds that the base moved since the
|
|
612
|
+
last shelve, the branch was rebased onto it, and it changed such a file, it first inserts an empty commit, `Rebase
|
|
613
|
+
onto CL <N>`, right after the last included commit, with the commits after it rebased onto it. Its shelf is a patch
|
|
614
|
+
of its own, holding what the sync changed, and its entry keeps the commit list matching the patches.
|
|
615
|
+
|
|
616
|
+
- With `--per-commit`, it's the first step. Without it, `update --shelve` shelves twice: at the rebase commit, then at
|
|
617
|
+
the tip.
|
|
618
|
+
- An update without `--shelve` leaves the catch-up to the next one that shelves, and a changelist that was never
|
|
619
|
+
shelved has no patches to catch up. A dry run says what it would insert.
|
|
620
|
+
|
|
621
|
+
**Other changelists**, whose alias records nothing (made by `alias new` or an older git-p4son), or named by a number
|
|
622
|
+
no alias holds: the commits since the base branch, `HEAD~1` by default, replace their existing entries in the
|
|
623
|
+
commit list (matched by subject) and new ones are appended; entries outside the range are kept and the list is
|
|
624
|
+
renumbered.
|
|
625
|
+
|
|
626
|
+
With `--per-commit`, `update` runs once per commit instead of once for the whole range, the way `new --per-commit`
|
|
627
|
+
and `review` do after creating the changelist. It checks out each commit in turn, oldest first, runs the update on
|
|
628
|
+
it, and returns to where you started. With `--shelve`, every commit gets a shelf of its own and so shows up as its
|
|
629
|
+
own patch in the Swarm review.
|
|
630
|
+
|
|
631
|
+
- **With a record,** plain `update --per-commit --shelve` runs on exactly the commits the changelist doesn't include
|
|
632
|
+
yet. `-b` is refused there, as it would shelve included commits again.
|
|
633
|
+
- **Without one,** pass the range: `update -b HEAD~2 --per-commit --shelve` updates the changelist with the last two
|
|
634
|
+
commits, one at a time. The base is resolved once, before the first step, so a relative base like `HEAD~2` means
|
|
635
|
+
the same commit for every step.
|
|
636
|
+
|
|
637
|
+
`-m`/`-F` is applied on the first step only. It needs a clean git workspace, also with `--no-edit`. If a step
|
|
638
|
+
fails, `update` returns to where you started and names the step and commit that failed. The error ends with the
|
|
639
|
+
command that resumes after the last commit that worked, so earlier commits get no second shelf; with a record,
|
|
640
|
+
running the same command again does the same.
|
|
521
641
|
|
|
522
642
|
```sh
|
|
523
643
|
git p4son update [changelist] [-m <message> | -F <file>] [--base-branch BASE_BRANCH] [--dry-run]
|
|
@@ -531,27 +651,27 @@ git p4son update [changelist] [-m <message> | -F <file>] [--base-branch BASE_BRA
|
|
|
531
651
|
- `-m, --message MESSAGE`: Replace the changelist description message above the commit list. The commit list is
|
|
532
652
|
kept and updated as usual, and so is a Swarm `#review` keyword on a line of its own at the end of the description
|
|
533
653
|
- `-F, --file FILE`: Like `-m`, but read the message from a file. The message may span multiple lines
|
|
534
|
-
- `-b, --base-branch BASE_BRANCH`:
|
|
535
|
-
`HEAD~1`
|
|
654
|
+
- `-b, --base-branch BASE_BRANCH`: Where the commits to fold in start, for the commit list and the files to open.
|
|
655
|
+
Defaults to after the last commit the changelist includes, when its alias records that, else to `HEAD~1`
|
|
536
656
|
- `-n, --dry-run`: Pretend and print what would be done, but do not execute. Ends with `Dry run, nothing changed`
|
|
537
657
|
- `--no-commit-list`: Leave the enumerated commit list as it is. Without `-m` or `-F` the description is not
|
|
538
658
|
touched at all
|
|
539
|
-
- `--no-edit`: Skip opening changed files for edit in Perforce
|
|
659
|
+
- `--no-edit`: Skip opening changed files for edit in Perforce. With a record, the new commits are then neither
|
|
660
|
+
appended nor counted, so the next update that opens files includes them
|
|
540
661
|
- `--shelve`: Re-shelve the changelist after updating
|
|
541
|
-
- `--per-commit`: Update the changelist once per commit since the base branch
|
|
542
|
-
|
|
543
|
-
each shelf.
|
|
544
|
-
`--dry-run` prints the generated rebase todo. A message from `-m` or `-F` is saved to
|
|
545
|
-
`.git-p4son/reviews/message` for the first step
|
|
662
|
+
- `--per-commit`: Update the changelist once per commit it doesn't include yet, or since the base branch without
|
|
663
|
+
a record, oldest first, with each commit checked out in turn. With `--shelve`, steps sleep 5 seconds between them
|
|
664
|
+
to give Perforce/Swarm time to process each shelf. `--dry-run` prints the steps, one per commit
|
|
546
665
|
|
|
547
666
|
**Examples:**
|
|
548
667
|
```sh
|
|
549
|
-
git p4son update #
|
|
668
|
+
git p4son update # fold the new commits into the changelist for the current branch
|
|
550
669
|
git p4son update --shelve # update and re-shelve
|
|
551
670
|
git p4son update 12345
|
|
552
|
-
git p4son update myalias -b main
|
|
671
|
+
git p4son update myalias -b main # open every file of the change again
|
|
553
672
|
git p4son update -F description.txt # replace the message, e.g. after review feedback
|
|
554
|
-
git p4son update
|
|
673
|
+
git p4son update --per-commit --shelve # one shelf for each commit the changelist doesn't include yet
|
|
674
|
+
git p4son update 12345 -b HEAD~2 --per-commit --shelve # no record: the last two commits
|
|
555
675
|
```
|
|
556
676
|
|
|
557
677
|
### Keeping the changelist in sync with git
|
|
@@ -577,14 +697,16 @@ are left out of it.
|
|
|
577
697
|
|
|
578
698
|
### Review Command
|
|
579
699
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
700
|
+
Create a Swarm review with one shelf per commit. `review` is short for `git p4son new --review --per-commit`, taking the
|
|
701
|
+
same arguments apart from `--review`, `--per-commit`, `--shelve`, `--no-edit` and `--no-alias`. It checks out the first
|
|
702
|
+
commit since the base branch and runs `git p4son new --review` on it, then checks out each later commit and runs
|
|
703
|
+
`git p4son update --shelve`, and finally returns to where you started. Every step but the last sleeps 5 seconds to give
|
|
704
|
+
Perforce/Swarm time to process the shelf. The commits are reviewed where they are: to review them on top of the latest
|
|
705
|
+
`main`, rebase first. Like `new`, it needs a clean git workspace, untracked files included, and checks it even with
|
|
706
|
+
`--dry-run`.
|
|
584
707
|
|
|
585
708
|
```sh
|
|
586
|
-
git p4son review [alias] [-m <message> | -F <file>] [--
|
|
587
|
-
[--no-commit-list] [--no-edit-todo]
|
|
709
|
+
git p4son review -b BASE_BRANCH [alias] [-m <message> | -F <file>] [--force] [--dry-run] [--no-commit-list]
|
|
588
710
|
```
|
|
589
711
|
|
|
590
712
|
**Arguments:**
|
|
@@ -594,48 +716,40 @@ git p4son review [alias] [-m <message> | -F <file>] [--base-branch BASE_BRANCH]
|
|
|
594
716
|
- `-m, --message MESSAGE`: Changelist description message. Defaults to the HEAD commit subject
|
|
595
717
|
- `-F, --file FILE`: Read the changelist description message from a file instead of `-m`. The message may span
|
|
596
718
|
multiple lines
|
|
597
|
-
- `-b, --base-branch BASE_BRANCH`:
|
|
719
|
+
- `-b, --base-branch BASE_BRANCH`: Required. The base the change starts from, to find commits since: a branch or
|
|
720
|
+
bookmark, or a commit exactly one points at, which the alias records as for [`new`](#new-command)
|
|
598
721
|
- `-f, --force`: Overwrite an existing alias file
|
|
599
|
-
- `-n, --dry-run`: Print the
|
|
722
|
+
- `-n, --dry-run`: Print the steps, one per commit, without running them. Ends with `Dry run, nothing changed`
|
|
600
723
|
- `--no-commit-list`: Leave the enumerated commit list out of the changelist description. Passed on to `new` and
|
|
601
|
-
each `update`
|
|
602
|
-
- `--no-edit-todo`: Accept the generated rebase todo as is and start the rebase without opening an editor. No
|
|
603
|
-
editor needs to be configured. Useful for scripts and AI agents, which can check the todo with `--dry-run` first
|
|
724
|
+
each `update` step
|
|
604
725
|
|
|
605
|
-
|
|
726
|
+
A dry run prints the plan like this, with the base resolved to the commit every step uses; the message, which only
|
|
727
|
+
the first step gets, is printed below it:
|
|
606
728
|
|
|
607
729
|
```
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
exec git p4son update my-feature --shelve --sleep 5
|
|
612
|
-
pick ghi9012 Third commit
|
|
613
|
-
exec git p4son update my-feature --shelve
|
|
730
|
+
abc1234 First commit: git p4son new my-feature --review -b 5f1d0e9c2a7b4e8d9c0b1a2f3e4d5c6b7a8f9e0d
|
|
731
|
+
def5678 Second commit: git p4son update my-feature --shelve -b 5f1d0e9c2a7b4e8d9c0b1a2f3e4d5c6b7a8f9e0d
|
|
732
|
+
ghi9012 Third commit: git p4son update my-feature --shelve -b 5f1d0e9c2a7b4e8d9c0b1a2f3e4d5c6b7a8f9e0d
|
|
614
733
|
```
|
|
615
734
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
If the rebase fails mid-way, fix the issue, re-run the failed `git p4son` command (git does not re-run a failed
|
|
621
|
-
`exec` line), and run `git rebase --continue`.
|
|
735
|
+
If a step fails, `review` returns to where you started and names the step and commit that failed. Once the first
|
|
736
|
+
step has created the changelist, the error also says how to finish: after fixing the problem, run the
|
|
737
|
+
`git p4son update my-feature --shelve --per-commit -b <commit>` it prints, which resumes after the last commit that
|
|
738
|
+
worked.
|
|
622
739
|
|
|
623
740
|
**Examples:**
|
|
624
741
|
```sh
|
|
625
742
|
# Review all commits since main (alias defaults to branch name)
|
|
626
743
|
git p4son review -m "Add my feature" -b main
|
|
627
744
|
|
|
628
|
-
# Review
|
|
629
|
-
git p4son review -m "Fix bug"
|
|
745
|
+
# Review a branch's only commit: HEAD~1 is main's commit, so the alias records main
|
|
746
|
+
git p4son review -m "Fix bug" -b HEAD~1
|
|
630
747
|
|
|
631
|
-
# Preview the
|
|
748
|
+
# Preview the steps without running them
|
|
632
749
|
git p4son review -m "Add my feature" -b main --dry-run
|
|
633
750
|
|
|
634
751
|
# Take a multi-line description from a file
|
|
635
752
|
git p4son review -F description.txt -b main
|
|
636
|
-
|
|
637
|
-
# Run the rebase without reviewing the todo in an editor
|
|
638
|
-
git p4son review -m "Add my feature" -b main --no-edit-todo
|
|
639
753
|
```
|
|
640
754
|
|
|
641
755
|
### List-Changes Command
|
|
@@ -643,16 +757,19 @@ git p4son review -m "Add my feature" -b main --no-edit-todo
|
|
|
643
757
|
List commit subjects since a base branch in chronological order (oldest first):
|
|
644
758
|
|
|
645
759
|
```sh
|
|
646
|
-
git p4son list-changes [--base-branch BASE_BRANCH]
|
|
760
|
+
git p4son list-changes [--base-branch BASE_BRANCH] [--porcelain]
|
|
647
761
|
```
|
|
648
762
|
|
|
649
763
|
**Options:**
|
|
650
764
|
- `-b, --base-branch BASE_BRANCH`: Base branch to compare against. Default is `HEAD~1`.
|
|
765
|
+
- `--porcelain`: Print only the numbered list, and nothing when there are no changes, for scripts and agents. Errors
|
|
766
|
+
still go to stderr.
|
|
651
767
|
|
|
652
768
|
**Examples:**
|
|
653
769
|
```sh
|
|
654
770
|
git p4son list-changes
|
|
655
771
|
git p4son list-changes --base-branch main
|
|
772
|
+
git p4son list-changes --base-branch main --porcelain
|
|
656
773
|
```
|
|
657
774
|
|
|
658
775
|
This command is useful for generating changelist descriptions by listing all commit messages since the base branch,
|
|
@@ -660,7 +777,12 @@ numbered sequentially.
|
|
|
660
777
|
|
|
661
778
|
### Alias Command
|
|
662
779
|
|
|
663
|
-
Manage changelist aliases stored
|
|
780
|
+
Manage changelist aliases, stored one per file as `.git-p4son/aliases/<alias>.toml` (`changelist = 12345`, and
|
|
781
|
+
with the jj backend `change = "<change ID>"`, the [jj change](#jujutsu-jj) it was made for). An alias that `new` or
|
|
782
|
+
`review` saved also records the changelist's base and the commits since it it includes, which
|
|
783
|
+
[`update`](#update-command) goes on from: `base`, `base_commit` and `included`, a list of the commits' identities.
|
|
784
|
+
Aliases saved by older versions in `.git-p4son/changelists/` keep working, and move to `.git-p4son/aliases/` when
|
|
785
|
+
written, or all at once with `alias clean`.
|
|
664
786
|
|
|
665
787
|
#### alias list
|
|
666
788
|
|
|
@@ -748,7 +870,8 @@ Clean up changelist aliases:
|
|
|
748
870
|
git p4son alias clean
|
|
749
871
|
```
|
|
750
872
|
|
|
751
|
-
|
|
873
|
+
It first moves any aliases still in `.git-p4son/changelists/` to `.git-p4son/aliases/`, then lists all aliases and
|
|
874
|
+
asks how to proceed:
|
|
752
875
|
- `a` (all): Delete all aliases
|
|
753
876
|
- `i` (interactive): Review each alias one by one
|
|
754
877
|
- `q` (quit): Exit without deleting anything
|
|
@@ -842,7 +965,8 @@ at defined times during git-p4son operations. Scripts get run in filename (lexic
|
|
|
842
965
|
order.
|
|
843
966
|
|
|
844
967
|
The hook process CWD is the directory where git-p4son was invoked, and `GIT_P4SON_REPO_ROOT_DIR` is
|
|
845
|
-
set to the git-p4son repository root.
|
|
968
|
+
set to the git-p4son repository root. `GIT_P4SON_BACKEND` is `git` or `jj`, the [backend](#choosing-the-backend)
|
|
969
|
+
the command runs with.
|
|
846
970
|
|
|
847
971
|
On Windows, `.ps1`, `.nu`, `.sh`, and `.py` files are run with
|
|
848
972
|
`powershell.exe -NoProfile -ExecutionPolicy Bypass -File`, `nu.exe`, `bash.exe`, and `python.exe` respectively.
|
|
@@ -868,6 +992,208 @@ before the first sync.
|
|
|
868
992
|
After a successful `git-p4son sync` that actually performs sync work, git-p4son runs executable hooks from
|
|
869
993
|
`.git-p4son/hooks/post-sync/`. They don't run when the workspace is already at the requested changelist.
|
|
870
994
|
|
|
995
|
+
## Jujutsu (jj)
|
|
996
|
+
|
|
997
|
+
git-p4son detects a jj workspace colocated with the git repository, which needs jj 0.41 or newer. CI tests both
|
|
998
|
+
0.41 and the latest jj release, and the minimum only rises with a note in the CHANGELOG. Separate jj workspaces,
|
|
999
|
+
sparse working copies, and conflicted or divergent changes are not supported. Without a `.jj` folder, nothing
|
|
1000
|
+
changes.
|
|
1001
|
+
|
|
1002
|
+
### The jj p4son alias
|
|
1003
|
+
|
|
1004
|
+
jj has no external subcommands, but an alias can run git-p4son, so `jj p4son sync` runs `git p4son sync`. Add it
|
|
1005
|
+
once per machine to jj's user config, or let `init` offer it. From jj 0.42, an alias can carry a doc, which jj's
|
|
1006
|
+
shell completion shows next to `p4son`:
|
|
1007
|
+
|
|
1008
|
+
```sh
|
|
1009
|
+
jj config set --user aliases.p4son '{ definition = ["util", "exec", "--", "git-p4son"], doc = "Run git-p4son" }'
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
With jj 0.41, set `aliases.p4son` to the list alone, `'["util", "exec", "--", "git-p4son"]'`. `init` writes
|
|
1013
|
+
whichever form the installed jj supports.
|
|
1014
|
+
|
|
1015
|
+
`jj util exec` neither locks nor snapshots, so `jj p4son` behaves exactly as `git p4son`, and git-p4son's messages
|
|
1016
|
+
keep saying `git p4son`. Run it from inside the workspace: `jj -R other-workspace p4son` would still run in the
|
|
1017
|
+
current directory, so git-p4son refuses with "Run jj p4son from inside the workspace; -R is not supported." Shell
|
|
1018
|
+
completion for `jj p4son` needs [a hook of its own](#jj-p4son).
|
|
1019
|
+
|
|
1020
|
+
### Choosing the backend
|
|
1021
|
+
|
|
1022
|
+
The backend is the tool git-p4son follows for the change, the base and the branch: git or jj. By default it is jj
|
|
1023
|
+
in a jj workspace and git otherwise. To choose, set `core.backend` in `.git-p4son/config.toml`, or put the global
|
|
1024
|
+
`--backend` flag before the command, which overrides the setting:
|
|
1025
|
+
|
|
1026
|
+
```toml
|
|
1027
|
+
[core]
|
|
1028
|
+
backend = "git" # "auto" (the default), "git" or "jj"
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
```sh
|
|
1032
|
+
git p4son --backend git new -b main
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
`jj` outside a jj workspace is an error. In a jj workspace, the jj backend refuses to run when jj is missing or
|
|
1036
|
+
older than 0.41, and points to `--backend git`. The git backend needs no jj, and still holds jj's working-copy
|
|
1037
|
+
lock, which jj 0.41 or newer honours, so jj cannot snapshot halfway through a command.
|
|
1038
|
+
|
|
1039
|
+
With the jj backend in a jj workspace:
|
|
1040
|
+
|
|
1041
|
+
- `new`, `update` and `list-changes` work on the jj working change `@`. When `@` is empty, has no description or
|
|
1042
|
+
bookmark and has one parent, they work on that parent instead, so a fresh working change above a feature still
|
|
1043
|
+
refers to the feature.
|
|
1044
|
+
- `new` records the change's ID in the alias it saves, so later commands find the alias by change, whatever the
|
|
1045
|
+
change's bookmarks or description have become since. A new alias is named after the one local bookmark at the
|
|
1046
|
+
change, with `/` replaced by `-`, or, with no bookmark or several, after the first 8 letters of its change ID.
|
|
1047
|
+
- An alias records one change, and a change one alias: `new` refuses a change another alias records, naming it, and
|
|
1048
|
+
`--force` moves the record to the new alias. `alias new` records no change. `alias list` shows each recorded change,
|
|
1049
|
+
marked `(gone)` once jj no longer has it.
|
|
1050
|
+
- The default message is the first line of the change's description. Use `jj describe`, `-m` or `-F`.
|
|
1051
|
+
- `-b/--base-branch` takes a jj revision that resolves to one change, such as a bookmark, change ID or commit ID.
|
|
1052
|
+
Where it has a default, it's the change's parent rather than git's `HEAD~1`. `new` and `review` record it as a
|
|
1053
|
+
bookmark, so it has to name one, or resolve to a commit exactly one points at.
|
|
1054
|
+
- `new` and `update` use jj's snapshot of the working copy, check that it did not change while git-p4son took the
|
|
1055
|
+
lock, and refuse files jj left untracked. You do not need a separate committed change before opening files in
|
|
1056
|
+
Perforce. Before a Perforce revert overwrites a file, git-p4son saves the working file and puts it back
|
|
1057
|
+
afterwards, keeping its bytes, line endings and permissions instead of taking git's index version.
|
|
1058
|
+
- `init` holds jj's working-copy lock while it sets up the git repository. It also offers to colocate jj and to
|
|
1059
|
+
add the `jj p4son` alias, see [Init Command](#init-command).
|
|
1060
|
+
|
|
1061
|
+
For example:
|
|
1062
|
+
|
|
1063
|
+
```sh
|
|
1064
|
+
jj git init --colocate # Add jj to an existing git-p4son repository (see Line endings), or answer yes in init
|
|
1065
|
+
jj p4son sync # From any change: syncs main, then rebases your changes onto it
|
|
1066
|
+
|
|
1067
|
+
jj new main -m "Fix login"
|
|
1068
|
+
# Edit files
|
|
1069
|
+
jj bookmark create fix-login
|
|
1070
|
+
jj p4son new -b main --review
|
|
1071
|
+
# Edit more files
|
|
1072
|
+
jj p4son update -b main --shelve
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
### Syncing a bookmark
|
|
1076
|
+
|
|
1077
|
+
`sync` works from any change, as with git. It moves the sync bookmark, `[sync] branch` or `--branch`, defaulting
|
|
1078
|
+
to `main`, to each sync commit:
|
|
1079
|
+
|
|
1080
|
+
1. It puts the bookmark's files on disk. Your working change keeps its content in jj, which snapshotted it first.
|
|
1081
|
+
2. It syncs and commits, then releases jj's lock.
|
|
1082
|
+
3. It rebases the changes you started from onto the moved bookmark, as `jj rebase -b <your change> -d main`, and
|
|
1083
|
+
lists any change that got conflicts, which jj records rather than stopping on.
|
|
1084
|
+
4. It returns you to where you started: `jj edit` on the change you were editing, or `jj new` above it.
|
|
1085
|
+
|
|
1086
|
+
From the sync bookmark itself, nothing is rebased. `--no-rebase` skips the rebase and still returns you.
|
|
1087
|
+
|
|
1088
|
+
`sync` refuses when the sync bookmark points at the working change itself, which a sync would make part of the
|
|
1089
|
+
bookmark's history. Move the bookmark back with `jj bookmark set main -r @- --allow-backwards`, or, to keep the edits
|
|
1090
|
+
as a change on it, run `jj describe` and `jj new`.
|
|
1091
|
+
|
|
1092
|
+
You stay on the sync bookmark when:
|
|
1093
|
+
|
|
1094
|
+
- local changes were merged back: they are in a new working change on it, for you to review, and your changes are
|
|
1095
|
+
still rebased
|
|
1096
|
+
- a sync fails partway: jj's next command puts a new working change there, holding the files as Perforce left them,
|
|
1097
|
+
and nothing is rebased
|
|
1098
|
+
- the rebase fails: sync reports it with the `jj rebase` command to run and a non-zero exit code, and the sync is
|
|
1099
|
+
not undone
|
|
1100
|
+
|
|
1101
|
+
A failing pre-sync hook, or anything else before the first sync, puts your working change's files back.
|
|
1102
|
+
|
|
1103
|
+
`sync` still stages and commits with git, including git attributes and filters, and sets `core.autocrlf` to match
|
|
1104
|
+
jj's line ending conversion.
|
|
1105
|
+
|
|
1106
|
+
### Line endings
|
|
1107
|
+
|
|
1108
|
+
jj writes the working files by its `working-copy.eol-conversion`, and git by its `core.autocrlf`. When the two
|
|
1109
|
+
disagree, jj and git see different line endings, and jj fills changes with line ending edits. Set them to go
|
|
1110
|
+
together:
|
|
1111
|
+
|
|
1112
|
+
| git's `core.autocrlf` | jj's `working-copy.eol-conversion` |
|
|
1113
|
+
| --- | --- |
|
|
1114
|
+
| `false`, the default | `none`, the default |
|
|
1115
|
+
| `true`, the default in Git for Windows | `input-output` |
|
|
1116
|
+
| `input` | `input` |
|
|
1117
|
+
|
|
1118
|
+
On the jj backend, git-p4son warns when they disagree, and names the jj setting that matches git, for example
|
|
1119
|
+
`jj config set --repo working-copy.eol-conversion input-output`. The check reads only `core.autocrlf`: `text` and
|
|
1120
|
+
`eol` attributes in a `.gitattributes` override it in git, and jj doesn't read them.
|
|
1121
|
+
|
|
1122
|
+
Set it before jj's first snapshot, as `jj git init --colocate` takes one. Once jj has recorded the files with the
|
|
1123
|
+
wrong line endings, a later setting doesn't fix them, as jj only reads the files again when they change. `init`
|
|
1124
|
+
colocates with the matching setting, and to colocate by hand, pass it to the init too:
|
|
1125
|
+
|
|
1126
|
+
```sh
|
|
1127
|
+
jj --config working-copy.eol-conversion=input-output git init --colocate
|
|
1128
|
+
jj config set --repo working-copy.eol-conversion input-output
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
If you colocated without it, and jj shows every text file as changed, colocate again before doing anything else in
|
|
1132
|
+
jj. Don't `jj restore` that change: it holds every file the first snapshot added, and restoring it deletes them from
|
|
1133
|
+
disk, including your untracked work. Colocating again leaves the files alone:
|
|
1134
|
+
|
|
1135
|
+
```sh
|
|
1136
|
+
rm -rf .jj # Remove-Item -Recurse -Force .jj in PowerShell
|
|
1137
|
+
git reset # Drops the entries jj added to git's index
|
|
1138
|
+
jj --config working-copy.eol-conversion=input-output git init --colocate
|
|
1139
|
+
jj config set --repo working-copy.eol-conversion input-output
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
If git ignores folders only by matching without case, see [Ignored files](#ignored-files): `git p4son init`
|
|
1143
|
+
colocates with both settings.
|
|
1144
|
+
|
|
1145
|
+
### Ignored files
|
|
1146
|
+
|
|
1147
|
+
git matches `.gitignore` patterns without case when `core.ignorecase` is true, the default on Windows and macOS. jj
|
|
1148
|
+
always matches them with case, so it would track a `Thirdparty/` folder that git ignores through `ThirdParty/`.
|
|
1149
|
+
|
|
1150
|
+
To keep jj from tracking them, git-p4son leaves each such folder, or file, out of jj's `snapshot.auto-track` for the
|
|
1151
|
+
repository, building on any value you have, for example `(all()) ~ root:Some/Plugin/Source/Thirdparty`. That's
|
|
1152
|
+
jj's own setting, so it works whatever `.gitignore` re-includes with `!`, which would outrank `.git/info/exclude`,
|
|
1153
|
+
and it leaves git alone. `jj status` then lists the folders under "Untracked paths". As the repository's value holds
|
|
1154
|
+
yours, a later change to your user-level `snapshot.auto-track` doesn't reach the repository.
|
|
1155
|
+
|
|
1156
|
+
git-p4son does so when `init` colocates, passing the setting to `jj git init`, as jj snapshots straight away, and in
|
|
1157
|
+
the steps it lists for colocating a repository it creates by hand. It also does so at the end of each sync on the jj
|
|
1158
|
+
backend, as a sync can bring in new folders. To let jj track such a folder again, remove its `root:"..."` from
|
|
1159
|
+
`snapshot.auto-track`, with `jj config edit --repo`.
|
|
1160
|
+
|
|
1161
|
+
If jj tracks such files anyway, for example in a workspace colocated before git-p4son did this, git-p4son warns about
|
|
1162
|
+
the ones the change you're working on adds, unless it's a commit in the sync branch's history, which git made. The
|
|
1163
|
+
warning lists the `jj config set` that leaves them out and the `jj file untrack` command that stops tracking them,
|
|
1164
|
+
which leaves the files on disk. Both are quoted to paste into cmd, PowerShell or a POSIX shell alike. They name a
|
|
1165
|
+
folder only when git tracks nothing else in it, so files git tracks stay tracked. Files you track on purpose, with
|
|
1166
|
+
`jj file track --include-ignored`, are left alone.
|
|
1167
|
+
|
|
1168
|
+
### Locking, and the git workflow
|
|
1169
|
+
|
|
1170
|
+
git-p4son holds jj's working-copy lock while commands run, including sync hooks and temporary Perforce reverts,
|
|
1171
|
+
so other jj processes cannot snapshot files halfway through. A busy lock stops the command. Queries during the
|
|
1172
|
+
command use a pinned jj operation without snapshotting.
|
|
1173
|
+
|
|
1174
|
+
jj's first snapshot and final reconciliation happen outside the lock, and so do sync's rebase and return, so
|
|
1175
|
+
another jj command can import the finished git changes before git-p4son does: this is not one atomic jj
|
|
1176
|
+
transaction. `--verbose` logs the jj operation git-p4son pinned at the start. The lock does not keep out
|
|
1177
|
+
editors, git commands or other jj workspaces. If a command fails, look at the workspace before continuing: the
|
|
1178
|
+
lock is released, but Perforce operations that completed are not undone.
|
|
1179
|
+
|
|
1180
|
+
Hooks must not run ordinary jj commands, which would wait for the lock their caller holds. Read-only queries such
|
|
1181
|
+
as `jj --at-op=@ log` avoid snapshotting and the git import. A hook that runs git-p4son itself needs
|
|
1182
|
+
`--backend git`, which reuses the caller's lock.
|
|
1183
|
+
|
|
1184
|
+
`review`, `new --per-commit` and `update --per-commit` run once per commit since the base, up to the jj change, as they
|
|
1185
|
+
do in git. Under jj's lock, each step puts its commit's files on disk with git, and the working change's files go back
|
|
1186
|
+
at the end, also when a step fails, so jj sees no change. No jj command runs, and untracked and ignored files are left
|
|
1187
|
+
alone. They refuse to start if files changed after jj's snapshot, as the checkouts would overwrite them:
|
|
1188
|
+
|
|
1189
|
+
```sh
|
|
1190
|
+
git p4son review -b main
|
|
1191
|
+
git p4son update --per-commit --shelve -b main
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
To use the git workflow on purpose, put `--backend git` **before** the command. This uses git branches, `HEAD` and
|
|
1195
|
+
git's clean-workspace check.
|
|
1196
|
+
|
|
871
1197
|
## Claude Code Skill
|
|
872
1198
|
|
|
873
1199
|
git-p4son ships a skill for Claude Code that teaches it how git-p4son is meant to be used: keeping `main` in sync
|
|
@@ -930,3 +1256,24 @@ Add the following to your PowerShell profile (`$PROFILE`):
|
|
|
930
1256
|
|
|
931
1257
|
All three enable completion for `git p4son <TAB>` and `git-p4son <TAB>`.
|
|
932
1258
|
|
|
1259
|
+
### jj p4son
|
|
1260
|
+
|
|
1261
|
+
jj completes an alias's arguments as file paths, so `jj p4son <TAB>` needs a hook of its own. It completes the words
|
|
1262
|
+
after `p4son` as `git p4son` does, skipping jj's global options such as `-R` or `--color` before it, and hands every
|
|
1263
|
+
other `jj` completion to jj's own. Load it after jj's completion; the PowerShell hook needs PowerShell 7 (`pwsh`):
|
|
1264
|
+
|
|
1265
|
+
```bash
|
|
1266
|
+
source $(git-p4son completion bash --jj) # ~/.bashrc
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
```zsh
|
|
1270
|
+
source $(git-p4son completion zsh --jj) # ~/.zshrc, after compinit
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
```powershell
|
|
1274
|
+
. $(git-p4son completion powershell --jj) # $PROFILE
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1277
|
+
Each loads the `git p4son` completion for its shell too. If you named the alias something other than `p4son`, set
|
|
1278
|
+
`GIT_P4SON_JJ_ALIAS` to its name.
|
|
1279
|
+
|