防止某些提交/代码合并到主分支中

4
我正在处理的项目中,我们决定开发一个工具来帮助开发,因此这是不应该在生产环境中使用的。
所以我想知道,既然git如此强大,是否有一种功能可以防止某些文件(是的,仅限文件:这是一个Magento项目,我们将开发的工具将位于自己的模块中,与应用程序的其余部分没有交集)合并到主分支中,但应该在其他分支中可用。
我们考虑使用git-flow,如果有帮助的话。因此,我们将拥有主分支,从中创建develop分支,从中创建所有功能分支。我们的想法是将此模块放在develop中,但永远不会合并回主分支。

我现在在思考,像忽略那些文件(.gitignore)只在主分支中这样的做法,这样行吗?

编辑1:项目结构
我觉得我需要更多关于项目结构的信息,它在这里:

+ main_folder/
    + magento/
    |---+ app/
    |   |--+ code/
    |   |  |--+ community/
    |   |  |--+ core/
    |   |  |--+ local/
    |   |     |--+ Namespace1/
    |   |        |--+ Module1/
    |   |        |--+ Module2/
    |   |     |--+ Namespace2/
    |   |        |--+ Module1/
    |   |        |--+ Module2/
    |   |--+ design/
    |   |  |--+ frontend/
    |   |     |--+ default/
    |   |        |--+ default/
    |   |           |--+ layout/
    |   |           |--+ template/
    |   +  js/
    |   +  lib/
    +  ezpublish/

开发工具模块必须包含在主项目中(仅限Magento部分)的不同位置,即app/code/local/Namespace1/Module3/、app/design/frontend/layout/dev.xml、app/design/frontend/template/dev/tool.phtml和js/dev/

编辑2:子模块选项
参考@VonC的答案,我已经做了以下工作:

  • 在主分支中:
    • git submodule add git@github.com:path/to/submodule.git devtool
    • cd devtool
    • git checkout 123abc #子模块的初始提交
    • cd ..
    • git add devtool
    • git commit -m "添加子模块的初始提交"
  • 在开发分支中:
    • cd devtool
    • git checkout abc213 #子模块的最后一次提交
    • cd ..
    • git add devtool
    • git commit -m "子模块在最后一次提交时的状态"
  • 回到主分支:
    • touch .gitattributes
    • 在 .gitattributes 中加入以下代码:devtool merge=ours
    • git add .gitattributes
    • git commit -m ".gitattributes 指令"

但是在主分支中,子模块的内容是最后一次提交的内容。如果我切换到主分支的初始提交并返回开发分支,初始提交仍然存在(而我希望得到的是开发分支中的最后一次提交)。
所以显然我做错了什么,但是是什么呢?


2
这可能是一个好点子,因为我不知道是否存在任何git构造来防止文件存在于一个分支中,除了.gitignore。问题在于你会一直拥有那个代码分支。而且,如果你的代码依赖于主分支中的代码,你就必须不断地将主分支合并或变基到你的工具分支上,但如果这不是问题,那就使用它吧。 - bitoiu
@bitoiu 代码不会依赖于主分支,所以这不是问题。但我找不到有关每个分支拥有不同.gitignore的任何信息。当我尝试时,当我将一个分支合并到主分支时,主分支的.gitignore也包括了该分支的内容。有关此事的任何信息吗? - OSdave
@OSdave,这是关于每个分支有不同.gitignore的问题:这里有一个很好的解释https://dev59.com/CHI-5IYBdhLWcg3weoPR(请查看“excludesfile”部分) - Shunya
@Meabed 还没有,刚开机,今天稍后会处理,我会随时通知你。 - OSdave
它能完成任务吗?你试过了吗? - Meabed
你应该尝试我的答案并加以改进,我相信这是最好的答案!!因为我也是Magento开发人员,并且正在为同样的目的使用它! - Meabed
3个回答

11

我非常推荐使用 子模块 将一组文件隔离到独立的仓库中。

思路是:如果你使用一个子模块,你只需要在父目录中防止合并一个元素(仅限一个):记录子模块 SHA1 的特殊条目
您不必担心子模块文件的合并。

您可以:


谢谢你的答案。我已经扩展了我的问题,说明了我认为我应该执行的步骤来应用你的建议。由于我不熟悉子模块,你介意审查一下我已经确定的步骤,并告诉我是否走在正确的道路上吗? - OSdave
@OSdave,gitattribute 应该包含添加到子模块的文件夹名称,而不是 SHA1 引用。该文件夹实际上作为特殊条目存储在 git 存储库中。 - VonC
我一定做错了什么:我已经编辑了我的问题并附上了我所做的内容,您能否帮忙检查一下看看是否能发现我的错误? - OSdave
@OSdave,在你的检出之后,你漏掉了一些 git submodule update - VonC
我尝试了所有的方法,但无法使其工作。当我切换回主分支时,子模块仍停留在最新的提交状态。我已经开始了一项奖励,希望能够得到详细而全面的答案,以使其正常工作。 - OSdave
显示剩余3条评论

