2013-10-24 37 views
2

是否有一种简单的方法来逐个推送所有提交的特征分支(从master开始),以便每次提交都会触发一个推送远程方面? 当您首先执行并提交失败的测试,然后进行修复时,这对于“测试优先”场景很有用。单独推送一个分支的所有提交,一个接一个

我知道我可以做git push sha:remote-ref-name,但手动操作很繁琐。

回答

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 
+0

这看起来不错,谢谢。任何你可以使用'git push ref:remote-branch'语法并避免'reset --hard'的机会? – krlmlr

+0

@krlmlr你不需要创建一个新的分支,也不需要做任何重置。您只需循环并将各个SHA1推送到远程分支。正如你所建议的(和我在我的回答中建议的)类似'git push origin SHA1:REMOTE_BRANCH'。 – jszakmeister

+0

@krlmr我已更新脚本以不创建新分支。 – cforbish

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被更新(和它的的 全名参考,而不是缩短版本)。您可能需要以某种方式为您的构建服务器提供 。

这一切都取决于您的特定设置。如果您的构建服务器只需轮询 轮询存储库的分支,那么您无法避免一次测试多个提交 。如果在推动时发出警告,那么它不会太过于使其变得更加智能。虽然你可能需要更多的逻辑。当推送中有多于x的提交时,您可能不想采取这种方法。想象一下拉动另一个项目的历史。它可能是成千上万的提交,并且您可能不希望在这种情况下单独测试它们。当分支分歧并计算需要测试的修订 时, 也可能是一些问题。您需要更仔细地测试一下 ,确保它展示您想要的行为。

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

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

+0

不幸的是,推钩(实际上,在GitHub上的特拉维斯CI钩)不*完全*在我的控制下,所以我真的更喜欢客户端解决方案。否则,是的,我相信一个合适的服务器端钩子是一条可行的路线。 – krlmlr

+0

这对于预先知道会非常有帮助。 – jszakmeister

+0

对不起。然而,尽管大多数的文章都不能帮助我解决当前的问题(尽管对rev-list和githook的引用最为有用),但它对其他人可能会有所帮助,或者可以帮助我解决将来的问题。所以,非常感谢! – krlmlr

1

@ cforbish的承诺清单并没有做什么,我觉得提问者(和我)需要:获取一个列表,以便形成最旧到最新,提交的是还没有推到。这奏效了,我(他欣赏的脚本,我在这里省略通过硬连线的一般性的一些事情):

#!/bin/bash 

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

您的解决方案与@cforbish的不同之处在于使用'..'符号,省略'--not --remotes'并使用强制推送。这些修改中的哪一个使它适合您? – krlmlr

+0

@krlmlr:当我使用他的@cforbish的'for'语句时,我只有3个提交列表,当时我比主要人员(从SVN转换)高出200多个。如果我记得Git在我手动尝试时请求'-f'。 – pelesl

+0

这就是我正在寻找的。 – ferit

相关问题