Repository navigation
Show files as conflicted in git panel when discard undo creates merge conflicts, handle various edge cases #563
Changes from all commits
ca3687e
0763353
c35db7b
5daf3a5
84d451b
97c4d4d
bdc9de2
61eaf73
1d5364a
79a6487
b52b602
65858ee
4cb9d0c
352b9af
a27ed97
e9c46bf
22458df
862c0a5
d8686e1
8ee9dd2
79f901d
b950c38
b247137
cd91dcd
0440a0c
bc4477e
d29cd8a
73941ff
65c38b5
867f9b2
56f158c
0003447
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,21 @@ | ||
| import path from 'path'; | ||
| import os from 'os'; | ||
|
|
||
| import mkdirp from 'mkdirp'; | ||
|
|
||
| import {PartialFileDiscardHistory, WholeFileDiscardHistory} from './discard-history-stores'; | ||
|
|
||
| import {getTempDir} from '../helpers'; | ||
| import {getTempDir, copyFile, fileExists, writeFile} from '../helpers'; | ||
|
|
||
| const emptyFilePath = path.join(os.tmpdir(), 'empty-file.txt'); | ||
| const emptyFilePromise = writeFile(emptyFilePath, ''); | ||
|
|
||
| export default class DiscardHistory { | ||
| constructor(createBlob, expandBlobToFile, mergeFile, {maxHistoryLength} = {}) { | ||
| constructor(createBlob, expandBlobToFile, mergeFile, workdirPath, {maxHistoryLength} = {}) { | ||
| this.createBlob = createBlob; | ||
| this.expandBlobToFile = expandBlobToFile; | ||
| this.mergeFile = mergeFile; | ||
| this.workdirPath = workdirPath; | ||
| this.partialFileHistory = new PartialFileDiscardHistory(maxHistoryLength); | ||
| this.wholeFileHistory = new WholeFileDiscardHistory(maxHistoryLength); | ||
| } | ||
|
|
@@ -114,25 +120,46 @@ export default class DiscardHistory { | |
| async expandBlobsToFilesInTempFolder(snapshots) { | ||
| const tempFolderPath = await getTempDir(path.join(os.tmpdir(), 'github-discard-history-')); | ||
| const pathPromises = snapshots.map(async ({filePath, beforeSha, afterSha}) => { | ||
| const otherPath = !beforeSha ? null : | ||
| const dir = path.dirname(path.join(tempFolderPath, filePath)); | ||
| await mkdirp(dir); | ||
| const theirsPath = !beforeSha ? null : | ||
| await this.expandBlobToFile(path.join(tempFolderPath, `${filePath}-before-discard`), beforeSha); | ||
| const basePath = !afterSha ? null : | ||
| const commonBasePath = !afterSha ? null : | ||
| await this.expandBlobToFile(path.join(tempFolderPath, `${filePath}-after-discard`), afterSha); | ||
| const resultPath = path.join(tempFolderPath, `${filePath}-merge-result`); | ||
| return {filePath, basePath, otherPath, resultPath}; | ||
| const resultPath = path.join(tempFolderPath, `~${path.basename(filePath)}-merge-result`); | ||
| return {filePath, commonBasePath, theirsPath, resultPath, theirsSha: beforeSha, commonBaseSha: afterSha}; | ||
| }); | ||
| return await Promise.all(pathPromises); | ||
| } | ||
|
|
||
| async mergeFiles(filePaths) { | ||
| const mergeFilePromises = filePaths.map(({filePath, basePath, otherPath, resultPath}) => { | ||
| if (otherPath && basePath) { | ||
| return this.mergeFile(filePath, basePath, otherPath, resultPath); | ||
| } else if (!otherPath && basePath) { // deleted file | ||
| // TODO: handle this | ||
| return null; | ||
| const mergeFilePromises = filePaths.map(async (filePathInfo, i) => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is starting to feel a little hairy again. Probably okay to merge, but I continue to wonder if there are more extractions we can do, especially around object modeling. E.g. would it make sense to have a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We couldn't use |
||
| const {filePath, commonBasePath, theirsPath, resultPath, theirsSha, commonBaseSha} = filePathInfo; | ||
| let mergeResult; | ||
| if (theirsPath && commonBasePath) { | ||
| mergeResult = await this.mergeFile(filePath, commonBasePath, theirsPath, resultPath); | ||
| } else if (!theirsPath && commonBasePath) { // deleted file | ||
| const oursSha = await this.createBlob({filePath}); | ||
| if (oursSha === commonBaseSha) { // no changes since discard, mark file to be deleted | ||
| mergeResult = {filePath, resultPath: null, deleted: true, conflict: false}; | ||
| } else { // changes since discard result in conflict | ||
| await copyFile(path.join(this.workdirPath, filePath), resultPath); | ||
| mergeResult = {filePath, resultPath, conflict: true}; | ||
| } | ||
| } else if (theirsPath && !commonBasePath) { // added file | ||
| const fileDoesExist = await fileExists(path.join(this.workdirPath, filePath)); | ||
| if (!fileDoesExist) { | ||
| await copyFile(theirsPath, resultPath); | ||
| mergeResult = {filePath, resultPath, conflict: false}; | ||
| } else { | ||
| await emptyFilePromise; | ||
| mergeResult = await this.mergeFile(filePath, emptyFilePath, theirsPath, resultPath); | ||
| } | ||
| } else { | ||
| throw new Error('One of the following must be defined - theirsPath:' + | ||
| `${theirsPath} or commonBasePath: ${commonBasePath}`); | ||
| } | ||
| return null; | ||
| return {...mergeResult, theirsSha, commonBaseSha}; | ||
| }); | ||
| return await Promise.all(mergeFilePromises); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,10 @@ export default class PushPullMenuView extends React.Component { | |
| remoteName: React.PropTypes.string, | ||
| aheadCount: React.PropTypes.number, | ||
| behindCount: React.PropTypes.number, | ||
| notificationManager: React.PropTypes.object, | ||
| fetch: React.PropTypes.func, | ||
| push: React.PropTypes.func, | ||
| pull: React.PropTypes.func, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a note for me to remove this same change in #565 |
||
| } | ||
|
|
||
| static defaultProps = { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