Skip to content

Commit 4ecd036

Browse files
v1.3.0 (#648)
* Live staging/unstaging updates on Git Graph (#640) * Fix for fetching local branches on linked worktrees returning root of main worktree * git-porcelain.hasStatus() added for checking for specific git status in files and directories * selectStagedFieldsByRepo selector added for obtaining partial Metafile fields related to VCS status * Git Graph automatically updates for staging/unstaging of files tracked under selected repository * Bump webpack from 5.67.0 to 5.68.0 (#629) Bumps [webpack](https://github.com/webpack/webpack) from 5.67.0 to 5.68.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](webpack/webpack@v5.67.0...v5.68.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Display Synectic version number in notification from Help menu (#642) * Bump css-loader from 6.5.1 to 6.6.0 (#630) Bumps [css-loader](https://github.com/webpack-contrib/css-loader) from 6.5.1 to 6.6.0. - [Release notes](https://github.com/webpack-contrib/css-loader/releases) - [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md) - [Commits](webpack/css-loader@v6.5.1...v6.6.0) --- updated-dependencies: - dependency-name: css-loader dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Dependency updates * Cloning updated to convert SSH URLs to HTTPS and properly resolve success/failure returns * Fix for resolving git refs in non-local off-main branches * Resolve linked worktree HEAD refs by following indicated ref path to refs/heads/{branch} * BranchStatus component checks for empty current repository root before checking out new branches * Repos Tracker renamed to Branch Tracker * Card selectors use RTK createSelector instead of RTK createDraftSafeSelector * Branch selectors use RTK createSelector instead of RTK createDraftSafeSelector * Branch Tracker properly displays card counts related to each tracked branch in a repository * branchSelectors.selectByRepo prefers local branches over remote branches * Dependency updates * v1.3.0 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 479806d commit 4ecd036

File tree

15 files changed

+786
-730
lines changed

15 files changed

+786
-730
lines changed

package.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "synectic",
33
"productName": "Synectic",
4-
"version": "1.2.0",
4+
"version": "1.3.0",
55
"description": "My Electron application description",
66
"main": ".webpack/main",
77
"scripts": {
@@ -41,8 +41,8 @@
4141
"@electron-forge/maker-squirrel": "^6.0.0-beta.63",
4242
"@electron-forge/plugin-webpack": "6.0.0-beta.63",
4343
"@testing-library/dom": "^8.11.3",
44-
"@testing-library/jest-dom": "^5.16.1",
45-
"@testing-library/react": "^12.1.2",
44+
"@testing-library/jest-dom": "^5.16.2",
45+
"@testing-library/react": "^12.1.3",
4646
"@testing-library/react-hooks": "^7.0.2",
4747
"@testing-library/user-event": "^13.5.0",
4848
"@types/dagre": "^0.7.47",
@@ -52,31 +52,31 @@
5252
"@types/ini": "^1.3.31",
5353
"@types/jest": "^27.4.0",
5454
"@types/luxon": "^2.0.9",
55-
"@types/node": "^17.0.13",
55+
"@types/node": "^17.0.18",
5656
"@types/pako": "^1.0.3",
5757
"@types/parse-git-config": "^3.0.1",
5858
"@types/parse-path": "^4.0.1",
59-
"@types/react": "^17.0.38",
59+
"@types/react": "^17.0.39",
6060
"@types/react-dom": "^17.0.11",
6161
"@types/react-transition-group": "^4.4.4",
6262
"@types/redux-mock-store": "^1.0.3",
6363
"@types/sha1": "^1.1.3",
6464
"@types/uuid": "^8.3.4",
6565
"@types/valid-url": "^1.0.3",
6666
"@types/validator": "^13.7.1",
67-
"@typescript-eslint/eslint-plugin": "^5.10.1",
68-
"@typescript-eslint/parser": "^5.10.1",
67+
"@typescript-eslint/eslint-plugin": "^5.12.0",
68+
"@typescript-eslint/parser": "^5.12.0",
6969
"@vercel/webpack-asset-relocator-loader": "1.7.0",
7070
"casual": "^1.6.2",
71-
"css-loader": "^6.5.1",
72-
"electron": "16.0.8",
73-
"eslint": "^8.8.0",
71+
"css-loader": "^6.6.0",
72+
"electron": "17.0.0",
73+
"eslint": "^8.9.0",
7474
"eslint-plugin-import": "^2.25.4",
7575
"file-loader": "^6.2.0",
76-
"fork-ts-checker-webpack-plugin": "^7.0.0",
76+
"fork-ts-checker-webpack-plugin": "^7.2.1",
7777
"git-remote-protocol": "^0.1.0",
7878
"identity-obj-proxy": "^3.0.0",
79-
"jest": "^27.4.7",
79+
"jest": "^27.5.1",
8080
"jest-serializer-path": "^0.1.15",
8181
"node-loader": "^2.0.0",
8282
"pako": "^2.0.4",
@@ -89,13 +89,13 @@
8989
"typescript": "^4.5.5",
9090
"valid-url": "^1.0.9",
9191
"validator": "^13.7.0",
92-
"webpack": "^5.67.0"
92+
"webpack": "^5.69.0"
9393
},
9494
"dependencies": {
9595
"@material-ui/core": "^4.12.3",
9696
"@material-ui/icons": "^4.11.2",
9797
"@material-ui/lab": "^4.0.0-alpha.60",
98-
"@reduxjs/toolkit": "^1.7.1",
98+
"@reduxjs/toolkit": "^1.7.2",
9999
"binarnia": "^3.1.3",
100100
"chokidar": "^3.5.3",
101101
"dagre": "^0.8.5",
@@ -105,7 +105,7 @@
105105
"git-config-path": "^2.0.0",
106106
"ignore": "^5.2.0",
107107
"ini": "^2.0.0",
108-
"isomorphic-git": "^1.11.1",
108+
"isomorphic-git": "^1.11.2",
109109
"luxon": "^2.3.0",
110110
"parse-git-config": "^3.0.0",
111111
"parse-path": "^4.0.3",
@@ -115,7 +115,7 @@
115115
"react-dnd-html5-backend": "^14.1.0",
116116
"react-dnd-preview": "^6.0.2",
117117
"react-dom": "^17.0.2",
118-
"react-flow-renderer": "^9.7.3",
118+
"react-flow-renderer": "^9.7.4",
119119
"react-redux": "^7.2.6",
120120
"react-transition-group": "^4.4.2",
121121
"redux": "^4.1.2",

src/components/CanvasComponent.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ const CanvasComponent: React.FunctionComponent = props => {
163163
{ label: 'Repository...', click: async () => { shell.openExternal('https://github.com/EPICLab/synectic/'); } },
164164
{ label: 'Release Notes...', click: async () => { shell.openExternal('https://github.com/EPICLab/synectic/releases'); } },
165165
{ label: 'View License...', click: async () => { shell.openExternal('https://github.com/EPICLab/synectic/blob/5ec51f6dc9dc857cae58c5253c3334c8f33a63c4/LICENSE'); } },
166+
{
167+
label: 'Version', click: () => dispatch(modalAdded({
168+
id: v4(), type: 'Notification',
169+
options: { 'message': `Synectic v${process.env.npm_package_version}` }
170+
}))
171+
}
166172
];
167173

168174
return (

src/components/SourceControl/CloneDialog.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const useStyles = makeStyles((theme: Theme) =>
5252
const CloneDialog: React.FunctionComponent<Modal> = props => {
5353
const classes = useStyles();
5454
const [url, setUrl] = useState('');
55-
const [invalid, setInvalid] = useState(false);
55+
const [invalid, setInvalid] = useState(true);
5656
const [targetPath, setTargetPath] = useState('');
5757
const [status, setStatus] = useState<Status>('Unchecked');
5858
const [log, setLog] = useState('');
@@ -74,11 +74,12 @@ const CloneDialog: React.FunctionComponent<Modal> = props => {
7474
const initiateCloning = async () => {
7575
try {
7676
setStatus('Running');
77-
await dispatch(cloneRepository({
78-
url: url,
77+
const repo = await dispatch(cloneRepository({
78+
url: new URL(url),
7979
root: targetPath,
8080
onProgress: (progress) => setLog(`cloning objects: ${progress.loaded}/${progress.total}`)
81-
}));
81+
})).unwrap();
82+
if (!repo) throw new Error('Cloning failed');
8283
setStatus('Passing');
8384
await dispatch(loadBranchVersions());
8485
await delay(2000);
@@ -87,7 +88,6 @@ const CloneDialog: React.FunctionComponent<Modal> = props => {
8788
setStatus('Failing');
8889
}
8990
}
90-
9191
if (targetPath !== '' && !invalid) initiateCloning();
9292
}, [targetPath]);
9393

@@ -124,7 +124,7 @@ const CloneDialog: React.FunctionComponent<Modal> = props => {
124124
<Typography color='textSecondary' variant='body2'>
125125
{status === 'Running' ? log : null}
126126
{status === 'Passing' ? `Clone completed from '${url}' to '${targetPath}'` : null}
127-
{status === 'Failing' ? `Existing repository at ${targetPath}` : null}
127+
{status === 'Failing' ? `Clone failed from '${url}' to '${targetPath}'` : null}
128128
</Typography>
129129
</div>
130130
</div>

src/components/SourceControl/ReposOverview.tsx

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,48 @@
11
import React from 'react';
22
import TreeView from '@material-ui/lab/TreeView';
3-
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
4-
import ArrowRightIcon from '@material-ui/icons/ArrowRight';
5-
import ErrorIcon from '@material-ui/icons/Error';
3+
import { ArrowDropDown, ArrowRight, Error } from '@material-ui/icons';
64
import { v4 } from 'uuid';
75
import type { Repository, Branch } from '../../types';
86
import { RootState } from '../../store/store';
9-
import { isDefined } from '../../containers/format';
107
import { StyledTreeItem } from '../StyledTreeComponent';
118
import { GitRepoIcon, GitBranchIcon } from '../GitIcons';
129
import { useAppDispatch, useAppSelector } from '../../store/hooks';
1310
import repoSelectors from '../../store/selectors/repos';
1411
import cardSelectors from '../../store/selectors/cards';
15-
import metafileSelectors from '../../store/selectors/metafiles';
1612
import { loadCard } from '../../store/thunks/handlers';
1713
import { checkoutBranch } from '../../store/thunks/repos';
18-
import { fetchMetafilesByFilepath } from '../../store/thunks/metafiles';
14+
import { fetchMetafile, fetchVersionControl, isFilebasedMetafile } from '../../store/thunks/metafiles';
1915
import branchSelectors from '../../store/selectors/branches';
20-
21-
const modifiedStatuses = ['modified', '*modified', 'deleted', '*deleted', 'added', '*added', '*absent', '*undeleted', '*undeletedmodified'];
16+
import { readDirAsync } from '../../containers/io';
17+
import { currentBranch } from '../../containers/git-porcelain';
18+
import { metafileUpdated } from '../../store/slices/metafiles';
2219

2320
const BranchStatus: React.FunctionComponent<{ repo: Repository, branch: Branch }> = props => {
2421
const cards = useAppSelector((state: RootState) => cardSelectors.selectByRepo(state, props.repo.id, props.branch.id));
25-
const metafiles = useAppSelector((state: RootState) => metafileSelectors.selectAll(state));
26-
const modified = cards.map(c => metafiles.find(m => m.id === c.metafile)).filter(isDefined).filter(m => m.status && modifiedStatuses.includes(m.status));
2722
const dispatch = useAppDispatch();
2823

2924
// load a new Explorer card containing the root of the repository at the specified branch
3025
const clickHandle = async () => {
3126
// undefined root indicates the main worktree, and any linked worktrees, are not associated with that branch
32-
if (props.branch.root) {
33-
dispatch(loadCard({ filepath: props.branch.root }));
34-
} else {
35-
const resultAction = await dispatch(fetchMetafilesByFilepath(props.repo.root));
36-
const updated = (fetchMetafilesByFilepath.fulfilled.match(resultAction))
37-
? await dispatch(checkoutBranch({ metafileId: metafiles[0].id, branchRef: props.branch.ref })).unwrap()
38-
: undefined;
39-
if (updated) {
40-
dispatch(loadCard({ metafile: updated }));
41-
}
27+
const directoryContent = (await readDirAsync(props.branch.root));
28+
const empty = directoryContent.length == 0 || (directoryContent.length == 1 && directoryContent.includes('.git')); // only a .git sub-directory counts as empty
29+
const current = await currentBranch({ dir: props.branch.root });
30+
let metafile = await dispatch(fetchMetafile({ filepath: props.branch.root })).unwrap();
31+
const vcs = isFilebasedMetafile(metafile) ? await dispatch(fetchVersionControl(metafile)).unwrap() : undefined;
32+
metafile = vcs ? dispatch(metafileUpdated({ ...metafile, ...vcs })).payload : metafile;
33+
const updated = (empty || props.branch.ref !== current)
34+
? await dispatch(checkoutBranch({ metafileId: metafile.id, branchRef: props.branch.ref })).unwrap()
35+
: metafile;
36+
if (updated) {
37+
dispatch(loadCard({ metafile: updated }));
4238
}
4339
}
4440

4541
return (
4642
<StyledTreeItem
4743
key={`${props.repo}-${props.branch.id}`}
4844
nodeId={`${props.repo}-${props.branch.id}`}
49-
labelText={`${props.branch.ref} [${modified.length}/${cards.length}]`}
45+
labelText={`${props.branch.ref} [${cards.length}]`}
5046
labelIcon={GitBranchIcon}
5147
onClick={clickHandle}
5248
/>
@@ -72,16 +68,16 @@ const ReposOverview: React.FunctionComponent = () => {
7268
return (
7369
<div className='version-tracker'>
7470
<TreeView
75-
defaultCollapseIcon={<ArrowDropDownIcon />}
76-
defaultExpandIcon={<ArrowRightIcon />}
71+
defaultCollapseIcon={<ArrowDropDown />}
72+
defaultExpandIcon={<ArrowRight />}
7773
defaultEndIcon={<div style={{ width: 8 }} />}
7874
expanded={expanded}
7975
onNodeToggle={handleToggle}
8076
>
8177
{repos.length == 0 &&
8278
<StyledTreeItem key={'no-repo'} nodeId={'no-repo'}
8379
labelText={'[no repos tracked]'}
84-
labelIcon={ErrorIcon}
80+
labelIcon={Error}
8581
/>
8682
}
8783
{repos.length > 0 && repos.map(repo => <RepoStatusComponent key={repo.id} repo={repo} />)}

src/containers/branch-tracker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const loadBranchVersions = createAsyncThunk<void, void, AppThunkAPI>(
1212
virtual: {
1313
id: v4(),
1414
modified: DateTime.local().valueOf(),
15-
name: 'Repos Tracker', handler: 'ReposTracker'
15+
name: 'Branch Tracker', handler: 'ReposTracker'
1616
}
1717
}))
1818
.unwrap()

src/containers/git-plumbing.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,13 @@ export const resolveRef = async ({ dir, gitdir = path.join(dir.toString(), '.git
113113
ref: string;
114114
depth?: number;
115115
}): Promise<string> => {
116-
const worktree = await getWorktreePaths(gitdir);
116+
const worktree = await getWorktreePaths(dir);
117117
const optional = removeUndefinedProperties({ depth: depth });
118-
const updatedRef = (worktree.worktreeLink && ref === 'HEAD') ? (await io.readFileAsync(path.join(worktree.worktreeLink.toString(), 'HEAD'), { encoding: 'utf-8' })).trim() : ref;
119-
120-
return (worktree.dir && worktree.gitdir)
121-
? isogit.resolveRef({ fs: fs, dir: worktree.dir.toString(), gitdir: worktree.gitdir.toString(), ref: updatedRef, ...optional })
122-
: isogit.resolveRef({ fs: fs, dir: dir.toString(), gitdir: gitdir.toString(), ref: ref, ...optional });
118+
if (worktree.gitdir && worktree.worktreeLink && ref === 'HEAD') {
119+
const linkedRef = (await io.readFileAsync(path.join(worktree.worktreeLink.toString(), 'HEAD'), { encoding: 'utf-8' })).slice('ref: '.length).trim();
120+
return (await io.readFileAsync(path.join(worktree.gitdir.toString(), linkedRef), { encoding: 'utf-8' })).trim();
121+
}
122+
return await isogit.resolveRef({ fs: fs, dir: dir.toString(), gitdir: gitdir.toString(), ref: ref, ...optional });
123123
}
124124

125125
/**

src/containers/git-porcelain.ts

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import { getProperty, setProperty, hasProperty, deleteProperty } from 'dot-prop'
88
import getGitConfigPath from 'git-config-path';
99
import type { Repository, GitStatus } from '../types';
1010
import * as io from './io';
11-
import { matrixEntry, statusMatrix } from './git-plumbing';
12-
import { removeUndefinedProperties } from './format';
11+
import { matrixEntry, matrixToStatus, statusMatrix } from './git-plumbing';
12+
import { isDefined, removeUndefinedProperties } from './format';
1313
import { getWorktreePaths } from './git-path';
1414

1515
export type GitConfig = { scope: 'none' } | { scope: 'local' | 'global', value: string, origin?: string };
@@ -38,8 +38,8 @@ export const resolveRef = async (dir: fs.PathLike, ref: string): Promise<string
3838
* Clone a repository; this function is a wrapper to the *isomorphic-git/clone* function to inject the `fs` parameter and extend with
3939
* additional local-only branch functionality. If the `ref` parameter or the current branch do not exist on the remote repository, then the
4040
* local-only repository (including the *.git* directory) is copied using the *fs.copy* function (excluding the `node_modules` directory).
41-
* @param repo A Repository object to be cloned.
4241
* @param dir The worktree root directory to contain the cloned repo.
42+
* @param repo A Repository object to be cloned.
4343
* @param ref An optional branch name or SHA-1 hash to target cloning to that specific branch or commit.
4444
* @param singleBranch Instead of the default behavior of fetching all the branches, only fetch a single branch.
4545
* @param noCheckout Only fetch the repo without checking out a branch. Skipping checkout can save a lot of time normally spent writing
@@ -49,35 +49,53 @@ export const resolveRef = async (dir: fs.PathLike, ref: string): Promise<string
4949
* @param exclude A list of branches or tags which should be excluded from remote server responses; specifically any commits reachable
5050
* from these refs will be excluded.
5151
* @param onProgress Callback for listening to GitProgressEvent occurrences during cloning.
52-
* @return A Promise object for the clone operation.
52+
* @return A Promise object containing a boolean representing success/failure of the cloning operation.
5353
*/
54-
export const clone = async ({ repo, dir, ref, singleBranch = false, noCheckout = false, noTags = false, depth, exclude, onProgress }: {
55-
repo: Repository;
54+
export const clone = async ({ dir, url, repo, ref, singleBranch = false, noCheckout = false, noTags = false, depth, exclude, onProgress }: {
5655
dir: fs.PathLike;
56+
url?: URL;
57+
repo?: Repository;
5758
ref?: string;
5859
singleBranch?: boolean;
5960
noCheckout?: boolean;
6061
noTags?: boolean;
6162
depth?: number;
6263
exclude?: string[];
6364
onProgress?: isogit.ProgressCallback | undefined;
64-
}): Promise<void> => {
65-
const optionals = removeUndefinedProperties({ depth: depth, exclude: exclude, onProgress: onProgress });
66-
const worktree = await getWorktreePaths(repo.root);
67-
const existingBranch = worktree.dir ? await currentBranch({ dir: worktree.dir, fullname: false }) : undefined;
68-
const targetBranch = ref ? ref : existingBranch;
69-
const remoteBranches = worktree.dir ? await isogit.listBranches({ fs: fs, dir: worktree.dir.toString(), remote: 'origin' }) : [];
65+
}): Promise<boolean> => {
66+
const optionals = removeUndefinedProperties({ ref, depth, exclude, onProgress });
67+
if (dir.toString().length == 0) return false;
7068

71-
if (targetBranch && !remoteBranches.includes(targetBranch)) {
72-
await fs.copy(repo.root.toString(), dir.toString(), { filter: path => !(path.indexOf('node_modules') > -1) }); // do not copy node_modules/ directory
73-
if (targetBranch !== existingBranch)
69+
if (url) {
70+
// cloning a new repository from remote URL
71+
await isogit.clone({
72+
fs: fs, http: http, dir: dir.toString(), url: url.toString(), singleBranch: singleBranch, noCheckout: noCheckout,
73+
noTags: noTags, ...optionals
74+
});
75+
return true;
76+
}
77+
78+
if (repo) {
79+
const worktree = await getWorktreePaths(repo.root);
80+
const existingBranch = worktree.dir ? await currentBranch({ dir: worktree.dir, fullname: false }) : undefined;
81+
const remoteBranches = worktree.dir ? await isogit.listBranches({ fs: fs, dir: worktree.dir.toString(), remote: 'origin' }) : [];
82+
const targetBranch = ref ? ref : existingBranch;
83+
84+
if (targetBranch && !remoteBranches.includes(targetBranch)) {
85+
// cloning a local-only branch via copy & checkout
86+
await fs.copy(repo.root.toString(), dir.toString(), { filter: path => !(path.indexOf('node_modules') > -1) }); // do not copy node_modules/ directory
7487
await checkout({ dir: dir, ref: targetBranch, noCheckout: noCheckout });
75-
return;
88+
return true;
89+
} else {
90+
// cloning an existing repository into a linked worktree root directory
91+
await isogit.clone({
92+
fs: fs, http: http, dir: dir.toString(), url: repo.url, singleBranch: singleBranch, noCheckout: noCheckout,
93+
noTags: noTags, ...optionals
94+
});
95+
return true;
96+
}
7697
}
77-
return isogit.clone({
78-
fs: fs, http: http, dir: dir.toString(), url: repo.url, singleBranch: singleBranch, noCheckout: noCheckout,
79-
noTags: noTags, ...optionals
80-
});
98+
return false;
8199
};
82100

83101
/**
@@ -283,6 +301,26 @@ export const getStatus = async (filepath: fs.PathLike): Promise<GitStatus | unde
283301
return matrixEntry(filepath);
284302
}
285303

304+
/**
305+
* Checks the git tracking status of a specific file or directory path for matches against a set of status filters. If the file is
306+
* tracked by a branch in a linked worktree then status checks will look at the index file in the `GIT_DIR/worktrees/{branch}` directory
307+
* for determining HEAD, WORKDIR, and STAGE status codes. Status codes are translated into comparable `GitStatus` type before comparison
308+
* with the provided status filters.
309+
* @param filepath The relative or absolute path to evaluate.
310+
* @param statusFilters Array of `GitStatus` values to check against.
311+
* @return A Promise object containing false if the path is not contained within a directory under version control, or a boolean
312+
* indicating whether any file or files matched at least one of the `GitStatus` values in the provided status filter.
313+
*/
314+
export const hasStatus = async (filepath: fs.PathLike, statusFilters: GitStatus[]): Promise<boolean> => {
315+
const statuses = await statusMatrix(filepath);
316+
const found: GitStatus[] = statuses ? statuses
317+
.map(row => matrixToStatus({ matrixEntry: row }))
318+
.filter(isDefined)
319+
.filter(status => statusFilters.includes(status))
320+
: [];
321+
return (found.length > 0) ? true : false;
322+
}
323+
286324
/**
287325
* List a remote servers branches, tags, and capabilities; this function is a wrapper to inject the `fs` parameter in to the
288326
* *isomorphic-git/getRemoteInfo* function.

0 commit comments

Comments
 (0)