全局重置git分支(适用于所有用户)

时间:2015-02-24 23:54:13

标签: git github git-branch remote-branch

在我们当前的工作流程中,我们有两个主要的git分支:

master - 稳定发布分支

testing - 每个人都测试他们的代码

现在每个开发人员都为他们开发的每个功能创建新的分支。完成后,他们会将其合并到testing,当我们的质量检查表明它很好时,他们会将他们的分支合并到master,并将其部署到生产中。

随着时间的推移,我们的testing分支受到了从未进入生产状态的提交的污染。被遗弃的功能,被改写而不是固定的东西和其他东西。

为了使mastertesting处于某种程度上一致的状态,我们希望不时“重置”testing。现在,我们通过完全删除testing并从master重新分支来实现此目的。

这里的一个大问题是我们需要确保每个开发人员都删除他的本地testing分支并检查它的新副本。 如果一个开发人员忘记这样做并再次推送测试,那么我们试图摆脱的所有脏提交都会回来。

有没有办法以分发给所有用户的方式重置服务器上的分支?

一个可接受的解决方案也是将testing分支置于一个没有人可以在不进行本地重置的情况下再推送它的状态。但我想不出怎么做的方法。

mastertesting之间创建差异并且还原提交不是一个选项,因为这会阻止每个提交再次进入测试。

理想情况下,我有一个脚本定期执行此重置,并且每个用户本地环境都不需要交互(git pull除外)。

4 个答案:

答案 0 :(得分:2)

  

随着时间的推移,我们的测试分支受到了从未进入生产的提交的污染。被遗弃的功能,被改写而不是固定的东西和其他东西。

这怎么可能?显然,如果一个功能被放弃,那么你应该从测试分支中删除它,因为它似乎是你的守门员。基本上,如果你说你的测试分支被时间污染了,那么它就会破坏测试分支的整个目的,因为现在你正在测试一些不代表你想要推向生产的代码的东西。

如果某些事情没有成功,那么开发人员应该恢复他的更改并将提交推送到测试分支,其中变更也会被恢复。

在您的场景中,您应该从测试到生产合并全部或全部。

答案 1 :(得分:2)

简短的回答是"不,你不能这样做"。

请记住,每个克隆都是一个完整的独立实体 1 ,它与克隆的源存储库略有不同,除了它的origin和(取决于克隆选项) )一些初始分支状态。 2 一旦有人拿起一个名为testing的分支并将其称为origin/testing

  • 他们有你让他们拥有的承诺;和
  • 他们有一个名为origin/testing的引用("远程跟踪分支"),他们的git将自动更新,甚至在指示时修剪(删除),当他们连接到远程{{1 }}。

到目前为止一直很好,这个"自动修剪"行动听起来很棒。如果您可以说服他们将origin设置为remote.origin.prune

true

然后,当您删除名为$ git config remote.origin.prune true 分支时,他们的 testing会在下一次自动消失origin/testing

他们创建名为git fetch origin的分支时,问题就出现了。他们的git 不会删除此分支,除非直到他们要求它。就他们的git而言,他们的私人分支机构是他们的私人分支机构。你不能说服他们的git删除他们的私人testing,而不是说服他们的git删除他们的私人testing。他们创造了它;它是他们的存储库;他们控制着它。

(请注意,他们也可以控制自动修剪,因为他们可以随时experiment-22设置git configremote.origin.prune。此设置适用于他们的便利性,不是你的 - 它与false设置一致,他们更改了remote.origin.fetch更改了它的功能;它的初始默认设置是他们在git fetch运行时创建的。 )

可以继续使用此模型,只要您让所有开发人员自行控制删除或清除此分支标签。但这不是可行的方法。相反,您应该使用另一种模型:为您的开发人员创建一个新的不同的分支标签,用于您正在进行的新(和不同)开发项目。

例如,您可能有git clone作为临时分支,您的开发人员可以共享这些分支以处理功能X.当您完成所有操作后,您可以随意保留或删除它,以及您的开发人员会自动选择删除(使用修剪设置),或者不是闲暇时。与此同时,您已创建dev-feature-X作为临时分支,您的开发人员可以共享这些分支以处理功能Y,依此类推。


1 忽略特殊情况,如"浅"克隆在这里不适用,至少。

2 如果您在没有dev-feature-Y的情况下进行克隆,则源的分支将成为您的远程分支,并且在您检出一个分支之前根本没有本地分支(通常为{{ 1}},通常作为--mirror命令的最后一步)。此外,克隆无法查看源的钩子,因此不会克隆它们。 master目录中的任何其他特殊状态都不存在,例如clone中的项目。但是,这些都不会影响普通分支使用的原则。

答案 2 :(得分:1)

一种选择是通过以特殊方式合并主分支来重置开发分支的状态。

git checkout master
git checkout -b new_testing
git merge -s ours testing # this creates a merge commit, but
                          # its tree is that of the current work-tree
                          # which in our case is the same as master
git checkout testing
git merge ours_testing
git branch -d new_testing

我们需要创建临时new_testing分支,因为合并策略ours保留当前树而不是其他树,并且没有等效的theirs策略。

在此之后,您将得到像

这样的分支结构
*         (testing) merge
|\
| *       (master) last commit on master
* |       last commit on testing
| |

但测试内容与主人的内容相符。

这样做的好处是任何有本地提交测试的人 last commit on testing能够将更改重新加入origin/testing之后发生的事情已经发生。

因为这不应该打断通常的开发流程,所以没有理由不能频繁地进行(夜间?)。

答案 3 :(得分:1)

  

如果一个开发人员忘记[rebase]并再次推送到testing,那么我们试图摆脱的所有脏提交[来自被遗弃的testing提示]都会回来。

您无法控制其他人的回购内容,但您可以控制他们推送给您的内容。

  

一个可接受的解决方案也是将测试分支置于一个没有人可以在不进行本地重置的情况下再推送它的状态。但我无法想办法如何做到这一点。

此预接收挂钩将拒绝推送通过合并引入不需要的历史记录:

#!/bin/sh
#  Do not permit merges from unwanted history
#set -x
err=0
while read old new ref; do              # for each pushed ref

        [[ ${old%[^0]*} = $old ]] && continue # new branches aren't checked.

        nomerge=$(git for-each-ref refs/do-not-merge --format='%(objectname)^!')

        if [[ $( git rev-list --count --ancestry-path --boundary $old..$new $nomerge
         ) != $( git rev-list --count --ancestry-path --boundary $old..$new ) ]]; then
                echo "$ref doesn't allow merges from outdated history"
                err=1
        fi
done
exit $err

# why it works:

# if adding nomerge commits' parents as ancestors has any effect, then the
# nomerge commits are reachable without going through $old, i.e. they're 
# in some merged history. So check whether adding the abandoned commits as
# explicit ancestors to the push makes them show up, and refuse it if so.

要标记不需要的提交,请参阅refs/do-not-merge下的提交,例如

git config alias.no-further-merges-from \
  '!f() { git update-ref "refs/do-not-merge/$1-@`date +%Y-%m-%dT%H%M%S`" "$1"; }; f'

所以放弃testing的仪式是

git no-further-merges-from testing
git checkout -B testing master

如果您想标记以前放弃的提示,可以通过sha或任何其他表达来引用它们,例如

git no-further-merges-from 'testing@{last october 31}'