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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cherry-pick #1736

Open
yardenshoham opened this issue Feb 22, 2023 · 14 comments · May be fixed by #1849
Open

Support cherry-pick #1736

yardenshoham opened this issue Feb 22, 2023 · 14 comments · May be fixed by #1849

Comments

@yardenshoham
Copy link

I think cherry-picking is very useful for automating backports (that's my use-case at least)

@jcubic
Copy link
Contributor

jcubic commented Feb 22, 2023

Ok, do you want to contribute?

@yardenshoham
Copy link
Author

I wouldn't know how to implement this. Is there an official git reference or another implementation you usually port from?

@jcubic
Copy link
Contributor

jcubic commented Feb 22, 2023

AFIK You need to know git internals and implement them based on those and the behavior of canonical git. Note that this project doesn't have an original author that left the project, so none will write this code for you. Unless you will find someone that will do this for you.

@yardenshoham
Copy link
Author

ChatGPT suggested the following approach, is it a good starting point or way off track?

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,
  });
}

@jcubic
Copy link
Contributor

jcubic commented Feb 24, 2023

Sorry, I have no idea, you should try but it probably will require refactoring. But I think that cherry-pick is just a merge of one commit taken from one branch to the other branch, I'm not sure how though.

@araknast
Copy link
Contributor

Since isomorphic-git has no analogue for revert or rebase or patch this would probably require implementing one or all of those from scratch I'm afraid. Since cherry-pick and rebase are somewhat redundant it would probably make the most sense to implement rebase which would also solve #189 and #1527.

If you wanted to implement this yourself I think the easiest way would be to study the code of src/commands/merge.js and create a similar rebase command that calls mergeTree(onto, commit1), mergeTree(commit1, commit2), etc. where onto is the commit we are rebasing onto.

If you only need to cherry-pick one commit at a time however, a simpler approach would be to expose mergeTree and you could manually merge the cherry-picked commit with the tip of your branch, then commit that to the repo.

@mdreier-sap
Copy link

It's possible to write this with the current API, I did so for a project. I'll check with my employer if I can contribute it, as it was written for work.

@jcubic
Copy link
Contributor

jcubic commented Jul 14, 2023

@mdreier-sap sorry I have no idea, but you can try the ChatGPT solution.

@mojavelinux
Copy link
Contributor

@jcubic I think Martin is saying that he already has a solution and is willing to contribute it, if permitted.

@jcubic
Copy link
Contributor

jcubic commented Jul 14, 2023

I thought that the first sentence was a question.

@mdreier-sap
Copy link

I think Martin is saying that he already has a solution and is willing to contribute it, if permitted.

This is correct

@bilalshaikh42
Copy link

bilalshaikh42 commented Aug 16, 2023

@mdreier-sap Were you able to get permission to post this? rebase would be very helpful for us as well!

Edit: I though the implementation you were mentioning was rebase, no cherry-pick

@IAmSSH
Copy link

IAmSSH commented Sep 2, 2023

Is this still a requirement? I can try the implementation if needed.

@jcubic
Copy link
Contributor

jcubic commented Sep 2, 2023

@IAmSSH the feature is missing so if you want to implement cherry-pick that would be great. Make sure that you will add unit tests for the new feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants