-
Notifications
You must be signed in to change notification settings - Fork 5
Auto-sync local repository before commit and push when behind remote #623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
91b3c4b
8a6be9a
e49a947
43a782b
e44dc41
42260b2
6e69daa
0288a9e
733f8ef
b903ed8
9b4386a
ae75141
34e6b2a
ff34a29
1d9aef4
a1173ee
5b3e0df
47153bf
c022aff
d0236d7
90372d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -689,6 +689,59 @@ export class JobManagerContainer extends Container { | |
| const userConfigService = new UserConfigService(googleFileSystem); | ||
| const userConfig = await userConfigService.load(); | ||
|
|
||
| // Check if local branch is behind remote and sync if needed | ||
| if (userConfig.remote_branch) { | ||
| try { | ||
| await gitScanner.fetch({ | ||
| privateKeyFile: await userConfigService.getDeployPrivateKeyPath() | ||
| }); | ||
|
|
||
| const { ahead, behind } = await gitScanner.countAheadBehind(userConfig.remote_branch); | ||
|
|
||
| if (ahead > 0 && behind > 0) { | ||
| throw new Error('Local and remote branches have diverged. Please manually sync your repository before committing.'); | ||
| } | ||
|
|
||
| if (behind > 0) { | ||
| logger.info(`Local branch is ${behind} commit(s) behind remote. Syncing before commit...`); | ||
|
Comment on lines
+705
to
+706
|
||
|
|
||
| // Stash local changes - returns true if something was stashed | ||
| const stashed = await gitScanner.stashChanges(); | ||
|
|
||
| try { | ||
| // Pull with rebase to integrate remote changes (uses git pull --rebase internally) | ||
| await gitScanner.pullBranch(userConfig.remote_branch, { | ||
|
Comment on lines
+699
to
+713
|
||
| privateKeyFile: await userConfigService.getDeployPrivateKeyPath() | ||
| }); | ||
|
|
||
| // Apply stashed changes if we stashed something | ||
| if (stashed) { | ||
| await gitScanner.stashPop(); | ||
|
|
||
| // Check for conflicts after stash pop | ||
| if (await gitScanner.hasConflicts()) { | ||
| throw new Error('Stash pop resulted in merge conflicts. Cannot proceed with commit. ' + | ||
| 'Please resolve conflicts manually using "Reset and Pull" or by running git commands directly.'); | ||
| } | ||
| } | ||
|
Comment on lines
+718
to
+726
|
||
| } catch (err) { | ||
| // If pull fails, leave stash intact for manual recovery | ||
| // The user can use "Reset and Pull" to clean up or `git stash list` to view saved changes | ||
| if (stashed) { | ||
| logger.warn('Pull failed. Stashed changes remain saved for manual recovery. ' + | ||
|
Comment on lines
+729
to
+731
|
||
| 'Use `git stash list` to view stashed changes or "Reset and Pull" to clean up.'); | ||
| } | ||
| throw err; | ||
| } | ||
| } | ||
| } catch (err) { | ||
| if (err.message.indexOf('Failed to retrieve list of SSH authentication methods') > -1) { | ||
| throw new Error('Failed to authenticate with remote repository: ' + err.message); | ||
| } | ||
| throw err; | ||
| } | ||
| } | ||
|
Comment on lines
+740
to
+743
|
||
|
|
||
| const contentFileService = await getContentFileService(transformedFileSystem, userConfigService); | ||
| const markdownTreeProcessor = new MarkdownTreeProcessor(contentFileService); | ||
| await markdownTreeProcessor.load(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -349,38 +349,63 @@ export class GitScanner { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (err.message.indexOf('Updates were rejected because the remote contains work') > -1 || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| err.message.indexOf('Updates were rejected because a pushed branch tip is behind its remote') > -1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec(`git fetch origin ${remoteBranch}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_SSH_COMMAND: sshParams?.privateKeyFile ? `ssh -i ${sanitize(sshParams.privateKeyFile)} -o StrictHostKeyChecking=no -o IdentitiesOnly=yes` : '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Stash any local changes before fetching and rebasing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stashed = await this.stashChanges(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec(`git fetch origin ${remoteBranch}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_SSH_COMMAND: sshParams?.privateKeyFile ? `ssh -i ${sanitize(sshParams.privateKeyFile)} -o StrictHostKeyChecking=no -o IdentitiesOnly=yes` : '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec(`git rebase origin/${remoteBranch}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_AUTHOR_NAME: committer.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_AUTHOR_EMAIL: committer.email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_COMMITTER_NAME: committer.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_COMMITTER_EMAIL: committer.email | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Restore stashed changes if any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (stashed) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.stashPop(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check for conflicts after restoring stash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (await this.hasConflicts()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec('git rebase --abort', { ignoreError: true }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('Stash pop resulted in merge conflicts after rebase. Cannot proceed with push. ' + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Please resolve conflicts manually.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec('git rebase --abort', { ignoreError: true }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (err.message.indexOf('Resolve all conflicts manually') > -1 || err.message.indexOf('merge conflicts') > -1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.error('Conflict detected during rebase', { filename: __filename }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('Rebase conflicts detected. Please resolve conflicts manually and retry.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw err; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec(`git rebase origin/${remoteBranch}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec(`git push origin main:${remoteBranch}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_AUTHOR_NAME: committer.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_AUTHOR_EMAIL: committer.email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_COMMITTER_NAME: committer.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_COMMITTER_EMAIL: committer.email | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_SSH_COMMAND: sshParams?.privateKeyFile ? `ssh -i ${sanitize(sshParams.privateKeyFile)} -o StrictHostKeyChecking=no -o IdentitiesOnly=yes` : '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec('git rebase --abort', { ignoreError: true }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (err.message.indexOf('Resolve all conflicts manually') > -1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.error('Conflict', { filename: __filename }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If we stashed something and the operation failed, warn about it | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (stashed) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.warn('Push/rebase failed. Stashed changes remain saved. Use `git stash list` to view.', { filename: __filename }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw err; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec(`git push origin main:${remoteBranch}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GIT_SSH_COMMAND: sshParams?.privateKeyFile ? `ssh -i ${sanitize(sshParams.privateKeyFile)} -o StrictHostKeyChecking=no -o IdentitiesOnly=yes` : '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For other errors, just throw them | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw err; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -902,8 +927,9 @@ export class GitScanner { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ahead, behind | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // deno-lint-ignore no-empty | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (ignore) {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.warn(`Failed to count ahead/behind commits for branch ${remoteBranch}: ${err.message}`, { filename: __filename }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { ahead: 0, behind: 0 }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1013,4 +1039,64 @@ export class GitScanner { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.companionFileResolver = resolver; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private async getStashCount(): Promise<number> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const result = await this.exec('git stash list --format=%gd', { skipLogger: !this.debug }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const lines = result.stdout.trim().split('\n').filter(line => line.length > 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return lines.length; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async stashChanges(): Promise<boolean> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Capture the number of existing stash entries before attempting to stash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const beforeCount = await this.getStashCount(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.exec('git stash push -u -m "WikiGDrive auto-stash before sync"', { skipLogger: !this.debug }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If there's nothing to stash, git stash may report "No local changes to save" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // in the error output. In that case, report that no stash was created. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (err.message && err.message.includes('No local changes to save')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw err; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1052
to
+1061
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | |
| await this.exec('git stash push -u -m "WikiGDrive auto-stash before sync"', { skipLogger: !this.debug }); | |
| return true; | |
| } catch (err) { | |
| // If there's nothing to stash, git stash will return "No local changes to save" | |
| // Error message format: "Process exited with status: X\n" + stderr | |
| if (err.message && err.message.includes('No local changes to save')) { | |
| return false; | |
| } | |
| throw err; | |
| } | |
| // Capture the number of existing stash entries before attempting to stash. | |
| const beforeResult = await this.exec('git stash list --format=%gd', { skipLogger: !this.debug }); | |
| const beforeCount = beforeResult.stdout.trim().length === 0 | |
| ? 0 | |
| : beforeResult.stdout.trim().split('\n').length; | |
| try { | |
| await this.exec('git stash push -u -m "WikiGDrive auto-stash before sync"', { skipLogger: !this.debug }); | |
| } catch (err) { | |
| // If there's nothing to stash, git stash may report "No local changes to save" | |
| // in the error output. In that case, report that no stash was created. | |
| if (err.message && err.message.includes('No local changes to save')) { | |
| return false; | |
| } | |
| throw err; | |
| } | |
| // Re-count stash entries after the push to determine if a new stash was created. | |
| const afterResult = await this.exec('git stash list --format=%gd', { skipLogger: !this.debug }); | |
| const afterCount = afterResult.stdout.trim().length === 0 | |
| ? 0 | |
| : afterResult.stdout.trim().split('\n').length; | |
| return afterCount > beforeCount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improved to check git stash list before and after to reliably determine if a stash was created. Returns true only if stash count increased. Commit: 1d9aef4
Copilot
AI
Feb 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message pattern matching may not work as expected. Git's stderr output is appended after "Process exited with status: X\n" in the error message (see GitScanner.exec line 115). Consider checking if the message includes the pattern rather than using indexOf directly, or verify that the exact error message from git stash pop operations matches this pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed error message matching to account for "Process exited with status: X\n" + stderr format. Now using err.message.includes() which works correctly. Commit: 9b4386a
Copilot
AI
Feb 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stashPop() tries to detect conflicts by checking err.message.includes('CONFLICT'), but exec() throws errors that only include stderr (not stdout). If git reports conflict details on stdout, this check won’t trigger and callers will get a raw "Process exited..." error, and higher-level logic (e.g. conflict handling) won’t run. Consider (a) including stdout in the thrown error from exec(), or (b) in this catch block, run hasConflicts() after a non-zero exit and throw the friendly conflict error based on that instead of string-matching err.message.
| // If there's no stash to pop, handle gracefully | |
| // Error message format: "Process exited with status: X\n" + stderr | |
| if (err.message && err.message.includes('No stash entries found')) { | |
| return; | |
| } | |
| // Check if the error is due to merge conflicts | |
| if (err.message && err.message.includes('CONFLICT')) { | |
| throw new Error('Stash pop encountered merge conflicts. Please resolve conflicts manually.'); | |
| } | |
| const message = err instanceof Error ? err.message : String(err); | |
| // If there's no stash to pop, handle gracefully | |
| // Error message format: "Process exited with status: X\n" + stderr | |
| if (message.includes('No stash entries found')) { | |
| return; | |
| } | |
| // Check if the error is due to merge conflicts based on the error message | |
| if (message.includes('CONFLICT')) { | |
| throw new Error('Stash pop encountered merge conflicts. Please resolve conflicts manually.'); | |
| } | |
| // If the message did not explicitly mention conflicts, fall back to checking for unmerged files | |
| if (await this.hasConflicts()) { | |
| throw new Error('Stash pop encountered merge conflicts. Please resolve conflicts manually.'); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added fallback to hasConflicts() check after catching error. If error doesn't mention CONFLICT but unmerged files exist, throws clear conflict error. Commit: 1d9aef4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable ahead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now using
aheadvariable to check for diverged branches. Commit: b903ed8