使用git,如何在一个分支中忽略一个文件,但在另一个分支中提交它?

184

我有一个项目要部署到Heroku,源代码树包含一堆MP3文件(该网站将用于一个我深度参与的录音项目)。

我想将源代码放在GitHub上,但GitHub的免费账户有300 MB的限制。我不想在一堆MP3文件上使用50MB的限制。显然,我可以将它们添加到.gitignore文件中以将其排除在我的存储库外。

但是,我使用git push heroku进行部署。MP3文件必须存在于我推送到Heroku的分支中,以便它们被部署。

理想情况下,我希望在本地主分支中.gitignore MP3文件,这样当我将其推送到GitHub时,不会包括MP3文件。然后我会保留一个本地生产分支,其中包含提交的MP3文件而不是被忽略的。要部署,我将主分支合并到生产分支,然后将生产分支推送到Heroku。

我无法使这个过程正确运行。

以下是我尝试做的示例...

$ git init git-ignore-test
$ cd git-ignore-test
$ echo "*.ignored" >> .gitignore
$ git add .gitignore && git commit -m "Ignore .ignored files"
$ touch Foo.ignored

目前,在我的主分支中,Foo.ignored被忽略了,但它仍然存在,因此我的项目可以使用它。

$ git checkout -b unignored
$ cat /dev/null > .gitignore
$ git add Foo.ignored .gitignore && git commit -m "Unignore .ignored files"
现在我已经有一个分支,这些文件已经提交,正如我所希望的。然而,当我切换回我的主分支时,Foo.ignored 文件消失了。
有人有更好的设置建议吗?
编辑:为了澄清,我希望 mp3 文件在两个分支中都存在,以便在本地运行站点(使用任一分支)时,站点能够工作。我只想在一个分支中忽略文件,以便当我推送到 GitHub 时,它们不会被推送。通常 .gitignore 对于这种情况效果很好(即保留一个本地副本,不包括在远程推送中的文件),但是当我切换到已检入文件的分支,然后切换回已忽略文件的分支时,文件就会消失。

4
使用Heroku时,将代码提交到您的代码库是部署应用程序时获取文件的唯一途径。唯一的替代方法是使用类似Amazon S3这样的服务来提供mp3文件,但我更喜欢避免这种方式。 - Myron Marston
3
我注意到你标记了一个答案为正确,但根据我所读的,它可能并不正确。你有尝试过这个答案吗?它对你有用吗? - loop
@MyronMarston,你是如何克服这个挑战的? - user805981
这个问题解决了吗?我也遇到了几乎相同的问题。假设我有一个用于生产的“master”分支和一个用于开发的“development”分支。“master”分支忽略源文件(例如由“gulp”组装),而“development”分支忽略这些组装和压缩的文件。当我在“master”和“development”之间切换时,我的文件会不断消失,导致一切都崩溃 :( - Anton Egorov
这也是一个实际问题,适用于任何FORKED A REPO并希望保留分支以进行贡献、同时将其作为应用程序在单独的分支上使用的人。每次他们使用框架分支找到改进时,都可以切换回fork-origin分支,然后推送他们的修复。这就是我遇到的问题。我想忽略某些文件,比如主页,这样我就可以确保在索引模板上添加H2标签来识别自己,这样我就不会弄混了。对主页进行快速编辑,然后仅在该分支上进行忽略。 - blamb
显示剩余4条评论
9个回答

85

这个解决方案似乎只适用于某些经过修补的git版本。请参见一个新答案指向的解决方法另一个回答和随后的评论,以获取哪些版本可能会起作用的提示。

我写了一篇关于如何有效地使用excludesfile来处理不同分支的博客文章,例如一个用于公共github,另一个用于heroku部署。

以下是快速简单的步骤:

$ git branch public_viewing
$ cd .git/
$ touch info/exclude_from_public_viewing
$ echo "path/to/secret/file" > info/exclude_from_public_viewing 

然后在 .git/config 文件中添加以下行:

[core]
excludesfile = +info/exclude

  
[branch "public_viewing"]
excludesfile = +info/exclude_from_public_viewing

现在所有的全局忽略设置都在info/exclude文件中,而分支特定的设置则在info/exclude_from_public_viewing文件中。

http://cogniton-mind.tumblr.com/post/1423976659/howto-gitignore-for-different-branches


1
抱歉等了这么久...但如果你不删除.gitignore文件,它会默认使用那些文件。 - Cognition.Mind
4
即使项目没有使用.gitignore,这对我也不起作用。您是否介意提供一份从头开始设置的命令副本(git init, ...),以及您所使用的 Git 版本? - Davor Cubranic
40
这个解决方案不可行。博客上有一些讨论,但没有人能够使它起作用。 - spuder
3
在标准版的Git中,我相当确定这是不可行的,并且从未可行过。如果你们中有人能够复现它,请分享你们的Git版本和其他相关环境信息。也许你们使用的是由Linux发行版提供的经过修补的Git软件包。 - Palec
显示剩余8条评论

29

重要提示:Cognition.Mind所提供的被接受的答案(已经)不能用于解决关于 git 的问题 (可能是多年前的答案,或者只适用于git原始版本); 请参阅评论以了解有效的解决方案和解决办法:

https://dev59.com/lV0b5IYBdhLWcg3wIOF-#29583813

另一种替代解决办法(适用于我的特定问题,但需要手动执行存储操作或实现hook) 即 git stash -u -a. 当差异很大时这种方法很繁琐。

最后,我现在采用的解决方案是 fork 我们开发环境中的虚拟机,并为该分支设置相应的 info/excludes,然后删除有问题的未提交文件/文件夹。


16

假设我们希望忽略除production分支外的所有其他分支中的build文件夹, 因为我们想要将build文件夹推送到生产环境。

1)不要在.gitignore中包含build。如果这样做,它将始终被所有分支忽略。

