Skip to content

Commit 02efcea

Browse files
committed
safe delete branch
1 parent 7ad5c2d commit 02efcea

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

src/env/node/git/git.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1622,7 +1622,11 @@ export class Git {
16221622
async rev_list(
16231623
repoPath: string,
16241624
ref: string,
1625-
options?: { all?: boolean; maxParents?: number },
1625+
options?: {
1626+
all?: boolean;
1627+
maxParents?: number;
1628+
maxResults?: number;
1629+
},
16261630
): Promise<string[] | undefined> {
16271631
const params = ['rev-list'];
16281632
if (options?.all) {
@@ -1633,6 +1637,10 @@ export class Git {
16331637
params.push(`--max-parents=${options.maxParents}`);
16341638
}
16351639

1640+
if (options?.maxResults != null) {
1641+
params.push(`-n ${options.maxResults}`);
1642+
}
1643+
16361644
const rawData = await this.git<string>(
16371645
{ cwd: repoPath, errors: GitErrorHandling.Ignore },
16381646
...params,
@@ -1898,6 +1906,10 @@ export class Git {
18981906
return data.length === 0 ? undefined : data.trim();
18991907
}
19001908

1909+
async update_ref(repoPath: string, ...args: string[]): Promise<void> {
1910+
await this.git<string>({ cwd: repoPath }, 'update-ref', ...args);
1911+
}
1912+
19011913
show(
19021914
repoPath: string,
19031915
options?: { cancellation?: CancellationToken; configs?: readonly string[] },

src/env/node/git/localGitProvider.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,8 +1287,6 @@ export class LocalGitProvider implements GitProvider, Disposable {
12871287
args.push('--force');
12881288
}
12891289

1290-
await this.git.branch(repoPath, ...args, ...branches.map((b: GitBranchReference) => b.ref));
1291-
12921290
if (options.remote) {
12931291
const trackingBranches = localBranches.filter(b => b.upstream != null);
12941292
if (trackingBranches.length !== 0) {
@@ -1297,17 +1295,43 @@ export class LocalGitProvider implements GitProvider, Disposable {
12971295
);
12981296

12991297
for (const [remote, branches] of branchesByOrigin.entries()) {
1300-
await this.git.push(repoPath, {
1301-
delete: {
1302-
remote: remote,
1303-
branches: branches.map(b => getBranchNameWithoutRemote(b.upstream!.name)),
1304-
},
1298+
const remoteCommitByBranch: Map<string, string> = {};
1299+
branches.forEach(async b => {
1300+
remoteCommit = await this.git.rev_list(repoPath, `refs/remotes/${remote}/${b.ref}`, {
1301+
maxResults: 1,
1302+
});
1303+
remoteCommitByBranch[b.ref] = remoteCommit;
13051304
});
1305+
1306+
await this.git.branch(
1307+
repoPath,
1308+
'--delete',
1309+
'--remotes',
1310+
...branches.map((b: GitBranchReference) => `${remote}/${b.ref}`),
1311+
);
1312+
1313+
try {
1314+
await this.git.branch(repoPath, ...args, ...branches.map((b: GitBranchReference) => b.ref));
1315+
await this.git.push(repoPath, {
1316+
delete: {
1317+
remote: remote,
1318+
branches: branches.map(b => getBranchNameWithoutRemote(b.upstream!.name)),
1319+
},
1320+
});
1321+
} catch (ex) {
1322+
// If it fails, restore the remote branches
1323+
remoteCommitByBranch.forEach(async (branch, commit) => {
1324+
await this.git.update_ref(repoPath, `refs/remotes/${remote}/${branch}`, commit);
1325+
await this.git.branch__set_upstream(repoPath, branch, remote, branch);
1326+
});
1327+
throw ex;
1328+
}
13061329
}
13071330
}
13081331
}
13091332
}
13101333

1334+
const remoteBranches = branches.filter((b: GitBranchReference) => b.remote);
13111335
if (remoteBranches.length !== 0) {
13121336
const branchesByOrigin = groupByMap(remoteBranches, b => getRemoteNameFromBranchName(b.name));
13131337

0 commit comments

Comments
 (0)