我有一个提交链,每个提交都有自己的分支,但是它们都是相同特性的一部分。
当我收到关于我的拉请求(GitHub/Bitbucket/任何其他)的评论时,我希望下面所有的拉请求都能以尽可能少的手工工作得到修复。
在这种情况下,没有其他人使用我的分支,所以如果需要的话,我可以自由地向它们施加压力。
我曾经在一家主要的Android设备制造商工作,我喜欢Gerrit轻松地处理这个问题的方式。Gerrit在Android之外并没有被广泛使用,所以我想找到一个很好的工作流程来覆盖90%的情况,即使在一个庞大的团队中也是如此。
我通常用两种方法之一来解决这个问题:
git rebase -i,然后根据需要多次执行git push origin <sha>:remote-branch。这也是很多工作,然后本地分支和远程分支之间出现了不匹配(这可以通过git reset进行补救,但这会增加更多的工作)。这也是容易出错的,因为它很容易拼错沙或分支的名称。是否有一种更简单的方法来管理指定用于拉请求的提交链?
发布于 2020-05-19 17:54:06
我在威廉·查金的博客上找到了一个很好的方法来处理这个问题,因为他称之为“依赖的拉请求”,这是描述它的一个很好的方法。
编辑2021-11-08:我已经开始使用git notes来管理remote-branch,而不是将它添加到提交消息中。这使得git提交消息历史更加清晰。
我修改了原来的脚本,因为它使用了MIT许可证,所以我遵循了指导方针,并添加了我的名字。
对脚本进行了以下修改:
sed兼容。git notes show获取远程分支消息,而不是git show。前言
要遵循这个答案,您需要相当熟练地使用git,并且您可能已经使用了足够多的git rebase -i来适应它。
如果这是你的第一次吉特竞技,它可能是明智的,获得一些经验,并回来另一个时间。
潜在缺陷
该方法使您更接近Gerrit的方便,只要您意识到潜在的缺点:
方法
先决条件
要使此方法正常工作,您必须配置git以使用这些设置(我喜欢全局配置它,但如果只需要针对特定的存储库,则可以删除--global )。
git config --global notes.rewriteRef refs/notes/commits
git config --global notes.rewrite.amend true
git config --global notes.rewrite.rebase true分支策略
所有提交都在单个本地分支上运行,这不一定需要推送,除非您希望在工作进行期间保持远程备份(建议)。
添加您需要的多个提交来构建依赖的拉请求的逻辑链。我曾经用11条链提交。
$ git log --oneline
aaaaaaa3 (HEAD -> my-backup-branch) Feature: Step 3
aaaaaaa2 Feature: Step 2
aaaaaaa1 Feature: Step 1
aaaaaaaa (origin/master) Probably some merge commit
...管理您的提交
对于,链中的每个提交,您必须添加一个git notes,它告诉脚本应该将它推送到哪个远程分支。远程分支不需要存在。在创建提交时或在推送更改之前的任何时候添加git notes。
$ git notes add -m "remote-branch: my-feature-step-3"
$ git log
commit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3 (HEAD -> my-backup-branch)
Author: Erik Zivkovic <...>
Date: Fri May 19 19:47:53 2020 +0200
Feature: Step 3
Notes:
remote-branch: my-feature-step-3
[... more commits]准备好推送和创建/更新PRs
我建议您不要同时进行git rebase -i修复并使用脚本。执行任何更改,然后测试您的提交链,然后再推送。这就是我建议的做法。
确保链中的所有提交都有唯一的remote-branch: <branch name>行!
要完成所有这些操作,请使用git rebase -i参数调用-x "git push-to-target"。
$ git rebase -i aaaaaaaa -x "git push-to-target"
[This will open your chosen git editor with a git rebase window]
pick aaaaaaa1 Feature: Step 1
exec git push-to-target
pick aaaaaaa2 Feature: Step 2
exec git push-to-target
pick aaaaaaa3 Feature: Step 3
exec git push-to-target当然,神奇的是,git rebase在每个pick命令之后停止并运行exec命令,该命令:
git notes消息。remote-branch行。--force-with-lease)当前HEAD (指向pick)到remote-branch。如果一切正常,您应该在git日志中看到更新的远程分支。
$ git log --oneline
aaaaaaa3 (HEAD -> my-backup-branch, origin/my-feature-step-3) Feature: Step 3
aaaaaaa2 (origin/my-feature-step-2) Feature: Step 2
aaaaaaa1 (origin/my-feature-step-1) Feature: Step 1
aaaaaaaa (origin/master) Probably some merge commit
...拉请求
如果您没有任何拉请求,那么现在是使用您所拥有的任何服务(Github、Bitbucket、.)创建这些请求的时候了,并且将分支按顺序指向对方。
如果拉请求已经存在,现在应该更新它们并再次运行测试(如果您有CI)。
更多提交,处理评审意见等。
git rebase -i并进行任何修复。git notes中添加唯一的git notes标签即可。git rebase -i <sha> -x "git push-to-target" (在本地测试您的更改之后,不用说)。清理
当所有内容都合并时,您可能希望删除远程备份分支。
提示
git push-to-targetgit config --global alias.ptt push-to-targetgit rebase -i <SHA> -x "git ptt"补充说明
注意:我已经通过电子邮件联系了开发人员,告诉他我的更改,并询问他对他们的看法,但我还没有收到答复。
脚本
脚本应该在Linux/macOS/WSL上工作。我只在macOS上测试过。
这个脚本的大部分是由William编写的,我只是让它在macOS上工作,并做了一些对我来说似乎不错的小改动。
文件:git-push-to-target
#!/bin/sh
#
# git-push-to-target: Push this commit to a branch specified in its
# commit description.
#
# Copyright (c) 2017 William Chargin. Released under the MIT license.
# Copyright (c) 2020 Erik Zivkovic.
#
# Originally https://wchargin.github.io/posts/managing-dependent-pull-requests/
#
# Usage: For a commit add a git notes line `remote-branch: branchname` then in a rebase do `exec git push-to-target`
#
# Tip: Add this file to your path, then you can use it as git push-to-target
# Tip: git config --global alias.ptt push-to-target
# Tip: git rebase -i <SHA> -x "git ptt"
#
set -eu
DIRECTIVE='remote-branch' # any regex metacharacters should be escaped
BRANCH_PREFIX='' # Add a branch prefix if needed
target_branch() {
directive="$( \
git notes show HEAD \
| sed -n 's/^'"${DIRECTIVE}"': \([A-Za-z0-9_.-]*\)$/\1/p' \
; )"
if [ -z "${directive}" ]; then
printf >&2 'error: missing "%s" directive\n' "${DIRECTIVE}"
return 1
fi
if [ "$(printf '%s\n' "${directive}" | wc -l)" -gt 1 ]; then
printf >&2 'error: multiple "%s" directives\n' "${DIRECTIVE}"
return 1
fi
printf '%s%s\n' "${BRANCH_PREFIX}" "${directive}"
}
main() {
if [ "${1:-}" = "--query" ]; then
target_branch
return
fi
remote="${1:-origin}"
branch="$(target_branch)"
set -x
git push --force-with-lease "${remote}" HEAD:refs/heads/"${branch}"
}
main "$@"发布于 2022-10-09 23:52:59
我一直在考虑解决同样的问题,并找到了一些工具:
更新:我尝试过git-chain,发现它很棒。级联多分支重基1命令和多推1命令正在满足我的需要。
我看了一下git-stack,但是复杂的命令引用令人望而生畏。
spr这次不适用于我,因为它是目前唯一的工具。
我已经把git-machete添加到列表中了,还没有尝试
https://stackoverflow.com/questions/61897602
复制相似问题