git-p4son 0.7.0__tar.gz → 0.9.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.7.0 → git_p4son-0.9.0}/PKG-INFO +507 -409
- {git_p4son-0.7.0 → git_p4son-0.9.0}/README.md +505 -407
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/__init__.py +1 -1
- git_p4son-0.9.0/git_p4son/alias.py +186 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/backend.py +22 -3
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/changelist_store.py +85 -17
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/cli.py +60 -19
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/common.py +17 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/complete.py +23 -3
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/git.py +4 -2
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/git_backend.py +3 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/hooks.py +3 -54
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/included.py +26 -7
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/jj.py +26 -5
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/jj_backend.py +15 -6
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/lib.py +128 -70
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/log.py +6 -1
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/new.py +48 -11
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/per_commit.py +1 -3
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/perforce.py +111 -17
- git_p4son-0.9.0/git_p4son/review_tools.py +168 -0
- git_p4son-0.9.0/git_p4son/scripts.py +64 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/skill/git-p4son.md +27 -12
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/sync.py +2 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/update.py +34 -12
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son.egg-info/PKG-INFO +507 -409
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son.egg-info/SOURCES.txt +5 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/pyproject.toml +2 -2
- git_p4son-0.9.0/tests/test_alias.py +364 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_changelist_store.py +122 -2
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_common.py +22 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_complete.py +26 -1
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_git.py +1 -1
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_hooks.py +9 -76
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_jj.py +219 -4
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_lib.py +69 -104
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_log.py +16 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_new.py +270 -4
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_perforce.py +78 -1
- git_p4son-0.9.0/tests/test_renames.py +144 -0
- git_p4son-0.9.0/tests/test_review_tools.py +216 -0
- git_p4son-0.9.0/tests/test_scripts.py +89 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_sync.py +3 -2
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_update.py +121 -5
- git_p4son-0.7.0/git_p4son/alias.py +0 -147
- git_p4son-0.7.0/tests/test_alias.py +0 -237
- {git_p4son-0.7.0 → git_p4son-0.9.0}/LICENSE +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/__main__.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/completions/_git-p4son +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/completions/git-p4son-jj.bash +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/completions/git-p4son-jj.ps1 +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/completions/git-p4son-jj.zsh +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/completions/git-p4son.bash +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/completions/git-p4son.ps1 +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/config.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/depot.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/description.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/init.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/jj_lock.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/list_changes.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/processes.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/skill/SKILL.md +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/skill.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/sync_branch.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/sync_merge.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/sync_split_users.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/toml_writer.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/words.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son/writable.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son.egg-info/dependency_links.txt +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son.egg-info/entry_points.txt +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/git_p4son.egg-info/top_level.txt +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/setup.cfg +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_catch_up.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_cli.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_completion_scripts.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_config.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_depot.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_description.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_git_backend.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_init.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_isolation.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_list_changes.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_per_commit.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_processes.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_skill.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_sync_merge.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_sync_split_users.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_toml_writer.py +0 -0
- {git_p4son-0.7.0 → git_p4son-0.9.0}/tests/test_writable.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-p4son
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
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
|
|
@@ -8,7 +8,7 @@ Project-URL: Homepage, https://github.com/neoboid/git-p4son
|
|
|
8
8
|
Project-URL: Repository, https://github.com/neoboid/git-p4son
|
|
9
9
|
Project-URL: Issues, https://github.com/neoboid/git-p4son/issues
|
|
10
10
|
Project-URL: Changelog, https://github.com/neoboid/git-p4son/blob/main/CHANGELOG.md
|
|
11
|
-
Keywords: perforce,git,version-control,sync
|
|
11
|
+
Keywords: perforce,git,jj,jujutsu,version-control,sync
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -25,31 +25,22 @@ Dynamic: license-file
|
|
|
25
25
|
|
|
26
26
|
`git-p4son` lets you work in a Perforce workspace with a local git repository, or a colocated
|
|
27
27
|
[Jujutsu (jj)](#jujutsu-jj) one, so you can use the familiar local development flow even though your project uses
|
|
28
|
-
Perforce
|
|
28
|
+
Perforce.
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
on feature branches
|
|
32
|
-
sync from for you.
|
|
30
|
+
The core idea is a local `main` branch kept in sync with the Perforce workspace. Each sync commits the changes since
|
|
31
|
+
the last one. You work on feature branches based on `main`, and rebase them onto it after a sync.
|
|
33
32
|
|
|
34
|
-
When your
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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.
|
|
40
|
-
|
|
41
|
-
## On big workspaces
|
|
42
|
-
Sometimes git struggles to keep entire perforce workspaces in the repo, like when working
|
|
43
|
-
on a Unreal Engine game with all source code in the workspace. If so, it helps to edit
|
|
44
|
-
`.gitignore` and include only the subdirectories in which you work, the rest of the files
|
|
45
|
-
will still be managed by perforce of course.
|
|
33
|
+
When your feature is ready, `git-p4son` creates a changelist from the commits on your branch. It can also create a
|
|
34
|
+
review, in Swarm or another review tool, with each commit as its own patch, so reviewers see the changes in the order
|
|
35
|
+
you made them, like the commits of a pull request on GitHub. To address feedback, commit more locally, and
|
|
36
|
+
`git-p4son` adds the new commits to the changelist and the review.
|
|
46
37
|
|
|
47
38
|
## Usage Example
|
|
48
39
|
|
|
49
40
|
Here's a typical workflow when developing a feature using `git-p4son`:
|
|
50
41
|
|
|
51
42
|
```sh
|
|
52
|
-
# Sync main with latest changes from
|
|
43
|
+
# Sync main with the latest changes from Perforce
|
|
53
44
|
git checkout main
|
|
54
45
|
git p4son sync
|
|
55
46
|
|
|
@@ -60,11 +51,9 @@ git checkout -b my-fancy-feature
|
|
|
60
51
|
git add .
|
|
61
52
|
git commit -m "Feature part1"
|
|
62
53
|
|
|
63
|
-
# Sync
|
|
54
|
+
# Sync again, and rebase your branch onto main
|
|
64
55
|
git checkout main
|
|
65
56
|
git p4son sync
|
|
66
|
-
|
|
67
|
-
# Rebase your changes on main
|
|
68
57
|
git checkout my-fancy-feature
|
|
69
58
|
git rebase main
|
|
70
59
|
|
|
@@ -72,32 +61,19 @@ git rebase main
|
|
|
72
61
|
git add .
|
|
73
62
|
git commit -m "Feature part2"
|
|
74
63
|
|
|
75
|
-
# Create a
|
|
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.
|
|
78
|
-
# An alias called "my-fancy-feature" (derived from the branch name) is
|
|
79
|
-
# saved so you can refer to this CL by name in follow-up commands.
|
|
64
|
+
# Create a review with a patch per commit, under an alias named after the branch
|
|
80
65
|
git p4son review -m "My fancy feature" -b main
|
|
81
66
|
|
|
82
|
-
#
|
|
67
|
+
# Address review feedback, then add the new commit to the changelist and the review
|
|
83
68
|
git add .
|
|
84
69
|
git commit -m "Address review feedback"
|
|
85
|
-
|
|
86
|
-
# Update the changelist with latest commit, re-open files, and re-shelve.
|
|
87
|
-
# The changelist is looked up by branch name automatically.
|
|
88
70
|
git p4son update --shelve
|
|
89
71
|
|
|
90
|
-
# After approval, submit in
|
|
91
|
-
|
|
92
|
-
# Sync to the latest changelist from perforce
|
|
72
|
+
# After approval, submit in P4V, then sync and clean up
|
|
93
73
|
git checkout main
|
|
94
74
|
git p4son sync
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
git branch -D my-fancy-feature
|
|
98
|
-
|
|
99
|
-
# Remove changelist alias for the branch
|
|
100
|
-
git p4son alias delete my-fancy-feature
|
|
75
|
+
git branch -D my-fancy-feature # -D, as the submitted change has other commit hashes
|
|
76
|
+
git p4son alias clean # deletes the aliases of submitted changelists
|
|
101
77
|
|
|
102
78
|
# Start working on the next feature
|
|
103
79
|
git checkout -b my-next-fancy-feature
|
|
@@ -119,8 +95,7 @@ jj p4son sync
|
|
|
119
95
|
jj new -m "Feature part2"
|
|
120
96
|
jj bookmark create my-fancy-feature
|
|
121
97
|
|
|
122
|
-
# Create a
|
|
123
|
-
# The alias is named after the bookmark and records the jj change.
|
|
98
|
+
# Create a review with a patch per change, under an alias named after the bookmark
|
|
124
99
|
jj p4son review -m "My fancy feature" -b main
|
|
125
100
|
|
|
126
101
|
# After review feedback, add a change and move the bookmark to it
|
|
@@ -128,11 +103,11 @@ jj new -m "Address review feedback"
|
|
|
128
103
|
jj bookmark set my-fancy-feature -r @
|
|
129
104
|
jj p4son update --shelve
|
|
130
105
|
|
|
131
|
-
# After approval, submit in
|
|
132
|
-
#
|
|
106
|
+
# After approval, submit in P4V, abandon the submitted changes, which deletes the
|
|
107
|
+
# bookmark too, then sync and clean up
|
|
133
108
|
jj abandon main..my-fancy-feature
|
|
134
|
-
jj p4son alias delete my-fancy-feature
|
|
135
109
|
jj p4son sync
|
|
110
|
+
jj p4son alias clean
|
|
136
111
|
|
|
137
112
|
# Start working on the next feature
|
|
138
113
|
jj new main -m "Next fancy feature"
|
|
@@ -141,13 +116,30 @@ jj new main -m "Next fancy feature"
|
|
|
141
116
|
`sync` only rebases the change you sync from, and the stack above it. Bring other bookmarks up to date with
|
|
142
117
|
`jj rebase -b <bookmark> -d main`.
|
|
143
118
|
|
|
119
|
+
## Contents
|
|
120
|
+
|
|
121
|
+
- [Installation](#installation)
|
|
122
|
+
- [Setup](#setup)
|
|
123
|
+
- [Commands](#commands): [init](#init-command), [sync](#sync-command), [sync-split-users](#sync-split-users-command),
|
|
124
|
+
[new](#new-command), [update](#update-command), [review](#review-command), [list-changes](#list-changes-command),
|
|
125
|
+
[alias](#alias-command), [writable](#writable-command), [completion](#completion-command), [skill](#skill-command)
|
|
126
|
+
- [Configuration](#configuration)
|
|
127
|
+
- [Review Tools](#review-tools)
|
|
128
|
+
- [Hooks](#hooks)
|
|
129
|
+
- [Jujutsu (jj)](#jujutsu-jj)
|
|
130
|
+
- [Claude Code Skill](#claude-code-skill)
|
|
131
|
+
- [Shell Completions](#shell-completions)
|
|
132
|
+
- [Development](#development)
|
|
133
|
+
|
|
144
134
|
## Installation
|
|
145
135
|
|
|
146
136
|
```sh
|
|
147
137
|
pip install git-p4son
|
|
148
138
|
```
|
|
149
139
|
|
|
150
|
-
Requires Python 3.11 or later.
|
|
140
|
+
Requires Python 3.11 or later. For tab completion in bash, zsh and PowerShell, see
|
|
141
|
+
[Shell Completions](#shell-completions). To let Claude Code drive git-p4son, see
|
|
142
|
+
[Claude Code Skill](#claude-code-skill).
|
|
151
143
|
|
|
152
144
|
### Updating
|
|
153
145
|
|
|
@@ -155,45 +147,6 @@ Requires Python 3.11 or later.
|
|
|
155
147
|
pip install --upgrade git-p4son
|
|
156
148
|
```
|
|
157
149
|
|
|
158
|
-
For tab completion (zsh and PowerShell), see [Shell Completions](#shell-completions). To let Claude Code drive
|
|
159
|
-
git-p4son, see [Claude Code Skill](#claude-code-skill).
|
|
160
|
-
|
|
161
|
-
## Development
|
|
162
|
-
|
|
163
|
-
To install from source in editable mode:
|
|
164
|
-
|
|
165
|
-
```sh
|
|
166
|
-
git clone https://github.com/neoboid/git-p4son.git
|
|
167
|
-
cd git-p4son
|
|
168
|
-
pip install -e .
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
The `-e` flag installs the package in "editable" mode, meaning changes to the code are immediately available
|
|
172
|
-
without reinstalling. This is also handy if you want to auto-update git-p4son whenever you pull from GitHub.
|
|
173
|
-
|
|
174
|
-
git-p4son only uses Python standard library modules - no additional packages are required.
|
|
175
|
-
|
|
176
|
-
Run the tests with `python -m pytest tests/` (`pip install pytest`). With `pytest-xdist` installed, add
|
|
177
|
-
`-n auto --maxprocesses 8` to run them in parallel, which is about three times faster.
|
|
178
|
-
|
|
179
|
-
### Git Hooks
|
|
180
|
-
|
|
181
|
-
The repository includes git hooks in the `hooks/` directory:
|
|
182
|
-
|
|
183
|
-
- **pre-commit** - verifies that staged Python files are formatted with `autopep8`. Install it with
|
|
184
|
-
`pip install autopep8`.
|
|
185
|
-
- **pre-push** - runs the test suite and blocks the push if any test fails. It needs `pytest` installed, and runs
|
|
186
|
-
the tests in parallel when `pytest-xdist` is too.
|
|
187
|
-
|
|
188
|
-
To activate the hooks, run:
|
|
189
|
-
|
|
190
|
-
```sh
|
|
191
|
-
scripts/setup-hooks.sh
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
This configures `core.hooksPath` so git uses the hooks from the repository. You only need to run this once after
|
|
195
|
-
cloning.
|
|
196
|
-
|
|
197
150
|
## Setup
|
|
198
151
|
|
|
199
152
|
These steps set up git-p4son in an existing Perforce workspace. You only need to do this once.
|
|
@@ -210,13 +163,13 @@ These steps set up git-p4son in an existing Perforce workspace. You only need to
|
|
|
210
163
|
cd /path/to/your/workspace # or a subdirectory of it
|
|
211
164
|
git p4son init
|
|
212
165
|
```
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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).
|
|
166
|
+
Answer its questions, starting with the depot root: the whole workspace or the subtree you're in. It then runs
|
|
167
|
+
`git init`, sets up `.gitignore` and makes a first commit holding only that. See [Init Command](#init-command) for
|
|
168
|
+
what it asks.
|
|
218
169
|
|
|
219
|
-
3. **Review `.gitignore`.** Edit the file to ensure build artifacts and other unwanted files are excluded.
|
|
170
|
+
3. **Review `.gitignore`.** Edit the file to ensure build artifacts and other unwanted files are excluded. In a big
|
|
171
|
+
workspace, such as an Unreal Engine game with all of the engine source in it, git can struggle to track
|
|
172
|
+
everything. Ignore all but the directories you work in; Perforce still manages the rest.
|
|
220
173
|
|
|
221
174
|
4. **Add and commit all files manually the first time**
|
|
222
175
|
```sh
|
|
@@ -233,94 +186,23 @@ These steps set up git-p4son in an existing Perforce workspace. You only need to
|
|
|
233
186
|
From here, branch off `main` for local development. See the [Usage Example](#usage-example) for a typical
|
|
234
187
|
workflow.
|
|
235
188
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
When you switch branches with `git checkout`, git removes the read-only flag on every file it writes. This means
|
|
239
|
-
that when you switch back to `main` for a sync, Perforce may refuse to overwrite those files because they are
|
|
240
|
-
writable. git-p4son handles these automatically by classifying each writable file:
|
|
241
|
-
|
|
242
|
-
**writable-unchanged** - The file on disk is identical to the last sync (only the read-only flag was removed
|
|
243
|
-
by git). This is the common case after switching branches. git-p4son detects this by comparing git blob IDs against
|
|
244
|
-
the last sync commit that touched the file, restores the read-only flag, and lets the sync overwrite the file.
|
|
245
|
-
|
|
246
|
-
**writable-changed** - The file on disk differs from the last sync. This happens when you manually edit a file
|
|
247
|
-
on `main` and commit it to git without submitting to Perforce. git-p4son lets the sync overwrite the file and
|
|
248
|
-
includes it in the sync commit (so the commit reflects pure Perforce state), then three-way merges your local
|
|
249
|
-
changes on top of the new Perforce content - similar to a `git rebase`. If the merge is clean, the result appears
|
|
250
|
-
as an unstaged change. If there are conflicts, standard conflict markers are inserted for you to resolve.
|
|
251
|
-
|
|
252
|
-
**added both locally and in Perforce** - A file you committed to git is also being added by Perforce (p4 has never
|
|
253
|
-
synced it to your workspace). There is no common baseline, so git-p4son merges the two versions against an empty
|
|
254
|
-
base: identical content merges cleanly, otherwise the file gets a single conflict block containing both full
|
|
255
|
-
versions for you to resolve.
|
|
256
|
-
|
|
257
|
-
**binary files** - Binary files that have local changes cannot be three-way merged. git-p4son restores your local
|
|
258
|
-
version to disk after the sync commit so it shows up in `git status` for you to handle manually.
|
|
259
|
-
|
|
260
|
-
**added locally, deleted upstream** - A file with local changes in git was deleted in Perforce. git-p4son lets the
|
|
261
|
-
delete stand and warns you - your version remains available in git history.
|
|
262
|
-
|
|
263
|
-
**deleted locally, added upstream** - A file you deleted from git was modified in Perforce. The Perforce version is
|
|
264
|
-
kept in the sync commit. You can delete it again if you want.
|
|
265
|
-
|
|
266
|
-
**ignored** - Files ignored by `.gitignore` are skipped with a warning. These are outside git's domain and should
|
|
267
|
-
be managed manually or via Perforce directly.
|
|
268
|
-
|
|
269
|
-
After syncing, git-p4son prints a summary of how each writable file was handled, and instructs you to review and
|
|
270
|
-
commit any files that need attention.
|
|
271
|
-
|
|
272
|
-
**Workspaces with `allwrite`** - When your client spec has the `allwrite` option, every file is writable by design,
|
|
273
|
-
so the read-only flag carries no information about local changes. git-p4son classifies files exactly as above (the
|
|
274
|
-
verdict comes from git, not from the flag), but leaves the write bit alone on files it finds unchanged: Perforce
|
|
275
|
-
compares digests before refusing to overwrite a writable file, and unchanged files pass that check. Only files with
|
|
276
|
-
local changes are made read-only for the duration of the sync, since those are the ones Perforce would otherwise
|
|
277
|
-
refuse to overwrite. The same digest check applies to git-ignored files: unchanged ones sync normally, and after the
|
|
278
|
-
sync git-p4son lists the ones Perforce skipped because they were modified locally.
|
|
279
|
-
|
|
280
|
-
**Writable mode** - With [writable mode](#writable-command) on, the files a sync touches are made writable again after
|
|
281
|
-
the sync if git tracks them. The sync itself works as described above, since the workspace is not `allwrite`.
|
|
282
|
-
|
|
283
|
-
## Configuration
|
|
284
|
-
|
|
285
|
-
git-p4son keeps its per-repository settings in `.git-p4son/config.toml`. `init`, `writable` and `sync-split-users`
|
|
286
|
-
write most of them; the rest you edit by hand.
|
|
287
|
-
|
|
288
|
-
- `[depot] root` (string, set by `init`): the depot path `sync` syncs, e.g. `//$(workspace)` or
|
|
289
|
-
`//$(workspace)/Engine`. See [Init Command](#init-command)
|
|
290
|
-
- `[core] writable` (`true` or `false`, default `false`): [writable mode](#writable-command), which keeps
|
|
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)
|
|
296
|
-
- `[sync] split-users` (list of strings, default empty): the users whose changelists `sync` gives a commit each;
|
|
297
|
-
`$(user)` stands for you. See [Split users](#split-users)
|
|
298
|
-
- `[sync] blocking-processes` (list of strings, default empty): processes that stop a sync while they run. See
|
|
299
|
-
[Blocking processes](#blocking-processes)
|
|
300
|
-
- `[hooks.extension-associations]` (table, Windows only): the command that runs a hook script, by file extension.
|
|
301
|
-
See [Hooks](#hooks)
|
|
302
|
-
|
|
303
|
-
For example:
|
|
304
|
-
|
|
305
|
-
```toml
|
|
306
|
-
[depot]
|
|
307
|
-
root = "//$(workspace)"
|
|
308
|
-
|
|
309
|
-
[core]
|
|
310
|
-
writable = true
|
|
311
|
-
|
|
312
|
-
[sync]
|
|
313
|
-
split-users = ["$(user)", "alice"]
|
|
314
|
-
blocking-processes = ["UnrealEditor"]
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
A value of the wrong type, such as `writable = "true"` or `split-users = "alice"`, or a file that is not valid TOML,
|
|
318
|
-
stops the command with an error naming the setting, so a typo is never silently ignored.
|
|
189
|
+
## Commands
|
|
319
190
|
|
|
320
|
-
|
|
191
|
+
git-p4son provides eleven commands:
|
|
321
192
|
|
|
322
|
-
|
|
323
|
-
|
|
193
|
+
| Command | What it does |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| [`init`](#init-command) | Set up a git repository in a Perforce workspace |
|
|
196
|
+
| [`sync`](#sync-command) | Sync the workspace from Perforce and commit the changes to `main` |
|
|
197
|
+
| [`sync-split-users`](#sync-split-users-command) | Show or edit the users whose changelists `sync` commits one by one |
|
|
198
|
+
| [`new`](#new-command) | Create a changelist from the commits on your branch, optionally with a review |
|
|
199
|
+
| [`update`](#update-command) | Add the newer commits to an existing changelist |
|
|
200
|
+
| [`review`](#review-command) | Create a review with one shelf per commit |
|
|
201
|
+
| [`list-changes`](#list-changes-command) | List the commit subjects since a base branch |
|
|
202
|
+
| [`alias`](#alias-command) | Manage the names that stand for changelist numbers |
|
|
203
|
+
| [`writable`](#writable-command) | Keep git-tracked files writable, without `p4 edit` first |
|
|
204
|
+
| [`completion`](#completion-command) | Print the path to a shell completion script |
|
|
205
|
+
| [`skill`](#skill-command) | Install or show the Claude Code skill |
|
|
324
206
|
|
|
325
207
|
To see help for any command, use `-h`:
|
|
326
208
|
|
|
@@ -339,48 +221,37 @@ Alternatively, call the executable directly: `git-p4son --help`.
|
|
|
339
221
|
|
|
340
222
|
### Init Command
|
|
341
223
|
|
|
342
|
-
|
|
224
|
+
Set up git-p4son in a Perforce workspace, from anywhere inside it:
|
|
343
225
|
|
|
344
226
|
```sh
|
|
345
227
|
git p4son init
|
|
346
228
|
```
|
|
347
229
|
|
|
348
|
-
|
|
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.
|
|
351
|
-
|
|
352
|
-
The depot root determines which part of the Perforce workspace git-p4son syncs. You can choose to sync the entire
|
|
353
|
-
workspace or just the directory's subtree where the git root is placed. The selection is saved in
|
|
354
|
-
`.git-p4son/config.toml` and used by all subsequent commands.
|
|
230
|
+
`init` checks that it runs in a Perforce workspace, then asks:
|
|
355
231
|
|
|
356
|
-
|
|
357
|
-
|
|
232
|
+
- **Depot root:** which part of the workspace git-p4son syncs, the whole workspace or the subtree the git root is in.
|
|
233
|
+
It's saved as `[depot] root` in `.git-p4son/config.toml`, with a `$(workspace)` placeholder for the workspace name,
|
|
234
|
+
e.g. `//$(workspace)/Engine`, so renaming the workspace doesn't break it. A concrete name works too.
|
|
235
|
+
- **Writable mode:** whether to turn on [writable mode](#writable-command), defaulting to the current setting. It only
|
|
236
|
+
saves the answer; run `git p4son writable apply` once your files are committed.
|
|
237
|
+
- **Split users:** whether to sync your own changelists one by one, as a [split user](#split-users), defaulting to the
|
|
238
|
+
current setting. Yes adds a `$(user)` entry and no removes it; other split users are left alone.
|
|
239
|
+
- **Claude Code skill:** if Claude Code is installed, whether to install the [skill](#claude-code-skill). An installed
|
|
240
|
+
skill is refreshed without asking.
|
|
241
|
+
- **jj:** with jj 0.41 or newer, whether to colocate jj and add the `jj p4son` alias, as described below.
|
|
358
242
|
|
|
359
|
-
|
|
360
|
-
`root = "//$(workspace)/Engine"`. git-p4son substitutes the live workspace name each time it runs, so renaming
|
|
361
|
-
the Perforce workspace does not break the config. You can still store a concrete name (e.g. `//my-workspace/Engine`)
|
|
362
|
-
by hand-editing `config.toml`; both forms work.
|
|
243
|
+
Then it sets up the repository:
|
|
363
244
|
|
|
364
|
-
|
|
365
|
-
-
|
|
366
|
-
-
|
|
367
|
-
|
|
245
|
+
- **`.gitignore`:** kept if it exists, else copied from `.p4ignore`, else created empty.
|
|
246
|
+
- **git:** `git init`, and a first commit holding only `.gitignore`.
|
|
247
|
+
- **Sync branch:** recorded as `[sync] branch`. In a repository it creates, that's the branch `HEAD` is on. In an
|
|
248
|
+
existing one, it's `main` if there is one, else the branch `HEAD` is on, else one you pick from the local branches.
|
|
249
|
+
A branch already set is kept.
|
|
368
250
|
|
|
369
|
-
|
|
370
|
-
|
|
251
|
+
It ends by listing the next steps. Nothing in `.git-p4son/` belongs in git: the folder has its own `.gitignore` that
|
|
252
|
+
ignores everything in it.
|
|
371
253
|
|
|
372
|
-
|
|
373
|
-
The default is the current setting. Yes adds a `$(user)` entry to the split users and no removes it; other split
|
|
374
|
-
users are left alone.
|
|
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
|
-
|
|
380
|
-
If Claude Code is installed, `init` offers to install the [Claude Code skill](#claude-code-skill). An
|
|
381
|
-
already installed skill is refreshed without asking.
|
|
382
|
-
|
|
383
|
-
With jj 0.41 or newer installed, `init` offers two things for [jj](#jujutsu-jj):
|
|
254
|
+
For [jj](#jujutsu-jj), `init` offers:
|
|
384
255
|
|
|
385
256
|
- **Colocating jj**, when the workspace has no `.jj` folder: "Use jj in this workspace too (colocated)?", default
|
|
386
257
|
no. On yes, in an existing repository it runs `jj git init --colocate` as its last step, so jj imports the branch
|
|
@@ -394,34 +265,19 @@ Running `init` again asks neither once they are done.
|
|
|
394
265
|
|
|
395
266
|
### Sync Command
|
|
396
267
|
|
|
397
|
-
Sync
|
|
268
|
+
Sync the workspace from Perforce and commit what changed onto the sync branch, `main` by default:
|
|
398
269
|
|
|
399
270
|
```sh
|
|
400
|
-
git p4son sync [changelist ...] [--branch BRANCH] [--force] [--dry-run] [--split-user NAME ...]
|
|
401
|
-
[--ignore-blocking-processes]
|
|
271
|
+
git p4son sync [changelist ...] [--branch BRANCH] [--no-rebase] [--force] [--dry-run] [--split-user NAME ...]
|
|
272
|
+
[--no-split] [--ignore-blocking-processes]
|
|
402
273
|
```
|
|
403
274
|
|
|
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
|
-
|
|
415
275
|
**Arguments:**
|
|
416
276
|
- `changelist` (optional): Changelist number, `last-synced` to re-sync the last synced changelist, or `head`
|
|
417
277
|
to sync to the latest changelist. Omit to sync to the latest changelist affecting the workspace. Several
|
|
418
278
|
strictly increasing changelist numbers may be given to sync each in sequence, producing one commit per
|
|
419
279
|
changelist. A trailing `head` may close out such a sequence to finish at the latest changelist.
|
|
420
280
|
|
|
421
|
-
`sync` requires clean git and Perforce workspaces: no uncommitted changes, untracked files included, and no
|
|
422
|
-
git-tracked files opened in Perforce. It checks them after any [blocking processes](#blocking-processes) and before
|
|
423
|
-
the [pre-sync hooks](#pre-sync-hook).
|
|
424
|
-
|
|
425
281
|
**Options:**
|
|
426
282
|
- `--branch BRANCH`: Commit onto this branch instead of `[sync] branch`. With the jj backend, the bookmark to move
|
|
427
283
|
to each sync commit
|
|
@@ -452,6 +308,21 @@ git p4son sync --no-split # sync without splitting out the configured split us
|
|
|
452
308
|
git p4son sync --branch p4 # commit onto the p4 branch this time
|
|
453
309
|
```
|
|
454
310
|
|
|
311
|
+
`sync` commits onto the sync branch, `[sync] branch` in `.git-p4son/config.toml`, which `init` sets and which
|
|
312
|
+
defaults to `main`. From another branch, it checks the sync branch out, syncs and commits, then returns you to
|
|
313
|
+
where you started, telling you to `git rebase` your branch onto the sync branch; it doesn't rebase for you. The
|
|
314
|
+
pre-sync and post-sync hooks run on the sync branch. You stay on the sync branch when:
|
|
315
|
+
|
|
316
|
+
- local changes were [merged back](#how-sync-handles-writable-files) into the work tree, for you to review and
|
|
317
|
+
commit there
|
|
318
|
+
- a sync fails partway, with the files as Perforce left them and the commits so far kept
|
|
319
|
+
|
|
320
|
+
A failing pre-sync hook, or anything else that stops `sync` before it syncs, returns you to where you started.
|
|
321
|
+
|
|
322
|
+
`sync` requires clean git and Perforce workspaces: no uncommitted changes, untracked files included, and no
|
|
323
|
+
git-tracked files opened in Perforce. It checks them after any [blocking processes](#blocking-processes) and before
|
|
324
|
+
the [pre-sync hooks](#pre-sync-hook).
|
|
325
|
+
|
|
455
326
|
#### Blocking processes
|
|
456
327
|
|
|
457
328
|
Syncing while e.g. the Unreal editor is open lets p4 replace assets the editor still has loaded, so the editor
|
|
@@ -496,17 +367,61 @@ visits `101 102 103 104 105 106`.
|
|
|
496
367
|
Splitting only moves forward from a previous sync. The first sync, `last-synced`, and syncing to an older changelist
|
|
497
368
|
with `--force` are never split. Without any split users, `sync` makes no extra Perforce queries.
|
|
498
369
|
|
|
499
|
-
Finding the split users' changelists
|
|
500
|
-
|
|
501
|
-
|
|
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.
|
|
370
|
+
Finding the split users' changelists takes one Perforce query per split user and one more, none of which scans every
|
|
371
|
+
file in the range, so a large range stays within the server's `maxscanrows`. They run after the checks and the
|
|
372
|
+
pre-sync hooks, so those fail first. `--dry-run` skips the checks and hooks but still shows the resulting sequence.
|
|
505
373
|
|
|
506
|
-
####
|
|
374
|
+
#### Sync hooks
|
|
507
375
|
|
|
508
376
|
`sync` runs the [pre-sync](#pre-sync-hook) and [post-sync](#post-sync-hook) hooks.
|
|
509
377
|
|
|
378
|
+
#### How sync handles writable files
|
|
379
|
+
|
|
380
|
+
When you switch branches with `git checkout`, git removes the read-only flag on every file it writes. This means
|
|
381
|
+
that when you switch back to `main` for a sync, Perforce may refuse to overwrite those files because they are
|
|
382
|
+
writable. git-p4son handles these automatically by classifying each writable file:
|
|
383
|
+
|
|
384
|
+
**writable-unchanged** - The file on disk is identical to the last sync (only the read-only flag was removed
|
|
385
|
+
by git). This is the common case after switching branches. git-p4son detects this by comparing git blob IDs against
|
|
386
|
+
the last sync commit that touched the file, restores the read-only flag, and lets the sync overwrite the file.
|
|
387
|
+
|
|
388
|
+
**writable-changed** - The file on disk differs from the last sync. This happens when you manually edit a file
|
|
389
|
+
on `main` and commit it to git without submitting to Perforce. git-p4son lets the sync overwrite the file and
|
|
390
|
+
includes it in the sync commit (so the commit reflects pure Perforce state), then three-way merges your local
|
|
391
|
+
changes on top of the new Perforce content - similar to a `git rebase`. If the merge is clean, the result appears
|
|
392
|
+
as an unstaged change. If there are conflicts, standard conflict markers are inserted for you to resolve.
|
|
393
|
+
|
|
394
|
+
**added both locally and in Perforce** - A file you committed to git is also being added by Perforce (p4 has never
|
|
395
|
+
synced it to your workspace). There is no common baseline, so git-p4son merges the two versions against an empty
|
|
396
|
+
base: identical content merges cleanly, otherwise the file gets a single conflict block containing both full
|
|
397
|
+
versions for you to resolve.
|
|
398
|
+
|
|
399
|
+
**binary files** - Binary files that have local changes cannot be three-way merged. git-p4son restores your local
|
|
400
|
+
version to disk after the sync commit so it shows up in `git status` for you to handle manually.
|
|
401
|
+
|
|
402
|
+
**added locally, deleted upstream** - A file with local changes in git was deleted in Perforce. git-p4son lets the
|
|
403
|
+
delete stand and warns you - your version remains available in git history.
|
|
404
|
+
|
|
405
|
+
**deleted locally, added upstream** - A file you deleted from git was modified in Perforce. The Perforce version is
|
|
406
|
+
kept in the sync commit. You can delete it again if you want.
|
|
407
|
+
|
|
408
|
+
**ignored** - Files ignored by `.gitignore` are skipped with a warning. These are outside git's domain and should
|
|
409
|
+
be managed manually or via Perforce directly.
|
|
410
|
+
|
|
411
|
+
After syncing, git-p4son prints a summary of how each writable file was handled, and instructs you to review and
|
|
412
|
+
commit any files that need attention.
|
|
413
|
+
|
|
414
|
+
**Workspaces with `allwrite`** - When your client spec has the `allwrite` option, every file is writable by design,
|
|
415
|
+
so the read-only flag carries no information about local changes. git-p4son classifies files exactly as above (the
|
|
416
|
+
verdict comes from git, not from the flag), but leaves the write bit alone on files it finds unchanged: Perforce
|
|
417
|
+
compares digests before refusing to overwrite a writable file, and unchanged files pass that check. Only files with
|
|
418
|
+
local changes are made read-only for the duration of the sync, since those are the ones Perforce would otherwise
|
|
419
|
+
refuse to overwrite. The same digest check applies to git-ignored files: unchanged ones sync normally, and after the
|
|
420
|
+
sync git-p4son lists the ones Perforce skipped because they were modified locally.
|
|
421
|
+
|
|
422
|
+
**Writable mode** - With [writable mode](#writable-command) on, the files a sync touches are made writable again after
|
|
423
|
+
the sync if git tracks them. The sync itself works as described above, since the workspace is not `allwrite`.
|
|
424
|
+
|
|
510
425
|
### Sync-Split-Users Command
|
|
511
426
|
|
|
512
427
|
Show or edit the [split users](#split-users), the Perforce users whose changelists `sync` gives a commit each:
|
|
@@ -531,16 +446,13 @@ bash, zsh and PowerShell run `$(user)` as a command substitution.
|
|
|
531
446
|
|
|
532
447
|
### New Command
|
|
533
448
|
|
|
534
|
-
Create a
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
Opening files requires a clean git workspace, untracked files included; `new` refuses to run otherwise. The check
|
|
538
|
-
is skipped with `--no-edit`. After opening files, unchanged ones are reverted (see
|
|
539
|
-
[Keeping the changelist in sync with git](#keeping-the-changelist-in-sync-with-git)).
|
|
449
|
+
Create a changelist from the commits since the base branch: their files are opened in it, and its description lists
|
|
450
|
+
the commits. Optionally shelve it, or create a review in Swarm or another [review tool](#review-tools):
|
|
540
451
|
|
|
541
452
|
```sh
|
|
542
453
|
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]
|
|
454
|
+
[--no-alias] [--no-commit-list] [--shelve] [--review] [--review-tool NAME] [--per-commit]
|
|
455
|
+
[--ignore-out-of-date]
|
|
544
456
|
```
|
|
545
457
|
|
|
546
458
|
**Arguments:**
|
|
@@ -553,24 +465,24 @@ git p4son new -b BASE_BRANCH [-m <message> | -F <file>] [alias] [--force] [--dry
|
|
|
553
465
|
- `--no-commit-list`: Leave the enumerated commit list out of the changelist description, so it holds only the
|
|
554
466
|
message
|
|
555
467
|
- `-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
|
|
557
|
-
|
|
558
|
-
knows where the next ones start. With `--no-alias`
|
|
468
|
+
changed files: a branch or bookmark, or a commit exactly one points at, or with jj a change without a bookmark. The
|
|
469
|
+
alias records it by name, or a jj change by its change ID, as a commit would go stale after a sync and rebase, along
|
|
470
|
+
with the commits since it the changelist includes, so `update` knows where the next ones start. With `--no-alias`
|
|
471
|
+
any commit will do
|
|
559
472
|
- `-f, --force`: Overwrite an existing alias file
|
|
560
473
|
- `-n, --dry-run`: Pretend and print what would be done, but do not execute. Ends with `Dry run, nothing changed`
|
|
561
474
|
- `--no-edit`: Skip opening changed files for edit in Perforce
|
|
562
475
|
- `--no-alias`: Skip saving a changelist alias
|
|
563
476
|
- `--shelve`: Shelve the changelist after creating it
|
|
564
|
-
- `--review`:
|
|
477
|
+
- `--review`: Shelve and create a review with the default [review tool](#review-tools), Swarm unless
|
|
478
|
+
`[review-tool] default` names another. For Swarm, adds the `#review` keyword
|
|
479
|
+
- `--review-tool NAME`: Push the review to this review tool instead of the default one: `swarm`, or a
|
|
480
|
+
`[review-tool.NAME]` in `.git-p4son/config.toml`. Implies `--review`. The alias records the tool, which
|
|
481
|
+
`update --shelve` then runs
|
|
565
482
|
- `--per-commit`: Create the changelist on the first commit since the base branch, then update it once per later
|
|
566
483
|
commit, as described below. Refuses `--no-edit` and `--no-alias`
|
|
567
|
-
|
|
568
|
-
|
|
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.
|
|
484
|
+
- `--ignore-out-of-date`: Shelve even if files in the change are not at the latest revision (see
|
|
485
|
+
[Shelving only files at the latest revision](#shelving-only-files-at-the-latest-revision))
|
|
574
486
|
|
|
575
487
|
**Examples:**
|
|
576
488
|
```sh
|
|
@@ -581,67 +493,28 @@ git p4son new -m "New feature" --review -b main
|
|
|
581
493
|
git p4son new -m "New feature" --shelve --per-commit -b main # a shelf per commit, without a Swarm review
|
|
582
494
|
```
|
|
583
495
|
|
|
496
|
+
Opening files requires a clean git workspace, untracked files included; `new` refuses to run otherwise. The check
|
|
497
|
+
is skipped with `--no-edit`. After opening files, unchanged ones are reverted (see
|
|
498
|
+
[Keeping the changelist in sync with git](#keeping-the-changelist-in-sync-with-git)).
|
|
499
|
+
|
|
500
|
+
With `--per-commit`, `new` checks out the first commit since the base branch and runs `git p4son new` on it, then
|
|
501
|
+
checks out each later commit and runs `git p4son update` on it, and finally returns to where you started. With
|
|
502
|
+
`--shelve` or `--review`, every step shelves, so each commit shows up as its own patch in the review. With Swarm,
|
|
503
|
+
every step but the last sleeps 5 seconds to give Perforce/Swarm time to process the shelf; another review tool runs
|
|
504
|
+
once per step instead. It needs a clean git workspace even with `--dry-run`. [`review`](#review-command) is
|
|
505
|
+
`new --review --per-commit`, and describes the steps, the dry run and resuming after a failed step.
|
|
506
|
+
|
|
584
507
|
### Update Command
|
|
585
508
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
longer part of the
|
|
589
|
-
[Keeping the changelist in sync with git](#keeping-the-changelist-in-sync-with-git)). Opening files
|
|
590
|
-
|
|
591
|
-
`--no-edit`.
|
|
592
|
-
|
|
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.
|
|
509
|
+
Add the commits a changelist doesn't include yet: `update` opens their files for edit and appends their subjects to
|
|
510
|
+
the commit list in the description, keeping the message above it unless `-m` or `-F` replaces it. It also reverts
|
|
511
|
+
files that are no longer part of the change (see
|
|
512
|
+
[Keeping the changelist in sync with git](#keeping-the-changelist-in-sync-with-git)). Opening files needs a clean git
|
|
513
|
+
workspace, untracked files included, unless `--no-edit` skips it.
|
|
641
514
|
|
|
642
515
|
```sh
|
|
643
516
|
git p4son update [changelist] [-m <message> | -F <file>] [--base-branch BASE_BRANCH] [--dry-run]
|
|
644
|
-
[--no-commit-list] [--no-edit] [--shelve] [--per-commit]
|
|
517
|
+
[--no-commit-list] [--no-edit] [--shelve] [--per-commit] [--ignore-out-of-date]
|
|
645
518
|
```
|
|
646
519
|
|
|
647
520
|
**Arguments:**
|
|
@@ -652,16 +525,23 @@ git p4son update [changelist] [-m <message> | -F <file>] [--base-branch BASE_BRA
|
|
|
652
525
|
kept and updated as usual, and so is a Swarm `#review` keyword on a line of its own at the end of the description
|
|
653
526
|
- `-F, --file FILE`: Like `-m`, but read the message from a file. The message may span multiple lines
|
|
654
527
|
- `-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
|
|
528
|
+
Defaults to after the last commit the changelist includes, when its alias records that, else to `HEAD~1`. When the
|
|
529
|
+
base the alias records no longer resolves, as a deleted branch or an abandoned or divergent jj change, `update`
|
|
530
|
+
refuses without `-b`, and with it records the new base, as `new` does. That base has to sit below the changelist's
|
|
531
|
+
first commit
|
|
656
532
|
- `-n, --dry-run`: Pretend and print what would be done, but do not execute. Ends with `Dry run, nothing changed`
|
|
657
533
|
- `--no-commit-list`: Leave the enumerated commit list as it is. Without `-m` or `-F` the description is not
|
|
658
534
|
touched at all
|
|
659
535
|
- `--no-edit`: Skip opening changed files for edit in Perforce. With a record, the new commits are then neither
|
|
660
536
|
appended nor counted, so the next update that opens files includes them
|
|
661
|
-
- `--shelve`: Re-shelve the changelist after updating
|
|
537
|
+
- `--shelve`: Re-shelve the changelist after updating. For a review in a [review tool](#review-tools) other than
|
|
538
|
+
Swarm, as the alias records it, the tool then runs for the new shelf
|
|
662
539
|
- `--per-commit`: Update the changelist once per commit it doesn't include yet, or since the base branch without
|
|
663
540
|
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`
|
|
541
|
+
to give Perforce/Swarm time to process each shelf, unless another review tool has the changelist. `--dry-run`
|
|
542
|
+
prints the steps, one per commit
|
|
543
|
+
- `--ignore-out-of-date`: Shelve even if files in the change or the changelist are not at the latest revision (see
|
|
544
|
+
[Shelving only files at the latest revision](#shelving-only-files-at-the-latest-revision))
|
|
665
545
|
|
|
666
546
|
**Examples:**
|
|
667
547
|
```sh
|
|
@@ -674,39 +554,95 @@ git p4son update --per-commit --shelve # one shelf for each commit the changel
|
|
|
674
554
|
git p4son update 12345 -b HEAD~2 --per-commit --shelve # no record: the last two commits
|
|
675
555
|
```
|
|
676
556
|
|
|
557
|
+
#### Which commits are new
|
|
558
|
+
|
|
559
|
+
A changelist made by `new` or `review` has an alias that records its base and the commits it includes, by jj change
|
|
560
|
+
ID or, with git, by author date, which survive rebases and amends. `update` adds only the commits it doesn't know,
|
|
561
|
+
whether it shelves or not, and leaves the entries already in the commit list as they are, so an entry you reworded
|
|
562
|
+
stays as you wrote it.
|
|
563
|
+
|
|
564
|
+
- `-b` only chooses which files to open, for example `-b main` to open them all again after a manual `p4 revert`. A
|
|
565
|
+
`-b` above the last included commit is refused.
|
|
566
|
+
- An included commit that is gone from the branch, dropped or squashed, gets a warning. Its patch stays in the
|
|
567
|
+
review: to undo a shelved commit, revert it in a new commit.
|
|
568
|
+
- A new commit below included ones is refused, as its patch would undo the ones above it. Move it after them.
|
|
569
|
+
- An amend keeps the commit's identity, so `update` sees nothing new and opens every file since the base, which
|
|
570
|
+
takes in the amend. With new commits as well, run `update -b main`.
|
|
571
|
+
|
|
572
|
+
#### After a sync
|
|
573
|
+
|
|
574
|
+
A shelf holds whole files, so after a sync that changed files the changelist touches, the next shelf would mix the
|
|
575
|
+
sync's changes into your next patch. So when `update --shelve` finds you synced and rebased, it first inserts an
|
|
576
|
+
empty commit, `Rebase onto CL <N>`, after the last included commit, and shelves it on its own: its patch holds what
|
|
577
|
+
the sync changed. An update without `--shelve` leaves this to the next one that shelves, and a dry run says what it
|
|
578
|
+
would insert.
|
|
579
|
+
|
|
580
|
+
#### Changelists without a record
|
|
581
|
+
|
|
582
|
+
For a changelist whose alias records no commits, made by `alias new` or an older git-p4son, or one named by a number
|
|
583
|
+
no alias holds, `update` takes the commits since `-b`, `HEAD~1` by default. Their entries replace the ones in the
|
|
584
|
+
commit list with the same subject, the others are appended, and the list is renumbered.
|
|
585
|
+
|
|
586
|
+
#### One update per commit
|
|
587
|
+
|
|
588
|
+
With `--per-commit`, `update` checks out each new commit in turn, oldest first, updates the changelist on it, and
|
|
589
|
+
returns to where you started. With `--shelve`, each commit gets a shelf of its own, so it shows up as its own patch in
|
|
590
|
+
the review. Without a record, give the range with `-b`, such as `-b HEAD~2` for the last two commits; with one, `-b`
|
|
591
|
+
is refused, as it would shelve included commits again. `-m`/`-F` applies to the first step only, and the run needs a
|
|
592
|
+
clean git workspace even with `--no-edit`.
|
|
593
|
+
|
|
594
|
+
If a step fails, `update` returns to where you started and names the commit that failed, with the command that
|
|
595
|
+
resumes after the last commit that worked. With a record, running the same command again does the same.
|
|
596
|
+
|
|
677
597
|
### Keeping the changelist in sync with git
|
|
678
598
|
|
|
679
|
-
`new` and `update` open every file changed since the base branch in the changelist. A file
|
|
599
|
+
`new` and `update` open every file changed since the base branch in the changelist. A file git sees as renamed is
|
|
600
|
+
opened as a `p4 move` from its old path to its new one, carrying any edit along, so Perforce keeps its history and the
|
|
601
|
+
review shows the move with only the lines that changed. git finds a rename as `git diff -M` does, by at least half
|
|
602
|
+
the content matching, whatever `diff.renames` says. A file renamed again later moves on from where it started, and an
|
|
603
|
+
existing move stays opened through later edits. A file added earlier in the same change is renamed as an add, as it
|
|
604
|
+
isn't in the depot yet, and a rename that only changes the case of the name is an edit, as a case-insensitive server
|
|
605
|
+
sees one file.
|
|
606
|
+
|
|
607
|
+
A file can later stop being
|
|
680
608
|
part of the change, for example when a later commit undoes an edit, or a file is added in one commit and deleted
|
|
681
609
|
in the next. Such files would otherwise stay opened as no-ops, so after opening files both commands revert them:
|
|
682
610
|
|
|
683
611
|
- Files opened for edit that are unchanged compared to the depot are reverted with `p4 revert -a`. Changed files
|
|
684
612
|
stay opened.
|
|
685
613
|
- Files opened for add that are missing from disk are reverted.
|
|
686
|
-
- Files opened for delete that git still has (deleted in one commit, restored in a later one) are reverted
|
|
687
|
-
|
|
614
|
+
- Files opened for delete that git still has (deleted in one commit, restored in a later one) are reverted, keeping
|
|
615
|
+
git's file.
|
|
616
|
+
- Moves whose new path git no longer has, as the rename was undone, are reverted, which reverts both ends.
|
|
688
617
|
|
|
689
618
|
Only files git-p4son has authority over are touched: files tracked by git, and files opened for add that are
|
|
690
619
|
missing from disk. Anything else in the changelist, such as binaries that only exist in Perforce and were opened
|
|
691
|
-
by hand, is left alone even when unchanged. Files opened with other actions (`
|
|
692
|
-
|
|
620
|
+
by hand, is left alone even when unchanged. Files opened with other actions (`integrate`, `branch`, ...) are also
|
|
621
|
+
left alone. This step is skipped with `--no-edit`.
|
|
693
622
|
|
|
694
623
|
Shelving (`--shelve`, `--review`) replaces the whole shelf with the changelist's opened files using
|
|
695
624
|
`p4 shelve -r -a leaveunchanged`, so the shelf never holds stale files, and unchanged files that are still opened
|
|
696
625
|
are left out of it.
|
|
697
626
|
|
|
627
|
+
#### Shelving only files at the latest revision
|
|
628
|
+
|
|
629
|
+
Before shelving, `new`, `update` and `review` check that the files are synced to the latest revision in the depot:
|
|
630
|
+
the change's files, and for `update` also the files already opened in the changelist, or with `--no-edit` only
|
|
631
|
+
those. A file is out of date when someone has submitted a newer revision, deleted it, or added a file of that name
|
|
632
|
+
since your last sync. Shelved, it would show in the review against an older revision, and the changelist would need a
|
|
633
|
+
resolve before it is submitted, so the command lists the files and refuses, before it changes anything. Run
|
|
634
|
+
`git p4son sync`, rebase the change onto it and run the command again, or pass `--ignore-out-of-date` to shelve
|
|
635
|
+
anyway; the command it gives to resume or rerun after a failure keeps the option. With `--per-commit`, the check
|
|
636
|
+
covers every commit once, before the first step. Without shelving there is no check.
|
|
637
|
+
|
|
698
638
|
### Review Command
|
|
699
639
|
|
|
700
|
-
Create a
|
|
701
|
-
|
|
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`.
|
|
640
|
+
Create a review with one shelf per commit, so each commit is a patch of its own. `review` is short for
|
|
641
|
+
`git p4son new --review --per-commit`:
|
|
707
642
|
|
|
708
643
|
```sh
|
|
709
644
|
git p4son review -b BASE_BRANCH [alias] [-m <message> | -F <file>] [--force] [--dry-run] [--no-commit-list]
|
|
645
|
+
[--review-tool NAME] [--ignore-out-of-date]
|
|
710
646
|
```
|
|
711
647
|
|
|
712
648
|
**Arguments:**
|
|
@@ -722,20 +658,8 @@ git p4son review -b BASE_BRANCH [alias] [-m <message> | -F <file>] [--force] [--
|
|
|
722
658
|
- `-n, --dry-run`: Print the steps, one per commit, without running them. Ends with `Dry run, nothing changed`
|
|
723
659
|
- `--no-commit-list`: Leave the enumerated commit list out of the changelist description. Passed on to `new` and
|
|
724
660
|
each `update` step
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
the first step gets, is printed below it:
|
|
728
|
-
|
|
729
|
-
```
|
|
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
|
|
733
|
-
```
|
|
734
|
-
|
|
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.
|
|
661
|
+
- `--ignore-out-of-date`: Shelve even if files in the change are not at the latest revision (see
|
|
662
|
+
[Shelving only files at the latest revision](#shelving-only-files-at-the-latest-revision))
|
|
739
663
|
|
|
740
664
|
**Examples:**
|
|
741
665
|
```sh
|
|
@@ -752,9 +676,30 @@ git p4son review -m "Add my feature" -b main --dry-run
|
|
|
752
676
|
git p4son review -F description.txt -b main
|
|
753
677
|
```
|
|
754
678
|
|
|
679
|
+
`review` checks out the first commit since the base branch and runs `git p4son new --review` on it, then checks out
|
|
680
|
+
each later commit and runs `git p4son update --shelve`, and finally returns to where you started. With Swarm, every
|
|
681
|
+
step but the last sleeps 5 seconds to give Perforce/Swarm time to process the shelf; another
|
|
682
|
+
[review tool](#review-tools) runs once per step instead. The commits are reviewed where they are: to review them on top
|
|
683
|
+
of the latest `main`, rebase first. Like `new`, it needs a clean git workspace, untracked files included, and checks
|
|
684
|
+
it even with `--dry-run`.
|
|
685
|
+
|
|
686
|
+
A dry run prints the plan like this, with the base resolved to the commit every step uses; the message, which only
|
|
687
|
+
the first step gets, is printed below it:
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
abc1234 First commit: git p4son new my-feature --review -b 5f1d0e9c2a7b4e8d9c0b1a2f3e4d5c6b7a8f9e0d
|
|
691
|
+
def5678 Second commit: git p4son update my-feature --shelve -b 5f1d0e9c2a7b4e8d9c0b1a2f3e4d5c6b7a8f9e0d
|
|
692
|
+
ghi9012 Third commit: git p4son update my-feature --shelve -b 5f1d0e9c2a7b4e8d9c0b1a2f3e4d5c6b7a8f9e0d
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
If a step fails, `review` returns to where you started and names the step and commit that failed. Once the first
|
|
696
|
+
step has created the changelist, the error also says how to finish: after fixing the problem, run the
|
|
697
|
+
`git p4son update my-feature --shelve --per-commit -b <commit>` it prints, which resumes after the last commit that
|
|
698
|
+
worked.
|
|
699
|
+
|
|
755
700
|
### List-Changes Command
|
|
756
701
|
|
|
757
|
-
List commit subjects since a base branch
|
|
702
|
+
List the commit subjects since a base branch, oldest first and numbered, as a changelist description lists them:
|
|
758
703
|
|
|
759
704
|
```sh
|
|
760
705
|
git p4son list-changes [--base-branch BASE_BRANCH] [--porcelain]
|
|
@@ -772,17 +717,12 @@ git p4son list-changes --base-branch main
|
|
|
772
717
|
git p4son list-changes --base-branch main --porcelain
|
|
773
718
|
```
|
|
774
719
|
|
|
775
|
-
This command is useful for generating changelist descriptions by listing all commit messages since the base branch,
|
|
776
|
-
numbered sequentially.
|
|
777
|
-
|
|
778
720
|
### Alias Command
|
|
779
721
|
|
|
780
|
-
Manage changelist aliases,
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
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`.
|
|
722
|
+
Manage changelist aliases: names that stand for changelist numbers, so you can say `my-feature` instead of `12345`.
|
|
723
|
+
`new` and `review` save one named after the branch, which also records what [`update`](#update-command) needs to go
|
|
724
|
+
on from. Aliases are stored in `.git-p4son/aliases/`; ones saved by older versions in `.git-p4son/changelists/` keep
|
|
725
|
+
working, and move when written, or all at once with `alias clean`.
|
|
786
726
|
|
|
787
727
|
#### alias list
|
|
788
728
|
|
|
@@ -792,11 +732,6 @@ List all aliases and their changelist numbers:
|
|
|
792
732
|
git p4son alias list
|
|
793
733
|
```
|
|
794
734
|
|
|
795
|
-
**Examples:**
|
|
796
|
-
```sh
|
|
797
|
-
git p4son alias list
|
|
798
|
-
```
|
|
799
|
-
|
|
800
735
|
#### alias show
|
|
801
736
|
|
|
802
737
|
Print the changelist number saved under an alias:
|
|
@@ -840,6 +775,36 @@ git p4son alias new 12345 myfeature
|
|
|
840
775
|
git p4son alias new 67890 myfeature -f
|
|
841
776
|
```
|
|
842
777
|
|
|
778
|
+
#### alias rename
|
|
779
|
+
|
|
780
|
+
Rename an alias, keeping its changelist and everything it records for `update`:
|
|
781
|
+
|
|
782
|
+
```sh
|
|
783
|
+
git p4son alias rename [OLD] NEW [--force]
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
As with `git branch -m`, a single name is the new name for the current alias, the one the current branch names, or
|
|
787
|
+
with jj the one that records the jj change. The `branch` keyword works for either name; as `NEW` it is the current
|
|
788
|
+
branch or bookmark name, so the alias can follow a renamed branch.
|
|
789
|
+
|
|
790
|
+
**Arguments:**
|
|
791
|
+
- `OLD` (optional): The alias to rename. Defaults to the current alias
|
|
792
|
+
- `NEW`: The new alias name
|
|
793
|
+
|
|
794
|
+
**Options:**
|
|
795
|
+
- `-f, --force`: Overwrite an existing alias of the new name
|
|
796
|
+
|
|
797
|
+
**Examples:**
|
|
798
|
+
```sh
|
|
799
|
+
git p4son alias rename my-feature-v2 # the current alias, then: git branch -m my-feature-v2
|
|
800
|
+
git p4son alias rename my-feature branch # after git branch -m: follow the branch's new name
|
|
801
|
+
git p4son alias rename my-feature my-feature-v2
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
With git, renaming the branch first means the branch no longer names the alias, so name both:
|
|
805
|
+
`alias rename OLD branch`. With jj, `alias rename NEW` works before or after `jj bookmark rename`, as the alias
|
|
806
|
+
records the jj change.
|
|
807
|
+
|
|
843
808
|
#### alias delete
|
|
844
809
|
|
|
845
810
|
Delete a changelist alias, or all of them:
|
|
@@ -852,8 +817,9 @@ git p4son alias delete [alias | --all]
|
|
|
852
817
|
- `alias` (optional): Alias name to delete. Defaults to the current branch name.
|
|
853
818
|
|
|
854
819
|
**Options:**
|
|
855
|
-
- `--all`: Delete all aliases without prompting
|
|
856
|
-
and
|
|
820
|
+
- `--all`: Delete all aliases without prompting, whether their changelists are pending or not. To delete only those
|
|
821
|
+
that are not, use `alias clean`. An alias that can't be deleted is reported and skipped, and the command then exits
|
|
822
|
+
with 1
|
|
857
823
|
|
|
858
824
|
**Examples:**
|
|
859
825
|
```sh
|
|
@@ -864,27 +830,37 @@ git p4son alias delete --all
|
|
|
864
830
|
|
|
865
831
|
#### alias clean
|
|
866
832
|
|
|
867
|
-
|
|
833
|
+
Delete the aliases whose changelist is no longer pending, as it was submitted or deleted:
|
|
868
834
|
|
|
869
835
|
```sh
|
|
870
|
-
git p4son alias clean
|
|
836
|
+
git p4son alias clean [-n] [--porcelain]
|
|
871
837
|
```
|
|
872
838
|
|
|
873
|
-
It first moves any aliases still in `.git-p4son/changelists/` to `.git-p4son/aliases/`, then
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
839
|
+
It first moves any aliases still in `.git-p4son/changelists/` to `.git-p4son/aliases/`, then goes through the aliases
|
|
840
|
+
in name order: it looks up the alias's changelist in Perforce and deletes the alias if the changelist was submitted or
|
|
841
|
+
doesn't exist. If p4 answers neither that nor pending for a changelist, it stops
|
|
842
|
+
there, leaving that alias and the ones after it. A submit that renumbers the changelist leaves its old number behind,
|
|
843
|
+
which counts as gone too. With the jj backend, an alias whose [jj change](#jujutsu-jj) is gone but whose changelist
|
|
844
|
+
is still pending is kept; `alias list` marks it `(gone)`, and `alias delete` removes it.
|
|
845
|
+
|
|
846
|
+
It ends under an `Alias clean done` heading with how many aliases it deleted and kept. If any couldn't be deleted,
|
|
847
|
+
that line is a warning with how many failed, followed by an error, and the command exits with 1.
|
|
878
848
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
-
|
|
883
|
-
|
|
849
|
+
To delete specific aliases, use `alias list` and `alias delete`.
|
|
850
|
+
|
|
851
|
+
**Options:**
|
|
852
|
+
- `-n, --dry-run`: List the aliases that would be deleted, without deleting or moving any. Ends with
|
|
853
|
+
`Dry run, nothing changed`
|
|
854
|
+
- `--porcelain`: Print only one `<action> <alias> <CL>` line per alias, for scripts and agents. The action is `kept`,
|
|
855
|
+
`deleted`, or `failed` when the alias couldn't be deleted; with `-n` it is `would-keep` or `would-delete`. Errors
|
|
856
|
+
still go to stderr. A `failed` alias makes the exit code 1, after the lines for all aliases; a stop exits with 1,
|
|
857
|
+
with no line for the alias it stopped at or those after it.
|
|
884
858
|
|
|
885
859
|
**Examples:**
|
|
886
860
|
```sh
|
|
861
|
+
git p4son alias clean -n # see which aliases would go
|
|
887
862
|
git p4son alias clean
|
|
863
|
+
git p4son alias clean --porcelain # e.g. "deleted feature-login 12345"
|
|
888
864
|
```
|
|
889
865
|
|
|
890
866
|
### Writable Command
|
|
@@ -957,28 +933,116 @@ Most commands that accept an alias or changelist argument default to the current
|
|
|
957
933
|
The keyword cannot be used in a detached HEAD state. Use `--no-alias` (on `new`) or supply an explicit
|
|
958
934
|
alias name instead.
|
|
959
935
|
|
|
936
|
+
## Configuration
|
|
937
|
+
|
|
938
|
+
git-p4son keeps its per-repository settings in `.git-p4son/config.toml`. `init`, `writable` and `sync-split-users`
|
|
939
|
+
write most of them; the rest you edit by hand.
|
|
940
|
+
|
|
941
|
+
- `[depot] root` (string, set by `init`): the depot path `sync` syncs, e.g. `//$(workspace)` or
|
|
942
|
+
`//$(workspace)/Engine`. See [Init Command](#init-command)
|
|
943
|
+
- `[core] writable` (`true` or `false`, default `false`): [writable mode](#writable-command), which keeps
|
|
944
|
+
git-tracked files writable
|
|
945
|
+
- `[core] backend` (`"auto"`, `"git"` or `"jj"`, default `"auto"`): the tool git-p4son follows for the change, the
|
|
946
|
+
base and the branch. `auto` means jj in a [jj workspace](#jujutsu-jj) and git otherwise
|
|
947
|
+
- `[sync] branch` (string, set by `init`): the sync branch, which `sync` commits onto from whatever branch you are
|
|
948
|
+
on. Without it, `sync` uses `main`. See [Sync Command](#sync-command)
|
|
949
|
+
- `[sync] split-users` (list of strings, default empty): the users whose changelists `sync` gives a commit each;
|
|
950
|
+
`$(user)` stands for you. See [Split users](#split-users)
|
|
951
|
+
- `[sync] blocking-processes` (list of strings, default empty): processes that stop a sync while they run. See
|
|
952
|
+
[Blocking processes](#blocking-processes)
|
|
953
|
+
- `[review-tool] default` (string, default `"swarm"`): the [review tool](#review-tools) `new --review` and `review`
|
|
954
|
+
push to without `--review-tool`
|
|
955
|
+
- `[review-tool.<name>]` (table): a [review tool](#review-tools)'s `command`, and its `new` and `update` arguments
|
|
956
|
+
- `[core.script-runners]` (table, Windows only): the command that runs a hook script, by file extension.
|
|
957
|
+
See [Hooks](#hooks). The old `[hooks.extension-associations]` is still read, and `core.script-runners` wins where
|
|
958
|
+
both name an extension
|
|
959
|
+
|
|
960
|
+
For example:
|
|
961
|
+
|
|
962
|
+
```toml
|
|
963
|
+
[depot]
|
|
964
|
+
root = "//$(workspace)"
|
|
965
|
+
|
|
966
|
+
[core]
|
|
967
|
+
writable = true
|
|
968
|
+
|
|
969
|
+
[sync]
|
|
970
|
+
split-users = ["$(user)", "alice"]
|
|
971
|
+
blocking-processes = ["UnrealEditor"]
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
A value of the wrong type, such as `writable = "true"` or `split-users = "alice"`, or a file that is not valid TOML,
|
|
975
|
+
stops the command with an error naming the setting, so a typo is never silently ignored.
|
|
976
|
+
|
|
977
|
+
## Review Tools
|
|
978
|
+
|
|
979
|
+
`new --review` and `review` create a review in Swarm by default: the description gets a `#review` keyword, and Swarm
|
|
980
|
+
picks up each shelf. A team that reviews with another tool, one that has to be run to post each shelf, configures the
|
|
981
|
+
tool's command line under a name of its choosing in `.git-p4son/config.toml`:
|
|
982
|
+
|
|
983
|
+
```toml
|
|
984
|
+
[review-tool]
|
|
985
|
+
default = "my-tool"
|
|
986
|
+
|
|
987
|
+
[review-tool.my-tool]
|
|
988
|
+
command = ["python", "tools/my-review.py", "--p4port", "$(p4port)", "--changelist", "$(changelist)"]
|
|
989
|
+
new = ["create"]
|
|
990
|
+
update = ["update"]
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
`--review-tool my-tool` pushes a review to it, and `default` makes it the default, so `--review-tool swarm` picks
|
|
994
|
+
Swarm again. The alias records the changelist's tool, so `update --shelve` runs it again without naming it; to move a
|
|
995
|
+
change to another tool, delete the changelist and its alias and create the review again. `--no-alias` is refused with
|
|
996
|
+
any tool but Swarm.
|
|
997
|
+
|
|
998
|
+
With a review tool other than Swarm, there is no `#review` keyword, and after each shelve of the review git-p4son runs
|
|
999
|
+
`command` from the workspace root, once per commit with `review`. On the shelve of `new`, the `new` arguments are
|
|
1000
|
+
added to it, to create the review, and on the shelves of `update` the `update` ones, to add the new shelf as a
|
|
1001
|
+
revision of it. If the first run fails, the `update --shelve` that reruns it still gets the `new` arguments, as the
|
|
1002
|
+
review doesn't exist yet. Both are optional; without one, `command` runs as it is.
|
|
1003
|
+
|
|
1004
|
+
`command`, `new` and `update` are lists, one string per argument; a single string is refused. No shell runs them,
|
|
1005
|
+
so they work the same on every platform and never need quoting. A program named by a relative path, such as
|
|
1006
|
+
`tools/review.exe`, is found from the workspace root, and a bare name, such as `python`, on `PATH`. A `.cmd` or `.ps1`
|
|
1007
|
+
script on Windows needs its interpreter named, such as `["pwsh", "-File", "tools/my-review.ps1"]`. `$(name)` in an
|
|
1008
|
+
argument is replaced:
|
|
1009
|
+
|
|
1010
|
+
- `$(changelist)`: the pending changelist number
|
|
1011
|
+
- `$(workspace)`: the Perforce client workspace name
|
|
1012
|
+
- `$(user)`: the Perforce user
|
|
1013
|
+
- `$(p4port)`: the server address, as `p4 set P4PORT` gives it
|
|
1014
|
+
- any other name: the environment variable of that name, which on Windows ignores case. A name that is neither fails
|
|
1015
|
+
the command before anything runs
|
|
1016
|
+
|
|
1017
|
+
A replaced value stays within its argument, spaces and all. The command is echoed with the values in, so it can be
|
|
1018
|
+
rerun by hand; that also shows any token passed through an environment variable. Anything more, such as settings
|
|
1019
|
+
files or a sign-in, goes in a wrapper script of your own that the command runs.
|
|
1020
|
+
|
|
1021
|
+
The first run can sign in or open a browser; later ones run once per shelve, often as the steps of a per-commit run,
|
|
1022
|
+
so keep them non-interactive. A tool that exits with a non-zero code fails the command. `review` then stops at that
|
|
1023
|
+
commit with the command that resumes it, which shelves the commit again and reruns the tool, and `new` names the
|
|
1024
|
+
`update <alias> --shelve` that reruns it once the tool works. `--dry-run` says which tool would run. The tool runs on
|
|
1025
|
+
the terminal, so its output shows as it is written and it can prompt. Like a hook, it runs under git-p4son's
|
|
1026
|
+
[jj lock](#locking-and-the-git-workflow), so it must not run jj commands that snapshot.
|
|
1027
|
+
|
|
960
1028
|
## Hooks
|
|
961
1029
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
at defined times during git-p4son operations. Scripts get run in filename (lexicographically) sorted
|
|
965
|
-
order.
|
|
1030
|
+
Like git hooks, hooks are programs git-p4son runs at set points of a command: executables, or on Windows scripts, in
|
|
1031
|
+
`.git-p4son/hooks/<hook-name>/`, run in filename order.
|
|
966
1032
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
the command runs with.
|
|
1033
|
+
A hook runs in the directory git-p4son was run from, with `GIT_P4SON_REPO_ROOT_DIR` set to the repository root and
|
|
1034
|
+
`GIT_P4SON_BACKEND` to `git` or `jj`, the [backend](#choosing-the-backend) the command runs with.
|
|
970
1035
|
|
|
971
|
-
On Windows, `.ps1`, `.
|
|
972
|
-
`
|
|
973
|
-
Customize or add Windows script associations in `.git-p4son/config.toml`:
|
|
1036
|
+
On Windows, `.ps1`, `.sh` and `.py` files run with `powershell.exe -NoProfile -ExecutionPolicy Bypass -File`,
|
|
1037
|
+
`bash.exe` and `python.exe`. Change or add script runners in `.git-p4son/config.toml`:
|
|
974
1038
|
|
|
975
1039
|
```toml
|
|
976
|
-
[
|
|
1040
|
+
[core.script-runners]
|
|
977
1041
|
".ps1" = ["pwsh.exe", "-NoProfile", "-File"]
|
|
978
|
-
".
|
|
1042
|
+
".nu" = "nu.exe"
|
|
979
1043
|
```
|
|
980
1044
|
|
|
981
|
-
Non-executable or unrecognized hook files, and invalid
|
|
1045
|
+
Non-executable or unrecognized hook files, and invalid runner entries, are skipped with a warning.
|
|
982
1046
|
|
|
983
1047
|
### pre-sync hook
|
|
984
1048
|
|
|
@@ -1044,13 +1108,20 @@ With the jj backend in a jj workspace:
|
|
|
1044
1108
|
- `new` records the change's ID in the alias it saves, so later commands find the alias by change, whatever the
|
|
1045
1109
|
change's bookmarks or description have become since. A new alias is named after the one local bookmark at the
|
|
1046
1110
|
change, with `/` replaced by `-`, or, with no bookmark or several, after the first 8 letters of its change ID.
|
|
1111
|
+
- When no alias records the change itself, as after adding changes on top of the one `new` recorded, the current
|
|
1112
|
+
alias is the one recording the nearest change below it. The search stops at the first bookmark below the change,
|
|
1113
|
+
so a bookmarked change stacked on another's CL doesn't take that CL's alias, and skips empty changes, which a sync
|
|
1114
|
+
leaves behind for submitted CLs. In a stack without bookmarks, every change above `main` counts. jj doesn't move
|
|
1115
|
+
a bookmark on `jj new`, so a bookmark left on the change `new` recorded stops the search from the changes above
|
|
1116
|
+
it: move it to the tip with `jj bookmark move <name> --to @-`, or `--to @` when the working change has content.
|
|
1047
1117
|
- An alias records one change, and a change one alias: `new` refuses a change another alias records, naming it, and
|
|
1048
1118
|
`--force` moves the record to the new alias. `alias new` records no change. `alias list` shows each recorded change,
|
|
1049
1119
|
marked `(gone)` once jj no longer has it.
|
|
1050
1120
|
- The default message is the first line of the change's description. Use `jj describe`, `-m` or `-F`.
|
|
1051
1121
|
- `-b/--base-branch` takes a jj revision that resolves to one change, such as a bookmark, change ID or commit ID.
|
|
1052
1122
|
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
|
|
1123
|
+
bookmark when it names one or resolves to a commit exactly one points at, and as its change ID when it has none, so
|
|
1124
|
+
a local change kept under a stack, never submitted, can be the base. Several bookmarks at it is an error.
|
|
1054
1125
|
- `new` and `update` use jj's snapshot of the working copy, check that it did not change while git-p4son took the
|
|
1055
1126
|
lock, and refuse files jj left untracked. You do not need a separate committed change before opening files in
|
|
1056
1127
|
Perforce. Before a Perforce revert overwrites a file, git-p4son saves the working file and puts it back
|
|
@@ -1147,44 +1218,35 @@ colocates with both settings.
|
|
|
1147
1218
|
git matches `.gitignore` patterns without case when `core.ignorecase` is true, the default on Windows and macOS. jj
|
|
1148
1219
|
always matches them with case, so it would track a `Thirdparty/` folder that git ignores through `ThirdParty/`.
|
|
1149
1220
|
|
|
1150
|
-
|
|
1151
|
-
repository, building on any value you have, for example `(all()) ~ root:Some/Plugin/Source/Thirdparty`.
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
yours, a later change to your user-level
|
|
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`.
|
|
1221
|
+
git-p4son keeps jj from tracking them by leaving each such folder, or file, out of jj's `snapshot.auto-track` for the
|
|
1222
|
+
repository, building on any value you have, for example `(all()) ~ root:Some/Plugin/Source/Thirdparty`. `jj status`
|
|
1223
|
+
then lists them under "Untracked paths". It does so when `init` colocates, and at the end of each sync on the jj
|
|
1224
|
+
backend, as a sync can bring in new folders. To let jj track such a folder again, remove its `root:"..."` with
|
|
1225
|
+
`jj config edit --repo`. As the repository's value holds yours, a later change to your user-level
|
|
1226
|
+
`snapshot.auto-track` doesn't reach the repository.
|
|
1160
1227
|
|
|
1161
1228
|
If jj tracks such files anyway, for example in a workspace colocated before git-p4son did this, git-p4son warns about
|
|
1162
|
-
the ones
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
`jj file track --include-ignored`, are left alone.
|
|
1229
|
+
the ones your change adds. The warning lists the `jj config set` that leaves them out and the `jj file untrack` that
|
|
1230
|
+
stops tracking them, which leaves the files on disk. Both are quoted to paste into cmd, PowerShell or a POSIX shell.
|
|
1231
|
+
They name a folder only when git tracks nothing else in it, so files git tracks stay tracked. Files you track on
|
|
1232
|
+
purpose, with `jj file track --include-ignored`, are left alone.
|
|
1167
1233
|
|
|
1168
1234
|
### Locking, and the git workflow
|
|
1169
1235
|
|
|
1170
1236
|
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.
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
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.
|
|
1237
|
+
so other jj processes cannot snapshot files halfway through. A busy lock stops the command. The lock does not keep
|
|
1238
|
+
out editors, git commands or other jj workspaces, and a command is not one atomic jj transaction: jj's first
|
|
1239
|
+
snapshot, the final import, and sync's rebase and return happen outside it. If a command fails, look at the workspace
|
|
1240
|
+
before continuing: Perforce operations that completed are not undone.
|
|
1179
1241
|
|
|
1180
1242
|
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`
|
|
1182
|
-
|
|
1243
|
+
as `jj --at-op=@ log` are fine, and a hook that runs git-p4son itself needs `--backend git`, which reuses the
|
|
1244
|
+
caller's lock.
|
|
1183
1245
|
|
|
1184
|
-
`review`, `new --per-commit` and `update --per-commit` run once per commit since the base,
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1246
|
+
`review`, `new --per-commit` and `update --per-commit` run once per commit since the base, as they do in git. Under
|
|
1247
|
+
jj's lock, each step puts its commit's files on disk with git, and the working change's files go back at the end,
|
|
1248
|
+
also when a step fails, so jj sees no change. Untracked and ignored files are left alone. They refuse to start if
|
|
1249
|
+
files changed after jj's snapshot, as the checkouts would overwrite them:
|
|
1188
1250
|
|
|
1189
1251
|
```sh
|
|
1190
1252
|
git p4son review -b main
|
|
@@ -1277,3 +1339,39 @@ source $(git-p4son completion zsh --jj) # ~/.zshrc, after compinit
|
|
|
1277
1339
|
Each loads the `git p4son` completion for its shell too. If you named the alias something other than `p4son`, set
|
|
1278
1340
|
`GIT_P4SON_JJ_ALIAS` to its name.
|
|
1279
1341
|
|
|
1342
|
+
## Development
|
|
1343
|
+
|
|
1344
|
+
To install from source in editable mode:
|
|
1345
|
+
|
|
1346
|
+
```sh
|
|
1347
|
+
git clone https://github.com/neoboid/git-p4son.git
|
|
1348
|
+
cd git-p4son
|
|
1349
|
+
pip install -e .
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
The `-e` flag installs the package in "editable" mode, meaning changes to the code are immediately available
|
|
1353
|
+
without reinstalling. This is also handy if you want to auto-update git-p4son whenever you pull from GitHub.
|
|
1354
|
+
|
|
1355
|
+
git-p4son only uses Python standard library modules - no additional packages are required.
|
|
1356
|
+
|
|
1357
|
+
Run the tests with `python -m pytest tests/` (`pip install pytest`). With `pytest-xdist` installed, add
|
|
1358
|
+
`-n auto --maxprocesses 8` to run them in parallel, which is about three times faster.
|
|
1359
|
+
|
|
1360
|
+
### Git Hooks
|
|
1361
|
+
|
|
1362
|
+
The repository includes git hooks in the `hooks/` directory:
|
|
1363
|
+
|
|
1364
|
+
- **pre-commit** - verifies that staged Python files are formatted with `autopep8`. Install it with
|
|
1365
|
+
`pip install autopep8`.
|
|
1366
|
+
- **pre-push** - runs the test suite and blocks the push if any test fails. It needs `pytest` installed, and runs
|
|
1367
|
+
the tests in parallel when `pytest-xdist` is too.
|
|
1368
|
+
|
|
1369
|
+
To activate the hooks, run:
|
|
1370
|
+
|
|
1371
|
+
```sh
|
|
1372
|
+
scripts/setup-hooks.sh
|
|
1373
|
+
```
|
|
1374
|
+
|
|
1375
|
+
This configures `core.hooksPath` so git uses the hooks from the repository. You only need to run this once after
|
|
1376
|
+
cloning.
|
|
1377
|
+
|