14

我已经进行了广泛的搜索,阅读了很多 SO 问题和解决方案并尝试了不同的方式,但是我无法做我想做的事,这很简单。

我有 master 分支,所有主要代码都驻留,设计分支,rails 应用程序的布局由设计团队构建。他们在公共文件夹中添加了一个名为“photoshop”的文件夹,以使他们的图像来源也受到版本控制。但我不希望在合并时将此文件夹复制到主分支,因为不需要它。

显然,这样做的方法是通过合并驱动程序。所以,我创建了“忽略”驱动程序:

[merge "ignore"]
name = always ignore during merge
driver = ignore.sh %0 %A %B

并在我的 $PATH 上创建了 ignore.sh 文件:

exit 0

我已经在 public/ 中创建了 .gitattributes 文件,因为应该完全忽略 photoshop 文件夹,它将出现在 public/ 下:

photoshop  merge=ignore
photoshop/ merge=ignore
photoshop/* merge=ignore
photoshop/**/* merge=ignore

如您所见,我尝试了几种不同的模式来忽略整个文件夹,但它不起作用。我相信这是因为 master 分支上没有文件夹,所以没有冲突,所以 git 不使用忽略驱动程序。有没有办法实现这一点而无需在 master 上创建 public/photoshop 文件夹?

谢谢!

4

3 回答 3

20

正如我的另一个答案所建议的,这里是解决方案的扩展、通用、工业强度版本。

(是的,我在家里很无聊,没有其他更好的事情可做:P)

此脚本将根据您的本地设计分支添加一个新的分离提交,因此它不会影响设计存储库或您的设计分支。提交将删除所有需要的文件。然后它执行合并。

对于那些懒得阅读完整代码的人来说,这些步骤的“核心”可以简化为:

original=$(gitbranch HEAD)    # current branch name, or sha1 if not in a branch
branchsha=$(gitsha "$branch") # sha1 of a ref, to force detached commit

git checkout "$branchsha"   &&
git rm -rf "${files[@]}"    &&
git commit -m "$msgcommit"  &&
newsha=$(gitsha HEAD)       &&
git checkout "$original"    &&
git merge -m "$msgmerge" "${mergeopts[@]}" "$newsha"

这是完整的脚本:

(稍作修改以应对弱且有限的 SO 语法着色,因此最好从下面的链接获取原始源)

git-strip-merge

#!/bin/bash
#
# git-strip-merge - a git-merge that delete files on branch before merging
#
#    Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program. If not see <http://www.gnu.org/licenses/gpl.html>
#
# Answer for "How to setup a git driver to ignore a folder on merge?"
# See http://stackoverflow.com/questions/3111515

#Defaults:
msgcommit="remove files from '<branch>' before merge"
msgmerge="Merge stripped branch '<branch>'"
verbose=0
quiet=(--quiet)

usage() {
    cat <<- USAGE
    Usage: $myname [git-merge options] [-M <commitmsg>] <branch> FILE...
    USAGE
    if [[ "$1" ]] ; then
        cat >&2 <<- USAGE
        Try '$myname --help' for more information.
        USAGE
        exit 1
    fi
    cat <<-USAGE

    "git-merge that delete files on "foreign" <branch> before merging

    Useful for ignoring a folder in <branch> before merging it with
    current branch. Works by deleting FILE(S) in a detached commit based
    on <branch>, and then performing the merge of this new commit in the
    current branch. Note that <branch> is not changed by this procedure.
    Also note that <branch> may actually be any reference, like a tag,
    or a remote branch, or even a commit SHA.

    For more information, see <http://stackoverflow.com/questions/3111515>

    Options:
      -h, --help
         show this page.

      -v, --verbose
         do not use -q to supress normal output of internal steps from git
         checkout, rm, commit. By default, only git merge output is shown.
         Errors, however, are never supressed

      -M <message>, --msgcommit=<message>
         message for the removal commit in <branch>. Not to be confused
         with the message of the merge commit, which is set by -m. Default
         message is: "$msgcommit"

      -m <message>, --message=<message>
         message for the merge commit. Since we are not merging <branch>
         directly, but rather a detached commit based on it, we forge a
         message similar to git's default for a branch merge. Otherwise
         git would use in message the full and ugly SHA1 of our commit.
         Default message is: "$msgmerge"

      For both commit messages, the token "<branch>" is replaced for the
      actual <branch> name.

    Additional options are passed unchecked to git merge.

    All options must precede <branch> and FILE(s), except -h and --help
    that may appear anywhere on the command line.

    Example:
      $myname design "photoshop/*"

    Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
    License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>"
    USAGE
    exit 0
}

