guito 1.0.2 → 1.0.3

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.
@@ -1,5 +1,5 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { isAbsolute, join, relative, resolve, sep } from 'node:path';
1
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
2
+ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
3
3
  /** NUL-delimited metadata is authoritative: patch headers quote unusual filenames. */
4
4
  function names(raw) {
5
5
  const fields = raw.split('\0');
@@ -137,5 +137,74 @@ export function workingTree(git, parse) {
137
137
  throw new Error('Stage changes before committing.');
138
138
  await git.commit([message.trim(), ...(description ? [description] : [])]);
139
139
  }
140
- return { snapshot, stage, unstage, commit };
140
+ async function conflictPath(path) {
141
+ const [selected] = await validate([path]);
142
+ const unmerged = await git.raw([
143
+ '--literal-pathspecs', 'ls-files', '--unmerged', '-z', '--', selected,
144
+ ]);
145
+ if (!unmerged)
146
+ throw new Error(`File is no longer conflicted: ${selected}`);
147
+ return selected;
148
+ }
149
+ async function conflictStage(path, stage) {
150
+ try {
151
+ const content = await git.raw(['show', `:${stage}:${path}`]);
152
+ return { content: content.includes('\0') ? '' : content, binary: content.includes('\0') };
153
+ }
154
+ catch {
155
+ // A missing stage represents a deletion on that side of the merge.
156
+ return { content: null, binary: false };
157
+ }
158
+ }
159
+ /** Returns the three index stages and the current marker-filled worktree result. */
160
+ async function conflict(path) {
161
+ const selected = await conflictPath(path);
162
+ const root = (await git.revparse(['--show-toplevel'])).trim();
163
+ let result = null;
164
+ let resultBinary = false;
165
+ try {
166
+ const buffer = await readFile(join(root, selected));
167
+ resultBinary = buffer.includes(0);
168
+ if (!resultBinary)
169
+ result = buffer.toString('utf8');
170
+ }
171
+ catch {
172
+ // Delete/modify conflicts can currently have no worktree file.
173
+ }
174
+ const [base, ours, theirs] = await Promise.all([
175
+ conflictStage(selected, 1), conflictStage(selected, 2), conflictStage(selected, 3),
176
+ ]);
177
+ return { path: selected, base, ours, theirs, result: { content: result, binary: resultBinary } };
178
+ }
179
+ /** Writes or selects a result and stages it, which marks the path resolved. */
180
+ async function resolveConflict(path, resolution, content) {
181
+ const selected = await conflictPath(path);
182
+ if (!['content', 'ours', 'theirs', 'delete'].includes(String(resolution))) {
183
+ throw new Error('Choose a valid conflict resolution.');
184
+ }
185
+ const root = (await git.revparse(['--show-toplevel'])).trim();
186
+ const absolute = join(root, selected);
187
+ if (resolution === 'content') {
188
+ if (typeof content !== 'string' || content.includes('\0')) {
189
+ throw new Error('Conflict result must be text.');
190
+ }
191
+ await mkdir(dirname(absolute), { recursive: true });
192
+ await writeFile(absolute, content);
193
+ }
194
+ else if (resolution === 'delete') {
195
+ await rm(absolute, { force: true, recursive: true });
196
+ }
197
+ else {
198
+ const stage = resolution === 'ours' ? 2 : 3;
199
+ const selectedStage = await conflictStage(selected, stage);
200
+ if (selectedStage.content === null) {
201
+ await rm(absolute, { force: true, recursive: true });
202
+ }
203
+ else {
204
+ await git.raw(['--literal-pathspecs', 'checkout', `--${resolution}`, '--', selected]);
205
+ }
206
+ }
207
+ await git.raw(['--literal-pathspecs', 'add', '-A', '--', selected]);
208
+ }
209
+ return { snapshot, stage, unstage, commit, conflict, resolveConflict };
141
210
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guito",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Easily explore your git repositories.",
5
5
  "homepage": "https://github.com/danisss9/Guito#readme",
6
6
  "repository": {