如何通过GitHub的API进行挑选性合并代码(cherry-pick)

3
我在通过GitHub API进行简单的cherry-pick时遇到了麻烦。这一定是可能的,但我不清楚如何操作...
我正在使用C#为Slack开发聊天机器人,以帮助管理Kubernetes环境和GitHub发布,并希望通过热修复功能来扩展它。给定一个环境,它应该创建与当前发布匹配的分支,并将一个或多个提交SHA作为由请求者通过Slack提供的参数,cherry-pick到此分支中。
所有的基础工作都已就绪。使用POST /repos/:owner/:repo/git/refs,我能够创建与特定发布相匹配的分支。这意味着我已经准备好了分支名称提交SHA树SHA,可以进行下一步操作:将一个或多个提交SHA cherry-pick到此分支中。使用POST /repos/:owner/:repo/git/commits,我能够创建一个提交,但我不确定要使用哪个树和/或父提交 - 这可能会导致我调用POST /repos/:owner/:repo/merges时遇到问题,因为它会返回状态码409(合并冲突),而本地上当然没有这种情况。
我似乎只找到了一个真正的例子https://github.com/tibdex/github-cherry-pick。然而,它并不完全符合我的情况,我很难理解Git的内部工作原理。
我的情况是(从最新到最旧):
* commit E (current state of `master`)
* commit D
* commit C (deployed to environment)
* commit B
* commit A

在这种情况下,我想要将提交 E 挑选出来,创建一个新的分支,该分支基于提交 C,从而创建一个集合 (A, B, C, E),以便我可以发布。
* commit E (current state of `master`)
* commit D
|
| * commit E (new branch, to be deployed)
|/
* commit C (deployed to environment)
* commit B
* commit A

基本上我需要的是这个bash脚本的GitHub API版本。
git checkout -b {new-branch-name} {sha}
git cherry-pick {sha}
git push main {new-branch-name}

任何帮助都受到赞赏!

挑选樱桃是一种合并的形式,而合并可能会导致冲突。冲突需要通过索引和工作树进行解决,而GitHub存储库没有工作树。也许有一种处理没有冲突的挑选樱桃的方法,因为在执行拉取请求时,GitHub会在幕后执行非冲突合并。他们会自动检测冲突,并使这些情况下的拉取请求无法合并。但是,无论您的目标是否可行(通过GitHub API),我不知道如何在那里实现。 - torek
2个回答

8

以下是我如何使用Github API实现cherry-pick的伪代码:

// here is a commit, for example, from a pull request:
listOfCommits = GET /repos/$owner/$repo/pulls/$number/commits
commit = listOfCommits.head // the first one in the list

// Here is the branch we want to cherry-pick to:
branch = GET /repos/$owner/$repo/branches/$branchName
branchSha = branch.commit.sha
branchTree = branch.commit.commit.tree.sha

// Create a temporary commit on the branch, which extends as a sibling of
// the commit we want but contains the current tree of the target branch:
parentSha = commit.parents.head // first parent -- there should only be one
tempCommit = POST /repos/$owner/$repo/git/commits { "message": "temp",
                                                    "tree": branchTree,
                                                    "parents": [parentSha] }

// Now temporarily force the branch over to that commit
PATCH /repos/$owner/$repo/git/refs/heads/$refName { sha = tempCommit.sha,
                                                    force = true }

// Merge the commit we want into this mess:
merge = POST /repos/$owner/$repo/merges { "base": branchName
                                  "head": commit.sha }

// and get that tree!
mergeTree = merge.commit.tree.sha

// Now that we know what the tree should be, create the cherry-pick commit.
// Note that branchSha is the original from up at the top.
cherry = POST /repos/$owner/$repo/git/commits { "message": "looks good!",
                                                "tree": mergeTree,
                                                "parents": [branchSha] }

// Replace the temp commit with the real commit:
PATCH /repos/$owner/$repo/git/refs/heads/$refName { sha = cherry.sha,
                                                    force = true }

// Done!

Git专家请指导,但我认为这样做可以完成以下内容:
git checkout -b {new-branch-name} {sha}
git cherry-pick {sha}
git push main {new-branch-name}

6
接受的答案可行,但不清楚原因。
以下内容摘自我用golang编写的脚本的评论(在我的gist中):https://gist.github.com/sashamor/7918b3be758759440feb7825547370f9 GitHub不支持直接使用其API创建cherry-pick提交。 但是,它支持在git树中创建提交对象。 因此,我们将从头开始创建新的cherry-pick提交。
要创建提交,我们需要三件事:
1. 提交消息。 2. 父提交。 3. 树(也就是库中所有对象的状态)。
对于cherry-pick提交,这些都很容易:
1. 消息很简单-我们使用原始提交的消息加上“cherry-picked from ...”底部。 2. 父SHA也很容易-我们使用想要进行cherry-pick的提交的SHA,延伸树。 3. 树是棘手的部分-我们需要创建一个包含所需状态的文件的新git对象,然后使用它。
下面的步骤是为了创建tree SHA。 一旦拥有它,就可以创建提交了。
要获取树,可以使用合并API。 目前,GitHub合并API需要两件事:
1. 要合并到的分支。 2. 我们要合并的提交的SHA。
乍一看,解决方案似乎是使用merge与:
1. 要进行cherry-pick的分支。 2. 要进行cherry-pick的提交。
然而,这有一个警告:所有在cherry-pick提交之前的提交(不在要进行cherry-pick的分支中)都包含在合并中。 我们不想这样。 为了解决这个问题,我们可以通过(暂时)将分支的父项设置为我们要进行cherry-pick的提交的父项来“欺骗”git,以便只包括cherry-pick提交。 这样,当git执行合并时,它会检测到我们正在合并的分支提交的父项与我们正在合并的提交的父项匹配,并合并仅包含cherry-pick提交的大小为1的树。
要创建这个新的“树尖”提交:
1. 消息无所谓-它丢失了。 2. 父项是我们要进行cherry-pick的提交的父项-这样,cherry-pick提交和分支具有相同的父项。 3. 树是我们要进行cherry-pick的分支的树。
我们首先创建一个指向此提交的临时分支,以便我们可以在其上进行合并。然后,我们可以使用以下方式调用合并操作:
  1. 拥有与我们要将其挑选到的分支匹配的树和与我们要挑选的提交的父项匹配的分支。
  2. 要挑选的提交
  3. 此合并操作的结果提交具有我们需要的树SHA。
最后,我们可以使用此操作创建挑选提交。这可以重复多次,新的挑选提交每次都是基本分支。

我不明白为什么每次提交都要创建一个临时分支。 我们难道不能只更新单个临时分支到最新的“baseCommitForMerging”吗? - LppEdd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接