Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

#3060 support cherry commit in gitgraph #3115

Merged
merged 4 commits into from Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 49 additions & 2 deletions cypress/integration/rendering/gitGraph.spec.js
Expand Up @@ -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': {
Expand Down Expand Up @@ -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
`,
{}
);
});
});
31 changes: 31 additions & 0 deletions docs/gitgraph.md
Expand Up @@ -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.
Expand Down
81 changes: 81 additions & 0 deletions src/diagrams/git/gitGraphAst.js
Expand Up @@ -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') {
Expand Down Expand Up @@ -390,6 +469,7 @@ export const commitType = {
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
CHERRY_PICK: 4,
};

export default {
Expand All @@ -401,6 +481,7 @@ export default {
commit,
branch,
merge,
cherryPick,
checkout,
//reset,
prettyPrint,
Expand Down
48 changes: 46 additions & 2 deletions src/diagrams/git/gitGraphRenderer.js
Expand Up @@ -14,6 +14,7 @@ const commitType = {
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
CHERRY_PICK: 4,
};

let branchPos = {};
Expand Down Expand Up @@ -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';
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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');

Expand All @@ -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 + ')'
Expand Down
6 changes: 6 additions & 0 deletions src/diagrams/git/parser/gitGraph.jison
Expand Up @@ -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';
Expand Down Expand Up @@ -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);}
Expand All @@ -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)}
Expand Down