# Helper functions
myname="${0##*/}"
argerr()  { printf "%s: %s\n" "${0##*/}" "${1:-error}" >&2 ; usage 1 ; }
invalid() { argerr "invalid option: $1" ; }
missing() { argerr "missing ${2:+$2 }operand${1:+ from $1}." ; }

# Option handling
files=()
mergeopts=()
for arg in "$@"; do case "$arg" in -h|--help) usage ;; esac; done
while (( $# )); do
    case "$1" in
    -v|--verbose  ) verbose=1            ;;
    -M            ) shift ; msgcommit=$1 ;;
    -m            ) shift ; msgmerge=$1  ;;
    --msgcommit=* ) msgcommit=${1#*=}    ;;
    --message=*   ) msgmerge=${1#*=}     ;;
    -*            ) mergeopts+=( "$1" )  ;;
    *             ) branch="$1"
                    shift ; break        ;;
    esac
    shift
done
files+=( "$@" )

# Argument handling

msgcommit=${msgcommit//<branch>/$branch}
msgmerge=${msgmerge//<branch>/$branch}

[[ "$msgcommit" ]]  || missing "msgcommit" "MSG"
[[ "$branch"   ]]   || missing ""          "<branch>"
(( ${#files[@]} ))  || missing ""          "FILE"

((verbose)) && quiet=()

# Here the fun begins...
gitsha()    { git rev-parse "$1" ; }
gitbranch() {
    git symbolic-ref "$1" 2> /dev/null | sed 's/refs\/heads\///' ||
    gitsha "$1"
}

original=$(gitbranch HEAD)
branchsha=$(gitsha "$branch")

trap 'git checkout --quiet "$original"' EXIT

git checkout "$branchsha"  "${quiet[@]}" &&
git rm -rf "${files[@]}"   "${quiet[@]}" &&
git commit -m "$msgcommit" "${quiet[@]}" &&
newsha=$(gitsha HEAD)                    &&
git checkout "$original"   "${quiet[@]}" &&
git merge -m "$msgmerge" "${mergeopts[@]}" "$newsha"

享受!

一张图胜过千言万语……

合并前:

在此处输入图像描述

合并后:

在此处输入图像描述

请注意,由于分离提交技巧,“设计”分支提示根本没有受到影响,即使是本地分支。除此之外,两个提交(删除和合并)都是常规提交,具有合适的提交消息和父级。并且“master”分支清除了任何不需要的文件。

于 2012-04-19T01:04:47.540 回答
10

本身不是一个答案,而是一些关于.gitignore:它不会在你的场景中帮助你的注释。

.gitignore用于忽略工作树中要添加索引(暂存区)的文件。所以它只有在你使用时才有效git add <files>,并且仍然可以在使用时被覆盖git add --force <files>。这只是为了方便防止添加不需要的文件,但它对存储库中的文件没有影响

在您的场景中,.gitignore不需要,因为没有任何本地./photoshop文件夹,因此您永远不会有任何 Photoshop 文件要添加到您的主分支。但是,为了以防万一,创建一个也没有什么坏处。并且对于设计团队.gitignore来说是不受欢迎的,因为他们希望将 Photoshop 文件添加到他们的分支中。

因此,由于合并处理已提交的数据,并且./photoshop文件已经在存储库中,因此您使用合并驱动程序的方法是正确的。

问题是……默认情况下,只有在发生冲突时才会触发合并驱动程序。而且,由于master分支没有任何./photoshop文件夹或文件,因此根本没有冲突,它们被干净地合并了。因此,无论您的路径模式如何,您的合并驱动程序也没有任何效果(顺便说一下,您的第二个photoshop/,,是正确的)。我不知道是否可以将 git merge 配置为即使对于非冲突文件也可以触发合并驱动程序,但值得一试。

正如我之前所说,我的回答不是真正解决您的问题。我只是希望对这个主题有所了解,解释为什么您使用合并驱动程序和 .gitignore 的尝试失败了。我建议阅读更多关于(配置)合并驱动程序的信息。子模块也值得研究。

希望这可以帮助!

更新

也许我的其他答案会对您有所帮助

Usage: git-strip-merge [git-merge options] [-M <commitmsg>] <branch> FILE...

git-strip-merge

享受!

于 2012-03-09T23:08:10.297 回答
0

您是否尝试在分支中添加.gitignore文件以忽略任何目录内容? 然后从设计合并到不应该在.masterphotopshop
mastermaster

如果这可行,您仍然需要一个合并驱动程序,但这次是管理.gitignore文件的内容。

于 2010-06-24T16:23:02.260 回答