mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-09 02:27:05 +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 branch9
|
||||
checkout branch1
|
||||
commit
|
||||
commit id: "1"
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('9: should render a simple gitgraph with rotated labels', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{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.
|
||||
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
|
||||
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.
|
||||
|
@@ -235,6 +235,85 @@ export const merge = function (otherBranch, tag) {
|
||||
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) {
|
||||
branch = common.sanitizeText(branch, configApi.getConfig());
|
||||
if (typeof branches[branch] === 'undefined') {
|
||||
@@ -390,6 +469,7 @@ export const commitType = {
|
||||
REVERSE: 1,
|
||||
HIGHLIGHT: 2,
|
||||
MERGE: 3,
|
||||
CHERRY_PICK: 4,
|
||||
};
|
||||
|
||||
export default {
|
||||
@@ -401,6 +481,7 @@ export default {
|
||||
commit,
|
||||
branch,
|
||||
merge,
|
||||
cherryPick,
|
||||
checkout,
|
||||
//reset,
|
||||
prettyPrint,
|
||||
|
@@ -14,6 +14,7 @@ const commitType = {
|
||||
REVERSE: 1,
|
||||
HIGHLIGHT: 2,
|
||||
MERGE: 3,
|
||||
CHERRY_PICK: 4,
|
||||
};
|
||||
|
||||
let branchPos = {};
|
||||
@@ -103,6 +104,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
case commitType.MERGE:
|
||||
typeClass = 'commit-merge';
|
||||
break;
|
||||
case commitType.CHERRY_PICK:
|
||||
typeClass = 'commit-cherry-pick';
|
||||
break;
|
||||
default:
|
||||
typeClass = 'commit-normal';
|
||||
}
|
||||
@@ -139,6 +143,43 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
typeClass +
|
||||
'-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 {
|
||||
const circle = gBullets.append('circle');
|
||||
circle.attr('cx', x);
|
||||
@@ -175,7 +216,11 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
const px = 4;
|
||||
const py = 2;
|
||||
// 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 labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg');
|
||||
|
||||
@@ -197,7 +242,6 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
if (gitGraphConfig.rotateCommitLabel) {
|
||||
let r_x = -7.5 - ((bbox.width + 10) / 25) * 9.5;
|
||||
let r_y = 10 + (bbox.width / 25) * 8.5;
|
||||
//wrapper.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + bbox.width / 2 + ') ');
|
||||
wrapper.attr(
|
||||
'transform',
|
||||
'translate(' + r_x + ', ' + r_y + ') rotate(' + -45 + ', ' + pos + ', ' + y + ')'
|
||||
|
@@ -48,6 +48,7 @@ accDescr\s*"{"\s* { this.begin("ac
|
||||
"branch" return 'BRANCH';
|
||||
"order:" return 'ORDER';
|
||||
"merge" return 'MERGE';
|
||||
"cherry-pick" return 'CHERRY_PICK';
|
||||
// "reset" return 'RESET';
|
||||
"checkout" return 'CHECKOUT';
|
||||
"LR" return 'DIR';
|
||||
@@ -102,6 +103,7 @@ line
|
||||
statement
|
||||
: commitStatement
|
||||
| mergeStatement
|
||||
| cherryPickStatement
|
||||
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
|
||||
| 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);}
|
||||
@@ -114,6 +116,10 @@ branchStatement
|
||||
| BRANCH ID ORDER NUM {yy.branch($2, $4)}
|
||||
;
|
||||
|
||||
cherryPickStatement
|
||||
: CHERRY_PICK COMMIT_ID STR {yy.cherryPick($3)}
|
||||
;
|
||||
|
||||
mergeStatement
|
||||
: MERGE ID {yy.merge($2)}
|
||||
| MERGE ID COMMIT_TAG STR {yy.merge($2, $4)}
|
||||
|
Reference in New Issue
Block a user