我有一个hacky shell脚本,用于清理功能分支上的历史记录,当时我正在与那些不了解rebasing如何工作并且有数百个混乱提交和多个合并提交的人一起工作,这意味着它是不可能做单个壁球或修复交互式rebase。
这个脚本基本上会在他们的分支中创建一个单独的压缩提交,而不管他们是如何合并的。
但它真的很hacky,有没有现成的git命令呢?或者是否有更惯用的方式来编写脚本?
#!/bin/bash
set -e
if [ -n "$(git status -s)" ] ; then
echo "ERROR: uncommitted changes"
exit 1
fi
if [ -z "$1" ] ; then
echo "ERROR: you must provide a base branch"
exit 1
fi
NAME=`git rev-parse --abbrev-ref HEAD`
CUR=`git rev-parse HEAD`
TO=`git rev-parse $1`
echo "backing up your branch in bak/$CUR"
git checkout -b bak/$CUR
git checkout -b tmp/$CUR
git reset --hard $TO
git merge --squash $CUR
git commit --no-edit
git checkout $NAME
git reset --hard tmp/$CUR
git branch -D tmp/$CUR
echo "created a squash commit against $1 and rewrote your history"
答案 0 :(得分:2)
...是否有现成的git命令执行此操作?
否:就最终提交和分支名称的位置而言,至少需要三个才能完成您的工作:
git branch
创建一个新的分支名称,指向由HEAD
标识的提交; git reset --soft
将当前分支名称移动到目标提交而不更改索引和工作树; git commit
进行新提交。为新提交(由git merge --squash
构建的提交)获取所需的日志消息需要其他命令。要让git merge --squash
为构建消息,您必须使用git merge --squash
或重复其逻辑(检查merge.branchdesc
和merge.log
设置,运行各种Git命令根据这些设置提取适当的字符串。)
或者是否有更惯用的方式来编写脚本?
好吧,如果您想将它作为贡献脚本提交给Git:那么您可能希望直接使用git-sh-setup
和许多较低级别的管道命令,并插入更多错误检查(例如,什么当$1
无法正确git rev-parse
时脚本应该执行吗?在完全空的存储库中它应该做什么,即使HEAD
无效?)。但这会使脚本更加冗长 - 不像rebase代码那样〜2000行怪物:
$ wc -l git-rebase*sh
103 git-rebase--am.sh
1042 git-rebase--interactive.sh
169 git-rebase--merge.sh
648 git-rebase.sh
1962 total
但仍然比现在长很多。
除此之外:通常,执行此类操作的Git命令根本不会设置备份分支名称。相反,他们依靠Git的 reflogs 作为分支名称,以及保留前一个设置的ORIG_HEAD
名称。如果您要省略备份分支并使用git reset --soft && git commit -F $msg_temp_file
,您将获得相同的行为 - 但是您必须再次在临时文件中构造合并消息。或者,由于git reset
和git merge --squash
都设置了ORIG_HEAD
,如果您使用git merge --squash
创建新合并,则必须使用git update-ref
来设置ORIG_HEAD
返回正确的值。
当然,两者都会显着改变可观察行为。