Skip to content

Commit

Permalink
Merge pull request desktop#11549 from desktop/cherry-pick-git-no-conf…
Browse files Browse the repository at this point in the history
…ict-resolution

Cherry pick git no confict resolution
  • Loading branch information
tidy-dev committed Feb 9, 2021
2 parents a991d10 + 43736be commit 6ba93ba
Show file tree
Hide file tree
Showing 5 changed files with 389 additions and 1 deletion.
47 changes: 47 additions & 0 deletions app/src/lib/git/cherry-pick.ts
@@ -0,0 +1,47 @@
import { Repository } from '../../models/repository'
import { git, IGitResult } from './core'

/** The app-specific results from attempting to cherry pick commits*/
export enum CherryPickResult {
/**
* Git completed the cherry pick without reporting any errors, and the caller can
* signal success to the user.
*/
CompletedWithoutError = 'CompletedWithoutError',

/**
* An unexpected error as part of the cherry pick flow was caught and handled.
*
* Check the logs to find the relevant Git details.
*/
Error = 'Error',
}

/**
* A stub function to initiate cherry picking in the app.
*
* @param revisionRange - this could be a single commit sha or could be a range
* of commits like sha1..sha2 or inclusively sha1^..sha2
*/
export async function cherryPick(
repository: Repository,
revisionRange: string
): Promise<CherryPickResult> {
const result = await git(
['cherry-pick', revisionRange],
repository.path,
'cherry pick'
)

return parseCherryPickResult(result)
}

function parseCherryPickResult(result: IGitResult): CherryPickResult {
if (result.exitCode === 0) {
return CherryPickResult.CompletedWithoutError
}

// TODO: handle known exceptions

throw new Error(`Unhandled result found: '${JSON.stringify(result)}'`)
}
18 changes: 17 additions & 1 deletion app/src/lib/git/rev-list.ts
Expand Up @@ -7,7 +7,8 @@ import { CommitOneLine } from '../../models/commit'
/**
* Convert two refs into the Git range syntax representing the set of commits
* that are reachable from `to` but excluding those that are reachable from
* `from`.
* `from`. This will not be inclusive to the `from` ref, see
* `revRangeInclusive`.
*
* Each parameter can be the commit SHA or a ref name, or specify an empty
* string to represent HEAD.
Expand All @@ -19,6 +20,21 @@ export function revRange(from: string, to: string) {
return `${from}..${to}`
}

/**
* Convert two refs into the Git range syntax representing the set of commits
* that are reachable from `to` but excluding those that are reachable from
* `from`. However as opposed to `revRange`, this will also include `from` ref.
*
* Each parameter can be the commit SHA or a ref name, or specify an empty
* string to represent HEAD.
*
* @param from The start of the range
* @param to The end of the range
*/
export function revRangeInclusive(from: string, to: string) {
return `${from}^..${to}`
}

/**
* Convert two refs into the Git symmetric difference syntax, which represents
* the set of commits that are reachable from either `from` or `to` but not
Expand Down
13 changes: 13 additions & 0 deletions app/test/helpers/repositories.ts
Expand Up @@ -62,6 +62,19 @@ export async function setupEmptyRepository(): Promise<Repository> {
return new Repository(repoPath, -1, null, false)
}

/**
* Initializes a new, empty, git repository at in a temporary location with
* default branch of main.
*
* @returns the new local repository
*/
export async function setupEmptyRepositoryDefaultMain(): Promise<Repository> {
const repoPath = mkdirSync('desktop-empty-repo-')
await GitProcess.exec(['init', '-b', 'main'], repoPath)

return new Repository(repoPath, -1, null, false)
}

/**
* Initialize a new, empty folder that is incorrectly associated with a Git
* repository. This should only be used to test error handling of the Git
Expand Down
45 changes: 45 additions & 0 deletions app/test/helpers/repository-builder-cherry-pick-test.ts
@@ -0,0 +1,45 @@
import { Repository } from '../../src/models/repository'
import { setupEmptyRepositoryDefaultMain } from './repositories'
import { makeCommit, switchTo, createBranch } from './repository-scaffolding'

/**
* Creates a test repository to be used for testing cherry pick behaviour with:
* - one commit on default branch,
* - one commit on `featureBranchName` to cherry pick
* - creates `targetBranchName` off of default branch
*/
export async function createRepository(
featureBranchName: string,
targetBranchName: string
): Promise<Repository> {
const repository = await setupEmptyRepositoryDefaultMain()

const firstCommit = {
commitMessage: 'First!',
entries: [
{
path: 'README.md',
contents: '# HELLO WORLD! \n',
},
],
}
await makeCommit(repository, firstCommit)

await createBranch(repository, featureBranchName, 'HEAD')
await createBranch(repository, targetBranchName, 'HEAD')

await switchTo(repository, featureBranchName)
const featureBranchCommit = {
commitMessage: 'Cherry Picked Feature!',
entries: [
{
path: 'THING.md',
contents: '# HELLO WORLD! \nTHINGS GO HERE\n',
},
],
}
await makeCommit(repository, featureBranchCommit)

await switchTo(repository, targetBranchName)
return repository
}

0 comments on commit 6ba93ba

Please sign in to comment.