mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-11 19:39:43 +02:00
Merge pull request #3115 from mermaid-js/#3060-Support-cherry-commit-in-Gitgraph
#3060 support cherry commit in gitgraph
This commit is contained in:
@@ -126,12 +126,11 @@ describe('Git Graph diagram', () => {
|
|||||||
branch branch8
|
branch branch8
|
||||||
branch branch9
|
branch branch9
|
||||||
checkout branch1
|
checkout branch1
|
||||||
commit
|
commit id: "1"
|
||||||
`,
|
`,
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('9: should render a simple gitgraph with rotated labels', () => {
|
it('9: should render a simple gitgraph with rotated labels', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
|
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
|
||||||
@@ -160,4 +159,52 @@ describe('Git Graph diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('11: should render a simple gitgraph with cherry pick commit', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A"
|
||||||
|
commit id:"THREE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('11: should render a simple gitgraph with two cherry pick commit', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
branch featureA
|
||||||
|
commit id:"FIX"
|
||||||
|
commit id: "FIX-2"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A"
|
||||||
|
commit id:"THREE"
|
||||||
|
cherry-pick id:"FIX"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
merge featureA
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -182,6 +182,37 @@ After this we made use of the `checkout` keyword to set the current branch as `m
|
|||||||
After this we merge the `develop` branch onto the current branch `main`, resulting in a merge commit.
|
After this we merge the `develop` branch onto the current branch `main`, resulting in a merge commit.
|
||||||
Since the current branch at this point is still `main`, the last two commits are registered against that.
|
Since the current branch at this point is still `main`, the last two commits are registered against that.
|
||||||
|
|
||||||
|
### Cherry Pick commit from another branch
|
||||||
|
Similar to how 'git' allows you to cherry pick a commit from **another branch** onto the **current** branch, Mermaid also suports this functionality. You can also cherry pick a commit from another branch using the `cherry-pick` keyword.
|
||||||
|
|
||||||
|
To use the `cherry-pick` keyword, you must specify the id using the `id` attribute, followed by `:` and your desired commit id within `""` quote. For example:
|
||||||
|
|
||||||
|
`cherry-pick id: "your_custom_id"`
|
||||||
|
|
||||||
|
Here, a new commt representing the cherry pick is created on the current branch, and is visually highlighted in the diagram with a **cherry** and a tag depicting the commit id from which it is cherry picked from.
|
||||||
|
|
||||||
|
Few Important rules to note here are:
|
||||||
|
1. You need to provide the `id` for an existing commit to be cherry picked. If given commit id does not exist it will result in an error. For this make use of the `commit id:$value` format of declaring commits. See the examples from above.
|
||||||
|
2. The given commit must not exist on the current branch. Cherry picked commit must always be a different branch than the current branch.
|
||||||
|
3. Current branch must have atleast one commit, before you can cherry pick a commit, otherwise it will case an error is throw.
|
||||||
|
|
||||||
|
Let see an example:
|
||||||
|
```mermaid-example
|
||||||
|
gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A"
|
||||||
|
commit id:"THREE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
```
|
||||||
## Gitgraph specific configuration options
|
## Gitgraph specific configuration options
|
||||||
In Mermaid, you have the option to configure the gitgraph diagram. You can configure the following options:
|
In Mermaid, you have the option to configure the gitgraph diagram. You can configure the following options:
|
||||||
- `showBranches` : Boolean, default is `true`. If set to `false`, the branches are not shown in the diagram.
|
- `showBranches` : Boolean, default is `true`. If set to `false`, the branches are not shown in the diagram.
|
||||||
|
@@ -235,6 +235,85 @@ export const merge = function (otherBranch, tag) {
|
|||||||
log.debug('in mergeBranch');
|
log.debug('in mergeBranch');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const cherryPick = function (sourceId, targetId) {
|
||||||
|
sourceId = common.sanitizeText(sourceId, configApi.getConfig());
|
||||||
|
targetId = common.sanitizeText(targetId, configApi.getConfig());
|
||||||
|
|
||||||
|
if (!sourceId || typeof commits[sourceId] === 'undefined') {
|
||||||
|
let error = new Error(
|
||||||
|
'Incorrect usage of "cherryPick". Source commit id should exist and provided'
|
||||||
|
);
|
||||||
|
error.hash = {
|
||||||
|
text: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
token: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
line: '1',
|
||||||
|
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
|
||||||
|
expected: ['cherry-pick abc'],
|
||||||
|
};
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sourceCommit = commits[sourceId];
|
||||||
|
let sourceCommitBranch = sourceCommit.branch;
|
||||||
|
if (sourceCommit.type === commitType.MERGE) {
|
||||||
|
let error = new Error(
|
||||||
|
'Incorrect usage of "cherryPick". Source commit should not be a merge commit'
|
||||||
|
);
|
||||||
|
error.hash = {
|
||||||
|
text: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
token: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
line: '1',
|
||||||
|
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
|
||||||
|
expected: ['cherry-pick abc'],
|
||||||
|
};
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
if (!targetId || typeof commits[targetId] === 'undefined') {
|
||||||
|
// cherry-pick source commit to current branch
|
||||||
|
|
||||||
|
if (sourceCommitBranch === curBranch) {
|
||||||
|
let error = new Error(
|
||||||
|
'Incorrect usage of "cherryPick". Source commit is already on current branch'
|
||||||
|
);
|
||||||
|
error.hash = {
|
||||||
|
text: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
token: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
line: '1',
|
||||||
|
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
|
||||||
|
expected: ['cherry-pick abc'],
|
||||||
|
};
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const currentCommit = commits[branches[curBranch]];
|
||||||
|
if (typeof currentCommit === 'undefined' || !currentCommit) {
|
||||||
|
let error = new Error(
|
||||||
|
'Incorrect usage of "cherry-pick". Current branch (' + curBranch + ')has no commits'
|
||||||
|
);
|
||||||
|
error.hash = {
|
||||||
|
text: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
token: 'cherryPick ' + sourceId + ' ' + targetId,
|
||||||
|
line: '1',
|
||||||
|
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
|
||||||
|
expected: ['cherry-pick abc'],
|
||||||
|
};
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const commit = {
|
||||||
|
id: seq + '-' + getId(),
|
||||||
|
message: 'cherry-picked ' + sourceCommit + ' into ' + curBranch,
|
||||||
|
seq: seq++,
|
||||||
|
parents: [head == null ? null : head.id, sourceCommit.id],
|
||||||
|
branch: curBranch,
|
||||||
|
type: commitType.CHERRY_PICK,
|
||||||
|
tag: 'cherry-pick:' + sourceCommit.id,
|
||||||
|
};
|
||||||
|
head = commit;
|
||||||
|
commits[commit.id] = commit;
|
||||||
|
branches[curBranch] = commit.id;
|
||||||
|
log.debug(branches);
|
||||||
|
log.debug('in cheeryPick');
|
||||||
|
}
|
||||||
|
};
|
||||||
export const checkout = function (branch) {
|
export const checkout = function (branch) {
|
||||||
branch = common.sanitizeText(branch, configApi.getConfig());
|
branch = common.sanitizeText(branch, configApi.getConfig());
|
||||||
if (typeof branches[branch] === 'undefined') {
|
if (typeof branches[branch] === 'undefined') {
|
||||||
@@ -390,6 +469,7 @@ export const commitType = {
|
|||||||
REVERSE: 1,
|
REVERSE: 1,
|
||||||
HIGHLIGHT: 2,
|
HIGHLIGHT: 2,
|
||||||
MERGE: 3,
|
MERGE: 3,
|
||||||
|
CHERRY_PICK: 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -401,6 +481,7 @@ export default {
|
|||||||
commit,
|
commit,
|
||||||
branch,
|
branch,
|
||||||
merge,
|
merge,
|
||||||
|
cherryPick,
|
||||||
checkout,
|
checkout,
|
||||||
//reset,
|
//reset,
|
||||||
prettyPrint,
|
prettyPrint,
|
||||||
|
@@ -14,6 +14,7 @@ const commitType = {
|
|||||||
REVERSE: 1,
|
REVERSE: 1,
|
||||||
HIGHLIGHT: 2,
|
HIGHLIGHT: 2,
|
||||||
MERGE: 3,
|
MERGE: 3,
|
||||||
|
CHERRY_PICK: 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
let branchPos = {};
|
let branchPos = {};
|
||||||
@@ -103,6 +104,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
case commitType.MERGE:
|
case commitType.MERGE:
|
||||||
typeClass = 'commit-merge';
|
typeClass = 'commit-merge';
|
||||||
break;
|
break;
|
||||||
|
case commitType.CHERRY_PICK:
|
||||||
|
typeClass = 'commit-cherry-pick';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
typeClass = 'commit-normal';
|
typeClass = 'commit-normal';
|
||||||
}
|
}
|
||||||
@@ -139,6 +143,43 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
typeClass +
|
typeClass +
|
||||||
'-inner'
|
'-inner'
|
||||||
);
|
);
|
||||||
|
} else if (commit.type === commitType.CHERRY_PICK) {
|
||||||
|
gBullets
|
||||||
|
.append('circle')
|
||||||
|
.attr('cx', x)
|
||||||
|
.attr('cy', y)
|
||||||
|
.attr('r', 10)
|
||||||
|
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||||
|
gBullets
|
||||||
|
.append('circle')
|
||||||
|
.attr('cx', x - 3)
|
||||||
|
.attr('cy', y + 2)
|
||||||
|
.attr('r', 2.75)
|
||||||
|
.attr('fill', '#fff')
|
||||||
|
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||||
|
gBullets
|
||||||
|
.append('circle')
|
||||||
|
.attr('cx', x + 3)
|
||||||
|
.attr('cy', y + 2)
|
||||||
|
.attr('r', 2.75)
|
||||||
|
.attr('fill', '#fff')
|
||||||
|
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||||
|
gBullets
|
||||||
|
.append('line')
|
||||||
|
.attr('x1', x + 3)
|
||||||
|
.attr('y1', y + 1)
|
||||||
|
.attr('x2', x)
|
||||||
|
.attr('y2', y - 5)
|
||||||
|
.attr('stroke', '#fff')
|
||||||
|
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||||
|
gBullets
|
||||||
|
.append('line')
|
||||||
|
.attr('x1', x - 3)
|
||||||
|
.attr('y1', y + 1)
|
||||||
|
.attr('x2', x)
|
||||||
|
.attr('y2', y - 5)
|
||||||
|
.attr('stroke', '#fff')
|
||||||
|
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||||
} else {
|
} else {
|
||||||
const circle = gBullets.append('circle');
|
const circle = gBullets.append('circle');
|
||||||
circle.attr('cx', x);
|
circle.attr('cx', x);
|
||||||
@@ -175,7 +216,11 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
const px = 4;
|
const px = 4;
|
||||||
const py = 2;
|
const py = 2;
|
||||||
// Draw the commit label
|
// Draw the commit label
|
||||||
if (commit.type !== commitType.MERGE && gitGraphConfig.showCommitLabel) {
|
if (
|
||||||
|
commit.type !== commitType.CHERRY_PICK &&
|
||||||
|
commit.type !== commitType.MERGE &&
|
||||||
|
gitGraphConfig.showCommitLabel
|
||||||
|
) {
|
||||||
const wrapper = gLabels.append('g');
|
const wrapper = gLabels.append('g');
|
||||||
const labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg');
|
const labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg');
|
||||||
|
|
||||||
@@ -197,7 +242,6 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
|||||||
if (gitGraphConfig.rotateCommitLabel) {
|
if (gitGraphConfig.rotateCommitLabel) {
|
||||||
let r_x = -7.5 - ((bbox.width + 10) / 25) * 9.5;
|
let r_x = -7.5 - ((bbox.width + 10) / 25) * 9.5;
|
||||||
let r_y = 10 + (bbox.width / 25) * 8.5;
|
let r_y = 10 + (bbox.width / 25) * 8.5;
|
||||||
//wrapper.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + bbox.width / 2 + ') ');
|
|
||||||
wrapper.attr(
|
wrapper.attr(
|
||||||
'transform',
|
'transform',
|
||||||
'translate(' + r_x + ', ' + r_y + ') rotate(' + -45 + ', ' + pos + ', ' + y + ')'
|
'translate(' + r_x + ', ' + r_y + ') rotate(' + -45 + ', ' + pos + ', ' + y + ')'
|
||||||
|
@@ -48,6 +48,7 @@ accDescr\s*"{"\s* { this.begin("ac
|
|||||||
"branch" return 'BRANCH';
|
"branch" return 'BRANCH';
|
||||||
"order:" return 'ORDER';
|
"order:" return 'ORDER';
|
||||||
"merge" return 'MERGE';
|
"merge" return 'MERGE';
|
||||||
|
"cherry-pick" return 'CHERRY_PICK';
|
||||||
// "reset" return 'RESET';
|
// "reset" return 'RESET';
|
||||||
"checkout" return 'CHECKOUT';
|
"checkout" return 'CHECKOUT';
|
||||||
"LR" return 'DIR';
|
"LR" return 'DIR';
|
||||||
@@ -102,6 +103,7 @@ line
|
|||||||
statement
|
statement
|
||||||
: commitStatement
|
: commitStatement
|
||||||
| mergeStatement
|
| mergeStatement
|
||||||
|
| cherryPickStatement
|
||||||
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
|
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
|
||||||
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
|
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
|
||||||
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } | section {yy.addSection($1.substr(8));$$=$1.substr(8);}
|
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } | section {yy.addSection($1.substr(8));$$=$1.substr(8);}
|
||||||
@@ -114,6 +116,10 @@ branchStatement
|
|||||||
| BRANCH ID ORDER NUM {yy.branch($2, $4)}
|
| BRANCH ID ORDER NUM {yy.branch($2, $4)}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
cherryPickStatement
|
||||||
|
: CHERRY_PICK COMMIT_ID STR {yy.cherryPick($3)}
|
||||||
|
;
|
||||||
|
|
||||||
mergeStatement
|
mergeStatement
|
||||||
: MERGE ID {yy.merge($2)}
|
: MERGE ID {yy.merge($2)}
|
||||||
| MERGE ID COMMIT_TAG STR {yy.merge($2, $4)}
|
| MERGE ID COMMIT_TAG STR {yy.merge($2, $4)}
|
||||||
|
Reference in New Issue
Block a user