我正在寻找一种从git show输出创建对象的方法
我使用git show -m --name-status --oneline <commit-hash>
。输出是这样的:
5b5f664 (from fd9fe89) Merge branch 'develop' into COMMIT-4
M src/app/app.module.ts
M src/app/components/accordion/accordion.component.scss
A src/app/components/file-diff-commit/file-diff-commit.component.html
A src/app/components/file-diff-commit/file-diff-commit.component.ts
M src/app/models/MockGitService.ts
M src/app/models/MockLeftPanelService.ts
M src/assets/i18n/en.json
M src/assets/i18n/fr.json
M package.json
5b5f664 (from a0ebd90) Merge branch 'develop' into COMMIT-4
M package.json
M src/app/components/copy-button/copy-button.component.scss
A src/app/models/CommitInformations.ts
M src/app/models/MockGitService.ts
M src/app/models/MockRightPanelService.ts
我只希望两个提交描述之间的部分并获得这种对象:
[
{ status: "M", path: "src/app/app.module.ts" },
{ status: "M", path: "src/app/components/accordion/accordion.component.scss" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.html" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.ts" },
{ status: "M", path: "src/app/models/MockGitService.ts" },
{ status: "M", path: "src/app/models/MockLeftPanelService.ts" },
{ status: "M", path: "src/assets/i18n/en.json" },
{ status: "M", path: "src/assets/i18n/fr.json" },
{ status: "M", path: "package.json" }
]
还有
{
"src": {
"app": {
{ file: "app.module.ts", status: "M" },
"components": {
"accordion": {
{ file: "accordion.component.scss" status: "m" }
}
...
}
},
"assets": {
....
}
},
{ file: "package.json", status: "M" }
}
我不知道如何创建第二个对象。但是我第一次尝试了这个:
var first = test.split(/\n/).map(x => {
return (x.split(/\s{7}/g))
}).filter(o => o.length === 2);
console.log(first);
问题是我在第二次提交描述之后得到了一部分。
如何继续创建这两个对象?
编辑 第一个对象的工作解决方案
var output = `5b5f664 (from fd9fe89) Merge branch 'develop' into COMMIT-4
M src/app/app.module.ts
M src/app/components/accordion/accordion.component.scss
A src/app/components/file-diff-commit/file-diff-commit.component.html
A src/app/components/file-diff-commit/file-diff-commit.component.ts
M src/app/models/MockGitService.ts
M src/app/models/MockLeftPanelService.ts
M src/assets/i18n/en.json
M src/assets/i18n/fr.json
M package.json
5b5f664 (from a0ebd90) Merge branch 'develop' into COMMIT-4
M package.json
M src/app/components/copy-button/copy-button.component.scss
A src/app/models/CommitInformations.ts
M src/app/models/MockGitService.ts
M src/app/models/MockRightPanelService.ts`;
var temp = output.split(/\n/);
temp.shift();
var arr = temp.map(x => {
return (x.split(/\s{7}/g))
})
var final = [];
for (s in arr) {
if (Array.isArray(arr[s]) && arr[s].length === 2) {
final.push({ status: arr[s][0], path: arr[s][1]});
} else {
break;
}
}
console.log(final);
答案 0 :(得分:2)
在下面,您将找到带有轻型单元测试的可行解决方案。
我不得不更改第二个对象结构,并用预期的数据填充它以完成测试。
// this is the git output provided by the OP
const output = `
5b5f664 (from fd9fe89) Merge branch 'develop' into COMMIT-4
M src/app/app.module.ts
M src/app/components/accordion/accordion.component.scss
A src/app/components/file-diff-commit/file-diff-commit.component.html
A src/app/components/file-diff-commit/file-diff-commit.component.ts
M src/app/models/MockGitService.ts
M src/app/models/MockLeftPanelService.ts
M src/assets/i18n/en.json
M src/assets/i18n/fr.json
M package.json
5b5f664 (from a0ebd90) Merge branch 'develop' into COMMIT-4
M package.json
M src/app/components/copy-button/copy-button.component.scss
A src/app/models/CommitInformations.ts
M src/app/models/MockGitService.ts
M src/app/models/MockRightPanelService.ts
`
// this is the first shape of object required by the OP:
// it looks like the result of splitting each git output line into the file and its status
// the OP mentionned that he/she wanted only the first commit, the solution below generates a set of object per commit
const entries = [
{ status: "M", path: "src/app/app.module.ts" },
{ status: "M", path: "src/app/components/accordion/accordion.component.scss" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.html" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.ts" },
{ status: "M", path: "src/app/models/MockGitService.ts" },
{ status: "M", path: "src/app/models/MockLeftPanelService.ts" },
{ status: "M", path: "src/assets/i18n/en.json" },
{ status: "M", path: "src/assets/i18n/fr.json" },
{ status: "M", path: "package.json" }
];
// This is the second object shape required by the OP, slightly modified, it looks like a full folder tree structure built from the entries extracted before
const folderTree = {
folders: {
"src": {
folders: {
"app": {
folders: {
"components": {
folders: {
"accordion": {
files: {
"accordion.component.scss": { status: "m" }
}
},
"file-diff-commit": {
files: {
"file-diff-commit.component.html": { status: "a" },
"file-diff-commit.component.ts": { status: "a" }
}
}
}
},
"models": {
files: {
"MockGitService.ts": { status: "m" },
"MockLeftPanelService.ts": { status: "m" }
}
}
},
files: {
"app.module.ts": { status: "m" },
}
},
"assets": {
folders: {
"i18n": {
files: {
"en.json": { status: "m" },
"fr.json": { status: "m" }
}
}
}
}
}
}
},
files: {
"package.json": { status: "m" }
}
};
// this will serve as commit splitter
const commitReg = /[a-f0-9]{7} \(from [a-f0-9]{7}\) Merge branch '[\w\d-_]+' into [\w\d-_]+\n/g;
// converts the first object shape into the second one
function buildTreeFromEntries(entries) {
// Note and entry is { status: A|M|U, path: /\w+(/\w+)*\.\w+ }
const root = {};
entries.forEach((entry) => {
const pathSplit = entry.path.split('/');
if (pathSplit.length < 2) {
if (!root.files) {
root.files = {};
}
root.files[pathSplit[0]] = { status: entry.status.toLowerCase() };
return;
}
let current = root;
pathSplit.forEach((p, index, list) => {
if (index === list.length - 1) {
if (!current.files) {
current.files = {};
}
current.files[p] = { status: entry.status.toLowerCase() };
return;
}
if (!current.folders) {
current.folders = {};
}
if (!current.folders[p]) {
current.folders[p] = {};
}
current = current.folders[p];
});
});
return root;
}
// returns a set of results as requested by the OP by commit
function parseGitOutput(output) {
const commits = output.split(commitReg).filter(c => c.trim() !== '');
const result = [];
commits.forEach((commit) => {
const currentEntries = [];
const currentCommitResult = { entries: currentEntries };
result.push(currentCommitResult);
const files = commit.split('\n').filter(c => c.trim() !== '');
files.forEach((file) => {
const statusFilePair = file.split(/\s+/);
const path = statusFilePair[1];
const status = statusFilePair[0];
currentEntries.push({ status, path });
});
});
result.forEach((commitResult) => {
commitResult.folderTree = buildTreeFromEntries(commitResult.entries);
});
return result;
}
// for testing purpose only, the test is far from perfect but more or less proves the concept
function objectMatch(obj1, obj2) {
const keys = Object.keys(obj1);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const v1 = obj1[key];
const v2 = obj2[key];
if (typeof v1 !== typeof v2) {
console.log(v1, ' is not the same type as ', v2);
return false;
}
if (typeof v1 === 'string') {
if (v1 !== v2) {
console.log(v1, ' !== ', v2);
return false;
}
continue;
}
if (!objectMatch(v1, v2)) {
return false;
}
}
return true;
}
// parsing
const parsedOutput = parseGitOutput(output)[0];
// console output of the results and tests
console.log(parsedOutput.entries);
console.log(
"entries match:",
parsedOutput.entries.every((entry, index) => objectMatch(entries[index], entry))
);
console.log("tree match:", parsedOutput.folderTree, folderTree);
console.log(parsedOutput.folderTree);