4

Is there an easy way to push all commits of a feature branch (starting from, say, master) individually, one after one, so that each commit triggers a push hook on the remote side? This is useful for "test-first" scenarios when you implement and commit first a failing test and then a fix.

I know I can do git push sha:remote-ref-name, but it's tedious to do manually.

4

3 回答 3

3

该脚本应该可以工作:

#!/bin/bash

if [ ! -d .git ]; then
    echo "$(basename $0): not a git directory." 1>&2
    exit 1
fi

# lbranch - name of local branch
# remote  - name of remote
# rbranch - name of remote branch
lbranch=$(git rev-parse --abbrev-ref HEAD)
remote=$(git config branch.${lbranch}.remote)
rbranch=$(git config branch.${lbranch}.merge)
rbranch=${rbranch/refs\/heads\//}

for rev in $(git rev-list --reverse ${lbranch} --not --remotes);
do
    git push ${remote} ${rev}:${rbranch}
done
于 2013-10-24T12:22:00.433 回答
1

我不确定为什么这对测试优先场景有好处,除非您的意思是通过一次触发构建一个提交,您实际上会看到构建失败然后成功。

也就是说,您只需拥有一个更好的钩子脚本服务器端即可获得您想要的东西。挂钩脚本同时接收旧的post-receivesha1 和新的 sha1,因此您可以计算中间的修订列表:

$ git rev-list OLD_SHA1..NEW_SHA1

这也将包括从合并中引入的单个提交。您可能希望也可能不希望单独测试它们,因为它们可能已经由于您的工作流程而进行了测试。因此,您只能将其限制为主线提交:

$ git rev-list --first-parent OLD_SHA1..NEW_SHA1

但是有一些边缘情况:

  • 可以重新设置分支。你想重新测试以前版本的分支中存在的新的 rebased 提交吗?

  • 分支可能是新的。不过,您不想重新测试分支的整个历史记录。您使用哪个分支来确定已经测试过的内容? master?

  • 可以删除分支。这个案子很简单……你可能什么都不做。

post-receive这是读取挂钩中更新的参考的示例:

#!/bin/bash

# The current working directory will be in the bare repo being updated.

while read oldrev newrev refname
do
    # Skip deleted branches.
    if [ "$newrev" != "0000000000000000000000000000000000000000"]
    then
      if [ "$oldrev" == "0000000000000000000000000000000000000000"]
      then
          # New branch.  Test all commits in the branch by using master
          # as a base.  If this was master being created, then nothing will
          # get triggered.
          oldrev=$(git merge-base master $newrev)
      fi

      for sha1 in $(git rev-list ${oldrev}..${newrev})
      do
          # Tip off build server for each commit between oldrev and newrev
          tip-off-build-server $sha1
      done
    fi
done

请注意,您有正在更新的 ref 的名称$refname(它是 ref 的全名,而不是缩短的版本)。您可能需要以某种方式为您的构建服务器调整它。

所有这些也取决于您的特定设置。如果您的构建服务器只是轮询存储库的分支,那么您无法避免一次测试多个提交。如果它在推送时得到提示,那么让它变得更聪明也不会太远。不过,您可能需要更多的逻辑。x当推送中有多个提交时,您可能不想采用这种方法。想象一下拉入另一个项目的历史。它可能是数千个提交,在这种情况下您可能不想单独测试它们。当分支分歧并计算需要测试的修订时,也可能存在一些问题。您需要对其进行更彻底的测试,以确保它表现出您想要的行为。

顺便说一句,githooks对于确定传递给脚本的内容很有用。

您也可以在客户端进行单独的推送,但不能没有一些脚本。您可以使用git rev-list与上述类似的方法, $newrev本地分支的当前提示在哪里。 $oldrev可能会出现 master(或develop),或者@{upstream}如果您之前已经推送过分支。关键是您可以使用git rev-list来帮助推送提交列表,然后单独推送每个提交。我不推荐这种方法,但可以做到。

于 2013-10-24T10:12:21.540 回答
1

@cforbish 的提交列表没有做我认为提问者(和我)需要的:获取尚未推送的提交的列表,从最旧到最新。这对我有用(欣赏他的脚本的一般性,我在这里通过硬连线一些东西省略了):

#!/bin/bash

for rev in $(git rev-list --reverse origin/master..HEAD);
do
    git push -f origin ${rev}:master
done
于 2015-07-13T00:14:45.073 回答