2)在./.git/info目录下创建一个名为exclude_from_public_viewing的文件(该文件夹已存在)。执行命令:touch ./.git/info/exclude_from_public_viewing

3)在exclude_from_public_viewing中写入一行文本(因为您正在尝试忽略所有分支中的build文件夹)。!build

4)现有的.git/info/exclude文件中已经存在。我们需要在其中添加以下内容。

 build

我们希望忽略 build 文件夹,但还没有在 .gitignore 文件中添加它。那么 git 如何知道要忽略什么?答案是将其添加到 exclude 文件中,并有条件地将该文件传递给 git config

5) 现在我们必须有条件地取消忽略 production 分支的 build 文件夹。为此,请执行以下操作

6) 存在一个名为 ./.git/config 的现有文件,我们需要添加以下内容 -

a) 在 [core] 下面添加 excludesfile = +info/exclude

[core]
     excludesfile = +info/exclude

b) 在 ./.git/config 文件末尾创建一个新的小节,如下所示:

[branch "production"]
    excludesfile = +info/exclude_from_public_viewing

解决方案 2

有一个聪明的替代方案。假设您想要将build/文件夹添加到production分支中,并在所有其他分支中忽略它。

1)将其添加到您的gitignore文件中。

2)在生产分支中,进行git add时,强制添加build文件夹:git add -f --all build/


2
这与已接受的解决方案有何不同?您使用哪个版本的git进行了测试?正如链接的答案所述,它失败是因为git中没有对branch.<name>.excludesfile的支持(再也没有了?),只有对core.excludesfile的支持,而我的测试似乎证实了这一点。 - Murphy
@murphy,它在git version 2.7.4 (Apple Git-66)上运行良好,而且我没有在我的解决方案中使用branch.<name>.excludesfile - sapy
4
根据 OP 的用例,我尝试了这个方法,但是在从生产环境切换到主分支时,文件仍然会消失。需要注意的是,“build”文件夹应该提交到“production”分支中。(另外,如果我不在“production”分支中提交“build”文件夹,“production”分支会忽略“build”文件夹的存在 - 也就是说,[branch "production"] excludesfile 配置不起作用)。我使用与你完全相同的 git 版本。我还尝试了[branch "production"] 方法来仅在生产环境中忽略文件,但像 Murphy 所说的那样,它也不起作用。 - justhalf
解决方案2正是我在寻找的。谢谢! - Vyacheslav Cotruta
@sapy 你怎么能说你没有使用过 branch.<name>.excludesfile?你在 [branch "production"] 下添加了一个 excludesfile - AJM
方案2不起作用: 当从“production”分支切换到其他分支时,“build/”文件夹仍然会消失。 - אלימלך שרייבר

14

我强烈建议考虑将这些 MP3 文件放在 S3 上。如果它们成为您 Heroku 推送的一部分(因此也是您 Heroku slug 的一部分),将大大减慢动态进程启动时间。由于 Heroku 使用 EC2,如果文件存储在 S3 上并且仅由您的应用程序访问(如果用户没有直接链接到 S3),则您甚至不会支付任何带宽费用,只需支付 50MB 存储费用。


5

你是否尝试过在你的分支中使用不同的.gitignore文件?

只要这些文件没有被跟踪,你就可以根据所在的分支忽略你想要忽略的内容。


6
我试过了。如果你看一下我上面发的命令,你会发现那正是我做的。问题在于,当我从已检入文件的分支切换到已忽略文件的分支时,Git 会丢弃这些文件。我想保留主分支中的 MP3 文件,以便在开发模式下网站能正常工作,即使这些文件被忽略了。 - Myron Marston
1
他已经说过他做了那件事。也许最好的方法是删除这个回答,它会分散注意力。 - blamb

4

1. 概要

  1. I use Travis CI for deploying (it supports Heroku deployment)
  2. I add to my .travis.yml:

    before_deploy:
    - mv misc/.gitignore .gitignore
    

    Where misc — any folder, contains another .gitignore.

    mv UNIX command move file; overwrite, if file already exist.

当Travis CI部署项目时,Travis CI不会推送到部署提供商的文件和文件夹,这些文件在misc/.gitignore中被忽略(不在源代码的.gitignore中)。

2. 限制

  1. 这个答案可能不适用于作者所有的情况。但是,这个答案回答了问题“使用git,如何在一个分支中忽略一个文件,但在另一个分支中提交它?”
  2. 我不是Heroku的用户,我的示例适用于GitHub,而不是Heroku。这个答案的数据在GitHub上对我有效,但可能在Heroku上无效。

3. 相关性

本答案适用于2018年4月。将来,本答案的数据可能会过时。


4. 演示

这是我的真实项目

成功部署的示例

4.1. 任务

我将我的项目从 src 分支部署到同一存储库的 dest 分支。

我希望文件 PaletteMira.suricate-profile

  • 本地机器 - 对于所有分支都存在,
  • src 远程分支 - 不存在,
  • dest 远程分支 - 存在。

如果我正确理解了问题的作者,他有类似的任务。

4.2. src

源分支 - SashaYAML

部分内容.travis.yml

before_deploy:
- mv misc/.gitignore .gitignore

deploy:
  provider: pages
  on:
    branch: SashaYAML
  keep-history: true
  skip-cleanup: true
  target-branch: SashaDevelop
  repo: Kristinita/PaletteMira
  github-token: $GITHUB_TOKEN
  committer-from-gh: true
  project-name: PaletteMira
verbose: true

.gitignore 的一部分:

*.sublime-snippet
*.suricate-profile

部分misc/.gitignore

*.sublime-snippet

*.suricate-profile 不在 misc/.gitignore 中。

PaletteMira.suricate-profile 在远程分支中不存在,但本地存在。

4.3. dest

目标分支 — SashaDevelop

.gitignore 的一部分:

*.sublime-snippet

*.suricate-profile 不在 misc/.gitignore 中。

PaletteMira.suricate-profile 在该分支 远程 和本地存在。

4.4. 重现步骤

我启用了 PaletteMira GitHub 仓库的 Travis CI → 我设置环境变量$GITHUB_TOKEN,并将其值设置为我的GitHub token → 我对我的 src 分支进行任何提交。

如果没有错误,我必须得到预期行为链接

0
你能从Heroku提交和推送吗?
例如,添加音频,将它们推送到github和heroku中,从Heroku的工作副本中删除文件。从repo中删除音频但不从磁盘中删除,然后将该更改推回github。

0

0

原始问题有点老,但我刚写了一篇medium文章,所以我想这可能会对某些人有所帮助。

我个人通过Git hookshusky解决了这个问题 - 似乎是最简单和最可靠的解决方案。

显然,我建议阅读文章,但这里是重现步骤

  • 步骤1:yarn add -D husky && yarn husky install
  • 步骤2:yarn husky add .husky/post-checkout
  • 步骤3:mkdir .husky/gitignores && cp .gitignore .husky/gitignores
  • 步骤4:touch .husky/gitignores/.gitignore_husky
  • 步骤5:this gist content复制并粘贴到.husky/post-checkout

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