Using git, how do I ignore a file in one branch but have it committed in another branch?
I've got a project that I'm deploying to Heroku. The source code tree includes a bunch of mp3 files (the website will be for a recording project I was heavily involved with).
I'd like to put the source code for it up on GitHub, but GitHub has a 300 MB limit on their free accounts. I don't want to use 50 MB of my limit on a bunch of mp3 files. Obviously, I could add them to the .gitignore
file to keep them out of my repo.
However, I deploy to Heroku using git push heroku
. The mp3 files must be pr开发者_StackOverflow社区esent in the branch I push to Heroku so that they get get deployed.
Ideally, I'd like to .gitignore
the mp3 files in my local master branch so that when I push that to GitHub, the mp3s are not included. Then I'd keep a local production branch that has the mp3s committed rather than ignored. To deploy, I would merge master into production, and then push the production branch to Heroku.
I can't get this to work right.
Here's an example of what I'm trying to do...
$ git init git-ignore-test
$ cd git-ignore-test
$ echo "*.ignored" >> .gitignore
$ git add .gitignore && git commit -m "Ignore .ignored files"
$ touch Foo.ignored
At this point, Foo.ignored is ignored in my master branch, but it's still present, so my project can use it.
$ git checkout -b unignored
$ cat /dev/null > .gitignore
$ git add Foo.ignored .gitignore && git commit -m "Unignore .ignored files"
Now I've got a branch with these files committed, as I want. However, when I switch back to my master branch, Foo.ignored is gone.
Anyone got any suggestions for a better way to set this up?
Edit: just to clarify, I want the mp3 files to be present in both branches so that when I run the site locally (using either branch) the site works. I just want the files ignored in one branch so when I push to GitHub they are not pushed as well. Usually .gitignore works well for this kind of thing (i.e. keeping a local copy of a file that does not get included in a push to a remote), but when I switch to the branch with the files checked in, and then back to the branch with the files ignored, the files vanish.
This solution appears to work only for certain, patched versions of git. See a new answer pointing to workarounds and another answer and subsequent comments for a hint which versions may work.
I wrote a blog post on how to effectively use the excludesfile
for different branches, like one for public github and one for heroku deployment.
Here's the quick and dirty:
$ git branch public_viewing
$ cd .git/
$ touch info/exclude_from_public_viewing
$ echo "path/to/secret/file" > info/exclude_from_public_viewing
then in the .git/config file add these lines:
[core]
excludesfile = +info/exclude
[branch "public_viewing"]
excludesfile = +info/exclude_from_public_viewing
Now all the global ignore stuff is in the info/exclude
file and the branch specific is in the info/exclude_from_public_viewing
Hope that helps!
http://cogniton-mind.tumblr.com/post/1423976659/howto-gitignore-for-different-branches
Important hint: The accepted answer by Cognition.Mind doesn't work (anymore, for several years now, or perhaps for vanilla versions of git); see the comments. A valid answer and workaround can be found here:
https://stackoverflow.com/a/29583813/2157640
Another alternative workaround (working for my particular problem, but demanding manual stash operations or implementation of a hook) would be git stash -u -a
. This is tedious when the differences are large.
And finally, the solution I'm now going with is having forked my VM that we hold our development environment in, and set up info/excludes
appropriately for the branch, respectively deleting the offending, uncommitted files/folders.
Let's say we want to ignore build
folder from all other branch except production
branch . As we want to push build
folder in production.
1) Dont include build
in .gitignore . If you do that it will always be ignored for all branches .
2) Create a file exclude_from_public_viewing
inside ./.git/info
(This folder already exists) folder touch ./.git/info/exclude_from_public_viewing
3) Inside exclude_from_public_viewing
write one line (As you are trying to ignore build
for all the branches).
!build
4)There's an existing file .git/info/exclude
. We need to add following line in it.
build
We want to ignore build
folder but hasn't added it in .gitignore . So how git will know what to ignore ? Answer is we are adding it to exclude
file and conditionally passing that file to git config
5) Now we have to conditionally unignore build
folder for production
branch. to do that perform following
6) There is a existing file called ./.git/config
we need to add following -
a) excludesfile = +info/exclude
below [core]
[core]
excludesfile = +info/exclude
b) Create a new section in the end of ./.git/config
as
[branch "production"]
excludesfile = +info/exclude_from_public_viewing
Solution 2
There is one smart alternate solution . Lets say you want to add build/
folder in production
branch and ignore it in all other branches.
1) Add it to your gitignore
file.
2) In production branch, while doing git add
, force add build
folder: git add -f --all build/
I would strongly advise considering putting those MP3 files on S3. Having them be part of your Heroku push (and thus part of your Heroku slug) will greatly slow down your dyno startup time. Since Heroku uses EC2, if the files are on S3 and are only accessed by your app (if users aren't directly linked to S3) you won't even pay any bandwidth charges, only the charge to store 50MB.
Have you tried having .gitignore be different in your branch?
You should be able to ignore what you want based on the branch you are in as long as the files are not tracked on that branch.
1. Summary
- I use Travis CI for deploying (it supports Heroku deployment)
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.
When Travis CI deploy project, Travis CI will not push to deploying provider files and folders, that ignore in misc/.gitignore
(not in the original .gitignore
of sources).
2. Limitations
- This answer may not be suitable for all conditions of the author. But this answer answers the question “Using git, how do I ignore a file in one branch but have it committed in another branch?”
- I'm not Heroku user, my examples for GitHub, not for Heroku. Data of this answer works for me in GitHub, but may doesn't work on Heroku.
3. Relevance
This answer is relevant for April 2018. In the future, the data of this answer may be obsolete.
4. Demonstration
my real project.
Example of successful deployment.
4.1. Task
I deploy my project from src branch to dest branch of the same repository.
I want, that file PaletteMira.suricate-profile
:
- Local machine — exists for all branches,
- src remote branch — not exists,
- dest remote branch — exists.
If I correctly understood the author of the question, he have similar task.
4.2. src
sources branch — SashaYAML.
Part of .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
Part of .gitignore
:
*.sublime-snippet
*.suricate-profile
Part of misc/.gitignore
*.sublime-snippet
*.suricate-profile
not in misc/.gitignore
.
PaletteMira.suricate-profile
not exists in this branch remotely, but exists locally.
4.3. dest
destination branch — SashaDevelop
Part of .gitignore
:
*.sublime-snippet
*.suricate-profile
not in misc/.gitignore
.
PaletteMira.suricate-profile
exists for this branch remotely and locally.
4.4. Steps to reproduce
I enable PaletteMira GitHub repository for Travis CI → I set environment variable $GITHUB_TOKEN
with value — my GitHub token → I make any commit to my src branch.
If no errors, I must get expected behavior.
Can you commit and push from Heroku?
e.g. Add the audio, push them to github and into heroku, remove the files on the working copy on Heroku. Remove the audio from the repo but not from the disk, then push that change back to github.
Github now has support for Large file storage, see more here https://git-lfs.github.com/
The original question is a little oder but I came across it since I've just written a medium article about it, I thought this might help someone.
I personally have solved this with Git hooks via husky - seems to be the easiest and most reliable solution.
Obviously, I suggest to read the article but here are the steps to reproduce
- step 1:
yarn add -D husky && yarn husky install
- step 2:
yarn husky add .husky/post-checkout
- step 3:
mkdir .husky/gitignores && cp .gitignore .husky/gitignores
- step 4:
touch .husky/gitignores/.gitignore_husky
- step 5: copy and paste this gist content into
.husky/post-checkout
精彩评论