mirror of
https://github.com/desktop/desktop
synced 2024-09-19 16:12:20 +00:00
Move discardChanges git method to apply.ts
We use the first argument of the git command as the name of the file
This commit is contained in:
parent
f5086a9b71
commit
93a7f3269d
|
@ -4,10 +4,10 @@ import {
|
|||
WorkingDirectoryFileChange,
|
||||
AppFileStatusKind,
|
||||
} from '../../models/status'
|
||||
import { DiffType } from '../../models/diff'
|
||||
import { DiffType, ITextDiff, DiffSelection } from '../../models/diff'
|
||||
import { Repository, WorkingTree } from '../../models/repository'
|
||||
import { getWorkingDirectoryDiff } from './diff'
|
||||
import { formatPatch } from '../patch-formatter'
|
||||
import { formatPatch, formatPatchToDiscardChanges } from '../patch-formatter'
|
||||
|
||||
export async function applyPatchToIndex(
|
||||
repository: Repository,
|
||||
|
@ -100,3 +100,39 @@ export async function checkPatch(
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards the local changes for the specified file based on the passed diff
|
||||
* and a selection of lines from it.
|
||||
*
|
||||
* When passed an empty selection, this method won't do anything. When passed a
|
||||
* full selection, all changes from the file will be discarded.
|
||||
*
|
||||
* @param repository The repository in which to update the working directory
|
||||
* with information from the index
|
||||
*
|
||||
* @param filePath The relative path in the working directory of the file to use
|
||||
*
|
||||
* @param diff The diff containing the file local changes
|
||||
*
|
||||
* @param selection The selection of changes from the diff to discard
|
||||
*/
|
||||
export async function discardChangesFromSelection(
|
||||
repository: Repository,
|
||||
filePath: string,
|
||||
diff: ITextDiff,
|
||||
selection: DiffSelection
|
||||
) {
|
||||
const patch = formatPatchToDiscardChanges(filePath, diff, selection)
|
||||
|
||||
if (patch === null) {
|
||||
// When the patch is null we don't need to apply it since it will be a noop.
|
||||
return
|
||||
}
|
||||
|
||||
const args = ['apply', '--unidiff-zero', '--whitespace=nowarn', '-']
|
||||
|
||||
await git(args, repository.path, 'discardChangesFromSelection', {
|
||||
stdin: patch,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import { git } from './core'
|
||||
import { Repository } from '../../models/repository'
|
||||
import { DiffSelection, ITextDiff } from '../../models/diff'
|
||||
import { formatPatchToDiscardChanges } from '../patch-formatter'
|
||||
|
||||
/**
|
||||
* Discards the local changes for the specified file based on the passed diff
|
||||
* and a selection of lines from it.
|
||||
*
|
||||
* When passed an empty selection, this method won't do anything. When passed a
|
||||
* full selection, all changes from the file will be discarded.
|
||||
*
|
||||
* @param repository The repository in which to update the working directory
|
||||
* with information from the index
|
||||
*
|
||||
* @param filePath The relative path in the working directory of the file to use
|
||||
*
|
||||
* @param diff The diff containing the file local changes
|
||||
*
|
||||
* @param selection The selection of changes from the diff to discard
|
||||
*/
|
||||
export async function discardChangesFromSelection(
|
||||
repository: Repository,
|
||||
filePath: string,
|
||||
diff: ITextDiff,
|
||||
selection: DiffSelection
|
||||
) {
|
||||
const patch = formatPatchToDiscardChanges(filePath, diff, selection)
|
||||
|
||||
if (patch === null) {
|
||||
// When the patch is null we don't need to apply it since it will be a noop.
|
||||
return
|
||||
}
|
||||
|
||||
const args = ['apply', '--unidiff-zero', '--whitespace=nowarn', '-']
|
||||
|
||||
await git(args, repository.path, 'discardChangesFromSelection', {
|
||||
stdin: patch,
|
||||
})
|
||||
}
|
|
@ -35,4 +35,3 @@ export * from './rebase'
|
|||
export * from './format-patch'
|
||||
export * from './worktree'
|
||||
export * from './tag'
|
||||
export * from './discard-changes'
|
||||
|
|
|
@ -1,14 +1,34 @@
|
|||
import { GitProcess } from 'dugite'
|
||||
import { setupTwoCommitRepo } from '../../helpers/repositories'
|
||||
import {
|
||||
setupTwoCommitRepo,
|
||||
setupFixtureRepository,
|
||||
} from '../../helpers/repositories'
|
||||
import { Repository } from '../../../src/models/repository'
|
||||
import { checkPatch } from '../../../src/lib/git'
|
||||
import {
|
||||
checkPatch,
|
||||
getWorkingDirectoryDiff,
|
||||
discardChangesFromSelection,
|
||||
} from '../../../src/lib/git'
|
||||
import {
|
||||
cloneLocalRepository,
|
||||
makeCommit,
|
||||
} from '../../helpers/repository-scaffolding'
|
||||
import {
|
||||
WorkingDirectoryFileChange,
|
||||
AppFileStatusKind,
|
||||
} from '../../../src/models/status'
|
||||
import {
|
||||
DiffSelection,
|
||||
DiffSelectionType,
|
||||
ITextDiff,
|
||||
} from '../../../src/models/diff'
|
||||
import { findInteractiveDiffRange } from '../../../src/ui/diff/diff-explorer'
|
||||
import { diffStringsUnified } from 'jest-diff'
|
||||
import * as FSE from 'fs-extra'
|
||||
import * as Path from 'path'
|
||||
|
||||
describe('git/apply', () => {
|
||||
describe('checkPatch', () => {
|
||||
describe('checkPatch()', () => {
|
||||
describe('on related repository without conflicts', () => {
|
||||
let repository: Repository
|
||||
let patch: string
|
||||
|
@ -48,4 +68,212 @@ describe('git/apply', () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('discardChangesFromSelection()', () => {
|
||||
let repository: Repository
|
||||
let testRepoPath: string
|
||||
|
||||
async function getDiff(filePath: string) {
|
||||
const file = new WorkingDirectoryFileChange(
|
||||
filePath,
|
||||
{ kind: AppFileStatusKind.Modified },
|
||||
DiffSelection.fromInitialSelection(DiffSelectionType.None)
|
||||
)
|
||||
return (await getWorkingDirectoryDiff(repository, file)) as ITextDiff
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
testRepoPath = await setupFixtureRepository('repo-with-changes')
|
||||
repository = new Repository(testRepoPath, -1, null, false)
|
||||
})
|
||||
|
||||
it('does not change the file when an empty selection is passed', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const previousDiff = await getDiff(filePath)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
previousDiff,
|
||||
DiffSelection.fromInitialSelection(DiffSelectionType.None)
|
||||
)
|
||||
|
||||
const diff = await getDiff(filePath)
|
||||
|
||||
expect(diff.text).toEqual(previousDiff.text)
|
||||
})
|
||||
|
||||
it('discards all file changes when a full selection is passed', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
DiffSelection.fromInitialSelection(DiffSelectionType.All)
|
||||
)
|
||||
|
||||
const diff = await getDiff(filePath)
|
||||
|
||||
// Check that the file has no local changes.
|
||||
expect(diff.text).toEqual('')
|
||||
expect(diff.hunks).toEqual([])
|
||||
})
|
||||
|
||||
it('re-adds a single removed line', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withLineSelection(4, true)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
selection
|
||||
)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -7,0 +7,1 @@
|
||||
+ Aliquam leo ipsum, laoreet sed libero at, mollis pulvinar arcu. Nullam porttitor"
|
||||
`)
|
||||
})
|
||||
|
||||
it('re-adds a removed hunk', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const diff = await getDiff(filePath)
|
||||
const hunkRange = findInteractiveDiffRange(diff.hunks, 4)
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withRangeSelection(
|
||||
hunkRange!.from,
|
||||
hunkRange!.to - hunkRange!.from + 1,
|
||||
true
|
||||
)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(repository, filePath, diff, selection)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -7,0 +7,4 @@
|
||||
+ Aliquam leo ipsum, laoreet sed libero at, mollis pulvinar arcu. Nullam porttitor
|
||||
+ nisl eget hendrerit vestibulum. Curabitur ornare id neque ac tristique. Cras in
|
||||
+ eleifend mi.
|
||||
+"
|
||||
`)
|
||||
})
|
||||
|
||||
it('removes an added line', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withLineSelection(16, true)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
selection
|
||||
)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -21,1 +21,0 @@
|
||||
- nisl eget hendrerit vestibulum. Curabitur ornare id neque ac tristique. Cras in"
|
||||
`)
|
||||
})
|
||||
|
||||
it('removes an added hunk', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const diff = await getDiff(filePath)
|
||||
const hunkRange = findInteractiveDiffRange(diff.hunks, 16)
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withRangeSelection(
|
||||
hunkRange!.from,
|
||||
hunkRange!.to - hunkRange!.from + 1,
|
||||
true
|
||||
)
|
||||
|
||||
console.log('diff', hunkRange)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
selection
|
||||
)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -20,4 +20,0 @@
|
||||
- Aliquam leo ipsum, laoreet sed libero at, mollis pulvinar arcu. Nullam porttitor
|
||||
- nisl eget hendrerit vestibulum. Curabitur ornare id neque ac tristique. Cras in
|
||||
- eleifend mi.
|
||||
-"
|
||||
`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const noColor = (str: string) => str
|
||||
|
||||
/**
|
||||
* Returns a diff-style string with the line differences between two strings.
|
||||
*/
|
||||
function getDifference(before: string, after: string) {
|
||||
return diffStringsUnified(
|
||||
before.replace(/\r\n/g, '\n'),
|
||||
after.replace(/\r\n/g, '\n'),
|
||||
{
|
||||
omitAnnotationLines: true,
|
||||
contextLines: 0,
|
||||
expand: false,
|
||||
aColor: noColor,
|
||||
bColor: noColor,
|
||||
changeColor: noColor,
|
||||
commonColor: noColor,
|
||||
patchColor: noColor,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,228 +0,0 @@
|
|||
/* eslint-disable no-sync */
|
||||
import { Repository } from '../../../src/models/repository'
|
||||
import { setupFixtureRepository } from '../../helpers/repositories'
|
||||
import {
|
||||
DiffSelection,
|
||||
DiffSelectionType,
|
||||
ITextDiff,
|
||||
} from '../../../src/models/diff'
|
||||
import {
|
||||
WorkingDirectoryFileChange,
|
||||
AppFileStatusKind,
|
||||
} from '../../../src/models/status'
|
||||
import {
|
||||
getWorkingDirectoryDiff,
|
||||
discardChangesFromSelection,
|
||||
} from '../../../src/lib/git'
|
||||
import * as FSE from 'fs-extra'
|
||||
import * as Path from 'path'
|
||||
import { findInteractiveDiffRange } from '../../../src/ui/diff/diff-explorer'
|
||||
import { diffStringsUnified } from 'jest-diff'
|
||||
|
||||
describe('discardChangesFromSelection()', () => {
|
||||
let repository: Repository
|
||||
let testRepoPath: string
|
||||
|
||||
async function getDiff(filePath: string) {
|
||||
const file = new WorkingDirectoryFileChange(
|
||||
filePath,
|
||||
{ kind: AppFileStatusKind.Modified },
|
||||
DiffSelection.fromInitialSelection(DiffSelectionType.None)
|
||||
)
|
||||
return (await getWorkingDirectoryDiff(repository, file)) as ITextDiff
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
testRepoPath = await setupFixtureRepository('repo-with-changes')
|
||||
repository = new Repository(testRepoPath, -1, null, false)
|
||||
})
|
||||
|
||||
it('does not change the file when an empty selection is passed', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const previousDiff = await getDiff(filePath)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
previousDiff,
|
||||
DiffSelection.fromInitialSelection(DiffSelectionType.None)
|
||||
)
|
||||
|
||||
const diff = await getDiff(filePath)
|
||||
|
||||
expect(diff.text).toEqual(previousDiff.text)
|
||||
})
|
||||
|
||||
it('discards all file changes when a full selection is passed', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
DiffSelection.fromInitialSelection(DiffSelectionType.All)
|
||||
)
|
||||
|
||||
const diff = await getDiff(filePath)
|
||||
|
||||
// Check that the file has no local changes.
|
||||
expect(diff.text).toEqual('')
|
||||
expect(diff.hunks).toEqual([])
|
||||
})
|
||||
|
||||
it('re-adds a single removed line', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withLineSelection(4, true)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
selection
|
||||
)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -7,0 +7,1 @@
|
||||
+ Aliquam leo ipsum, laoreet sed libero at, mollis pulvinar arcu. Nullam porttitor"
|
||||
`)
|
||||
})
|
||||
|
||||
it('re-adds a removed hunk', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const diff = await getDiff(filePath)
|
||||
const hunkRange = findInteractiveDiffRange(diff.hunks, 4)
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withRangeSelection(
|
||||
hunkRange!.from,
|
||||
hunkRange!.to - hunkRange!.from + 1,
|
||||
true
|
||||
)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(repository, filePath, diff, selection)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -7,0 +7,4 @@
|
||||
+ Aliquam leo ipsum, laoreet sed libero at, mollis pulvinar arcu. Nullam porttitor
|
||||
+ nisl eget hendrerit vestibulum. Curabitur ornare id neque ac tristique. Cras in
|
||||
+ eleifend mi.
|
||||
+"
|
||||
`)
|
||||
})
|
||||
|
||||
it('removes an added line', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withLineSelection(16, true)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
selection
|
||||
)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -21,1 +21,0 @@
|
||||
- nisl eget hendrerit vestibulum. Curabitur ornare id neque ac tristique. Cras in"
|
||||
`)
|
||||
})
|
||||
|
||||
it('removes an added hunk', async () => {
|
||||
const filePath = 'modified-file.md'
|
||||
const diff = await getDiff(filePath)
|
||||
const hunkRange = findInteractiveDiffRange(diff.hunks, 16)
|
||||
const selection = DiffSelection.fromInitialSelection(
|
||||
DiffSelectionType.None
|
||||
).withRangeSelection(
|
||||
hunkRange!.from,
|
||||
hunkRange!.to - hunkRange!.from + 1,
|
||||
true
|
||||
)
|
||||
|
||||
console.log('diff', hunkRange)
|
||||
|
||||
const previousContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
await discardChangesFromSelection(
|
||||
repository,
|
||||
filePath,
|
||||
await getDiff(filePath),
|
||||
selection
|
||||
)
|
||||
|
||||
const fileContents = await FSE.readFile(
|
||||
Path.join(repository.path, filePath),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(getDifference(previousContents, fileContents))
|
||||
.toMatchInlineSnapshot(`
|
||||
"@@ -20,4 +20,0 @@
|
||||
- Aliquam leo ipsum, laoreet sed libero at, mollis pulvinar arcu. Nullam porttitor
|
||||
- nisl eget hendrerit vestibulum. Curabitur ornare id neque ac tristique. Cras in
|
||||
- eleifend mi.
|
||||
-"
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
const noColor = (str: string) => str
|
||||
|
||||
/**
|
||||
* Returns a diff-style string with the line differences between two strings.
|
||||
*/
|
||||
function getDifference(before: string, after: string) {
|
||||
return diffStringsUnified(
|
||||
before.replace(/\r\n/g, '\n'),
|
||||
after.replace(/\r\n/g, '\n'),
|
||||
{
|
||||
omitAnnotationLines: true,
|
||||
contextLines: 0,
|
||||
expand: false,
|
||||
aColor: noColor,
|
||||
bColor: noColor,
|
||||
changeColor: noColor,
|
||||
commonColor: noColor,
|
||||
patchColor: noColor,
|
||||
}
|
||||
)
|
||||
}
|
Loading…
Reference in a new issue