2

最佳解决方案是使用git hooks!

下面是一个可行的例子:“我已经测试过并确保它可以正常工作”

用法:

git add . //添加所有文件,例如(包括要排除的文件)
git commit -am 'Test pre-commit' //提交所有文件,“pre-commit”钩子将运行


目录结构示例

|-- ex.file
|-- module
|   |-- f2.php
|   |-- f3.php
|   `-- file.php
`-- xml
    |-- file.xml
    `-- file1.xml

在你的git根目录中创建文件并将其命名为{.ignorefolders},用于排除你想要排除的文件或文件夹,“下面是一个示例”

/module/
/xml/file.xml
/ex.file

我在每行开头添加了“/”,因为我希望它与根目录相关。
“您可以添加完整的文件夹、单个文件”


在文件夹{.git/hooks}中创建名为{pre-commit}的文件,并填写以下内容:

ROOTDIR=$(git rev-parse --show-toplevel) #root folder
FILENAME="$ROOTDIR/.ignorefolders" #configuration file

if [ ! -f $FILENAME ]; then
    echo "File '.ignorefolders' not found!"
    exit 1
fi

BRANCHES=("master") # branches array to untrack this folders and files from if you want to remove this files from more than branch for example BRANCHES=("master" "branch2" "branch3")
CURRENTBRANCH=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p') #get current branch name

if [[ ! "$(declare -p BRANCHES)" =~ '['([0-9]+)']="'$CURRENTBRANCH'"' ]];then  #check if the current branch is NOT in the array of the branches
    exit 0
else
  echo "Executing pre-commit hook in $CURRENTBRANCH Branch"
fi

function removeFromGitAdd {
   PARAM="$ROOTDIR$1"
   if [ -e $PARAM ]; then
        #file or folder exist
        if [[ -n $(git ls-files $PARAM ) ]]; then
            #echo "there are files with this path added in the current commit"
            git rm --cached $PARAM -r #removing this files/folders
        else
            #echo "There is no file"
            echo ''
        fi
        
   fi
}
cat $FILENAME | while read LINE
do
       #echo $LINE
       removeFromGitAdd $LINE
done

注意:

代码已经很好地记录了(您可以在条件语句中使用exit或return),这取决于您想要的逻辑!

return ==> 提交将继续
exit ===> 提交将被中止

用例:

如果您添加了“git-add .”并且所有添加的文件都被配置文件“.ignorefolders”排除,然后尝试提交!
这些文件将从提交中删除,但您仍然可以提交一个空的“没有任何更改”的提交。


我严格按照您的指示操作,但是当我将分支(其中包含我不想要的文件)合并到主分支时,这些文件仍然存在于主分支中 :( - OSdave
我已经测试过了,它可以正常工作。pre-commit钩子是否有效?您能否看到此消息在主分支中执行pre-commit hook? - Meabed
我正在生产环境中使用它,它完美地工作!你能试试吗? - Meabed

2

在使用

git checkout <branch> 切换分支后,

你需要运行

git submodule update

这是为了解决你在 Edit 2 中描述的问题。

根据 VonC 的回答,gitsubmodule 对象是仓库中映射到 SHA 提交的一个对象,而不是子模块本身的内容。

因此,在初始化本地目录以包含此提交的内容时,需要运行 git submodule update 命令。在进行全新克隆或切换分支时,都需要运行此命令。你遇到的问题是,在切换分支时,子模块上一分支的内容仍然存在。运行 git submodule update 命令将用新分支的子模块对象所指向的内容替换掉那些内容。

编辑:

运行 git submodule update 命令会覆盖子模块中所有当前更改,以便与子模块对象正在指向的提交一致(在父仓库中)。如果要更改父仓库指向的提交,请在子模块中检出正确的版本,然后 cd .. 并提交对子模块对象的更改。


我已经尝试过了,但是当我执行 git submodule update 时,它会回到最新的提交。 - OSdave
你在develop分支中执行了'git submodule add'命令吗? - Johnny Z
我甚至没有到那里:在分支主线上,检出子模块的特定提交并执行 git submodule update 后,子模块又回到了最后一次提交,而我不想要这样(我想让子模块停留在先前的提交处,即没有代码的地方)。 - OSdave
切换到您的主分支并从顶层运行 git submodule status。在子模块旁边显示的提交哈希是否对应于您想要在主分支中的提交? - Johnny Z
看起来你正在覆盖子模块的内容。请查看我的最后一次编辑以了解有关覆盖子模块更改的信息。 - Johnny Z

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接