Skip to content

Instantly share code, notes, and snippets.

@yardenshoham
Created February 22, 2023 20:54
Show Gist options
  • Save yardenshoham/463eb3aec62cc0ef909af13b8203d778 to your computer and use it in GitHub Desktop.
Save yardenshoham/463eb3aec62cc0ef909af13b8203d778 to your computer and use it in GitHub Desktop.
ChatGPT's suggestion for implementing `cherry-pick` in `isomorphic-git`
import { RepoPath, CommitObject, GitError, MergeOptions, MergeReport } from 'isomorphic-git';
import { getCommit, listCommits, merge } from 'isomorphic-git';
// The cherryPick function takes a repository path and a commit SHA as input, and applies the
// changes made in the specified commit to the current branch. The function first gets the commit
// object for the specified commit, and then finds the parent commit(s) to use as the merge base(s).
// It then sets up the merge options, with ours set to the current HEAD commit and theirs set to the
// specified commit. The fastForwardOnly and noUpdateBranch options are used to ensure that the
// merge only applies changes from the specified commit, and does not change the branch reference
// or allow non-fast-forward merges. The merge function is then called to perform the merge and
// generate a merge report, which is used to check for merge conflicts. If there are conflicts,
// a GitError is thrown with an appropriate error message. If the merge succeeds without conflicts,
// the commit function is called to create a new commit with the merged changes. The commit message
// is set to cherry-pick: <original commit message>, and the author and committer are set to the same
// as the original commit. The parents are set to the current HEAD commit and the specified commit,
// and the tree is set to the merge result returned by the merge report.
async function cherryPick(repoPath: RepoPath, commitSha: string): Promise<void> {
// Get the commit object to apply changes from
const commit: CommitObject = await getCommit({ fs, dir: repoPath, oid: commitSha });
// Find the parent commit(s) to use as the merge base(s)
const parentCommits = await listCommits({ fs, dir: repoPath, ref: 'HEAD' });
// Set up the merge options
const mergeOptions: MergeOptions = {
dir: repoPath,
ours: parentCommits[0],
theirs: commitSha,
fastForwardOnly: true,
noUpdateBranch: true,
};
// Merge the changes from the specified commit
const mergeReport: MergeReport = await merge({ fs, ...mergeOptions });
// Check for merge conflicts
if (mergeReport.conflicts.length > 0) {
throw new GitError(E.MergeNotSupportedFail, {
message: 'Cherry-pick failed due to merge conflicts.',
});
}
// Commit the merge changes with the cherry-pick message
const message = `cherry-pick: ${commit.message}`;
const author = { ...commit.author, timestamp: Math.floor(new Date().getTime() / 1000) };
await commit({
fs,
dir: repoPath,
message,
author,
committer: author,
parents: [parentCommits[0], commitSha],
tree: mergeReport.oid,
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment