如何设置 git 驱动程序以忽略合并时的文件夹?

发布于 2024-09-06 14:00:02 字数 707 浏览 9 评论 0原文

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

显然,做到这一点的方法是通过合并驱动程序。因此,我创建了“ignore”驱动程序:

[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 文件夹?

I have the master branch, where all the main code resides, and the design branch, where the layout of the rails application is built by the design team. They have added a folder called "photoshop" to the public folder to keep their sources for the images also under version control. But I don't want this folder to be copied on merge to the master branch because, well, it is not needed.

Apparently, the way to do this is through a merge driver. So, I've created the "ignore" driver:

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

And created the ignore.sh file on my $PATH:

exit 0

I've created the .gitattributes file inside public/, because the photoshop folder should be ignored in whole and it is going to appear under public/:

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

As you can see, I've tried several different patterns to ignoring the whole folder, but it does not work. I believe this is because there is no folder on the master branch, so there's no conflict and so git doesn't use the ignore driver. Is there a way to achieve this without having to create a public/photoshop folder on master?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故事未完 2024-09-13 14:00:02

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

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

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

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

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"

这是完整的脚本:

git-strip-merge

#!/bin/bash
#
# git-strip-merge - a git-merge that delete files on branch before merging
#
#    Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]>
#
#    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) <[email protected]>
    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"

合并前:

enter image description here

合并后:

enter image description here

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

As suggested by my other answer, here goes the extended, generalized, industrial-strength version of the solution.

(yes, I was bored at home and had nothing else better to do :P)

This script will add a new, detached commit based on your local design branch, so it won't affect neither the design repository or your design branch. The commit will have all desired files removed. Then it performs the merge.

For those too lazy to read the full code, the "core" of these steps can be simplified as:

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"

And here is the full script:

git-strip-merge

#!/bin/bash
#
# git-strip-merge - a git-merge that delete files on branch before merging
#
#    Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]>
#
#    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) <[email protected]>
    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"

Before merge:

enter image description here

After merge:

enter image description here

Note that "design" branch tip wasn't affected at all, even being a local branch, thanks to the detached commit trick. Other than that, both commits (the removal and the merge) are regular commits, with suitable commit messages and parents. And "master" branch is clean of any undesired files.

毁梦 2024-09-13 14:00:02

关于.gitignore的一些注意事项:

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

在您的场景中,不需要.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

A few notes about .gitignore:

.gitignore is for ignoring files from the working tree to be added to index (staging area). So it is only effective when you use git add <files>, and it can still be overridden using git add --force <files>. It is meant just as a convenience to prevent unwanted files from being added, but it has no effect on files inside the repository

In your scenario, .gitignore is not needed, since you don't have any local ./photoshop folder, so you will never have any photoshop files to add to your master branch. It wouldn't hurt, however, to create one just in case. And for the design team .gitignore is not welcome, since they want photoshop files to be added to their branch.

So, since merge deals with committed data, and ./photoshop files are already inside the repository, your approach of using a a merge driver was correct.

The problem is... by default a merge driver is only triggered in case of conflicts. And, since master branch does not have any ./photoshop folder or files, there are no conflicts at all, they are cleanly merged. So your merge driver also had no effect, regardless of your path patterns (by the way, your 2nd one, photoshop/, was the correct one). I don't know if git merge can be configured to trigger a merge driver even for non-conflicting files, but it's worth googling for.

My answer is not a true solution to your problem. I just hoped to shed some light on the subject, explaining why your attempts using merge driver and .gitignore have failed. I suggest reading more about (configuring) merge drivers. Also submodules is worth investigating.

UPDATE

Maybe my other answer will help you:

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

git-strip-merge

停滞 2024-09-13 14:00:02

您是否尝试在 master 分支中添加 .gitignore 文件来忽略任何 photopshop 目录内容?
然后,从设计到 master 的合并不应在 master 中添加该新目录。

如果这有效,您仍然需要合并驱动程序,但这次是为了管理 .gitignore 文件的内容。

Did you try adding a .gitignore file in your master branch, to ignore any photopshop directory content ?
Then a merge from design to master shouldn't add that new directory in master.

If this works, you still needs a merge driver, but this time to manage the content of the .gitignore file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文