一个接一个地推送分支的所有提交

时间:2013-10-24 09:13:05

标签: git push githooks git-push

是否有一种简单的方法可以逐个推送功能分支的所有提交(例如,从master开始),以便每个提交触发远程端的推送挂钩? 当您首先实现并提交失败的测试然后修复时,这对于“测试优先”场景非常有用。

我知道我可以做git push sha:remote-ref-name,但手动做是很乏味的。

3 个答案:

答案 0 :(得分:1)

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

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

$ git rev-list OLD_SHA1..NEW_SHA1

这将包括从合并中引入的个人提交。你可以 或者可能不想单独测试它们,因为它们可能已经过测试 到你的工作流程。因此,您只能将其限制为主线提交:

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

但有一些边缘案例:

  • 分支可以重新定位。您想重新测试新的重新提交的提交吗? 以前版本的分支中存在哪些?

  • 分支可能是新的。你不想重新测试整个历史 虽然分支。您使用什么分支来确定已测试的内容 已经? 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

请注意,您在$refname中更新了ref的名称(而且它是 ref的全名,而不是缩短版本)。你可能需要这样做 不知怎的,你的构建服务器。

这一切都取决于您的特定设置。如果你的构建服务器简单 轮询存储库的分支,然后您无法避免测试多个 一次提交。如果它在推动时倾斜,那么它不会太多 更进一步,使它更聪明。您可能需要更多逻辑。你可以 当推送中有超过x次提交时,不想采用这种方法。 想象一下,拉进另一个项目的历史。它可能是成千上万的 提交,在这种情况下你可能不想单独测试它们。那里 当分支机构分歧并计算修订时,也可能存在一些问题 需要测试。你想要更彻底地测试一下 确保它表现出你想要的行为。

顺便说一下,githooks对于确定很有用 什么被传递到剧本。

您也可以在客户端进行单独推送,但不是没有 一些脚本。您可以使用类似于上面的git rev-list,其中 $newrev将是您当地分支的当前提示。 $oldrev可以接受 master(或develop)或@{upstream},如果您之前推过了分支。 关键是你可以使用git rev-list来帮助提交列表 推,然后逐个推动每一个。我不推荐这种方法,但是 它可以做到。

答案 1 :(得分:1)

此脚本应该有效:

#!/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

答案 2 :(得分:1)

@cforbish的提交列表没有做我认为提问者(和我)所需要的:从最旧到最新的顺序获取一个没有被推送的提交的列表然而。这对我来说很有把握(欣赏他的剧本的一般性,我通过硬连接某些东西来省略这些):

#!/bin/bash

for rev in $(git rev-list --reverse origin/master..HEAD);
do
    git push -f origin ${rev}:master
done