From 31a1203a7599b097fa93b16bdd32f4e16874183c Mon Sep 17 00:00:00 2001 From: Asier Llano Date: Tue, 28 Mar 2023 12:12:18 +0200 Subject: [PATCH] Add intelligence to detected branch when dettached Previous version only looked at local branches, and looking at the last commit hash of each branch. The idea is to look at all branches that contain the specific commit. It can be done with the command "git branch --constains" command. This way the command is much more intelligent. It has been tested extensively with out repositories and worked smoothly in several situations where previously couldn't detect the proper branch. --- src/application/GitRepository.ts | 32 ++++++++++++ .../DetectDetachedHead.handler.ts | 49 +++++++++---------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/src/application/GitRepository.ts b/src/application/GitRepository.ts index e7e5834..6b01747 100644 --- a/src/application/GitRepository.ts +++ b/src/application/GitRepository.ts @@ -4,6 +4,7 @@ import { join } from 'path' import { readFile } from 'fs' import Git from '../models/Git' import Submodule from '../models/Submodule' +import Branch from '../models/Branch' import Logger from '../UI/Logger' import Status from '../UI/Status' import StatusBar from '../UI/StatusBar' @@ -470,6 +471,37 @@ export default class GitRepository { }) } + /** + * Get the list of branches that conatining current commit + * @param gitModel Git-Model of Submodule + */ + static async getBranchesContain(gitModel: Git): Promise { + let simplegit = GitRepository.getSimplegit(gitModel.getRelativePath()) + const branches_local = await simplegit.branch(['--contains', gitModel.getBranch()]) + const branches_remote = await simplegit.branch(['--remote', '--contains', gitModel.getBranch()]) + let branches : Branch[] = [] + let branches_local_names : string[] = [] + let discardfirst : boolean = branches_local.detached + branches_local.all.forEach((key: any) => { + // Discard the first local branch if detached (it is our detached branch) + if (discardfirst) { + discardfirst = false + } else { + branches.push(new Branch(branches_local.branches[key].name, branches_local.branches[key].commit)) + branches_local_names.push(branches_local.branches[key].name) + } + }) + branches_remote.all.forEach((key: any) => { + // Get the branch name by removing the first part before slash which is the origin + let name = branches_remote.branches[key].name.split("/",2)[1] + // Make sure that we don't add twice a remote branch and local branch + if (!branches_local_names.includes(name)) { + branches.push(new Branch(name, branches_remote.branches[key].commit)) + } + }) + return branches + } + /*******************************************************************************************/ /* PULL */ /*******************************************************************************************/ diff --git a/src/handlers/git/branch_changed/DetectDetachedHead.handler.ts b/src/handlers/git/branch_changed/DetectDetachedHead.handler.ts index 0bcd3bb..ad05eb3 100644 --- a/src/handlers/git/branch_changed/DetectDetachedHead.handler.ts +++ b/src/handlers/git/branch_changed/DetectDetachedHead.handler.ts @@ -66,44 +66,41 @@ export default class DetectDetachedHead extends ChangeHandler { * finds the corresponding Branch for a Commit-Hash */ private static getRealBranchForHash = async (gitModel: Git): Promise => { - // the first one in the list is the current "detached HEAD" - const branches = gitModel.getLocalBranches().filter((branch, index) => index > 1) - const current = gitModel.getBranch() - - const realBranches: string[] = [] - branches.forEach((branch: Branch) => { - if (current === branch.getCommit() || current === branch.getName()) { - realBranches.push(branch.getName()) - } - }) - - if (realBranches.length) { - if (realBranches.length === 1) { - return realBranches[0] - } - + // Get the list of branches that contain the specified commit + const branches = await GitRepository.getBranchesContain(gitModel) + // If there is only one, we have found it + if (branches.length === 1) { + return branches[0].getName() + } + // Otherwise, if we have many options ... + if (branches.length) { + // Create a list with the branches names + const branches_names: string[] = [] + branches.forEach((branch: Branch) => { + branches_names.push(branch.getName()) + }) + // Check if any of them match with the configured one in .gitmodules if (gitModel.getMainRepositoryPath()) { const configuredBranch = await GitRepository.getConfiguredBranchForSubmodule(gitModel) - if (configuredBranch && realBranches.includes(configuredBranch)) { + if (configuredBranch && branches_names.includes(configuredBranch)) { return configuredBranch } - - const options: QuickPickOption[] = realBranches.map((branch) => new QuickPickOption(branch, branch)) - - const selectedBranch = await QuickPick.showQuickPick('choose the branch to check out', ...options) - if (selectedBranch) { - return selectedBranch - } + } + // Otherwise ask the user + const options: QuickPickOption[] = branches_names.map((branch) => new QuickPickOption(branch, branch)) + const selectedBranch = await QuickPick.showQuickPick('choose the branch to check out', ...options) + if (selectedBranch) { + return selectedBranch } } - + // If no branch contains the current commit, just warn the user + const current = gitModel.getBranch() Logger.showError( `could not find branch for '${current}' ${ !gitModel.isRootGit() ? ` in Submodule '${gitModel.getRelativePath()}'` : '' }. You have to checkout the branch manually.`, true, ) - return '' } }