I have a file in a git repository that has a local change on it. I want to have git ignore the local change forever, but not the file. In particular,
- If the file isn't touched besides this change,
git add .
should never stage it. - Likewise,
git commit -a
shouldn't commit it. - If I ever make an additional change to the file, I should be able to stage and commit that change - but the change I'm ignoring should not be staged and committed.
Is there a way to do this? Doing some research, I read about "smudge/clean cycles," where, if I read correctly,
- the file would be marked as unchanged,
- the change I made would be overwritten when I checkout,
- and then a script would automatically reapply the change and then mark the file as unchanged again.
I am very new to git and scripting, though (I'm an intern with C# and Java experience), so if that's what I need to do, can you please post detailed directions or a link to a tutorial on how to set a smudge/clean cycle up?
Background: I want my working branch to be out of sync with the trunk. There is a low priority bug that only affects development machines, so rather than fix it, we're just commenting out the offending code. Obviously, we don't want this code to be removed from production, where it works just fine.
If you happen to be using intellij as your IDE, then it has a neat feature (changelists) that I believe does exactly what OP is requesting.
You can mark and name a specific part of your local diff. If memory serves, this will keep those changes separate from all other local modifications and will only be staged for commit if you actively choose to do so - so long as you do your committing from intellij.
As I see it, the situation you are describing is this: you want to maintain a working directory that is different from the local repository.
This is not advisable; because these changes are not committed you will have little recourse if a file is accidentally deleted or changed in a way you do not want.
Therefore it is recommended that you in fact commit all your changes. If you would like to separate these changes you can easily do that using a branch. Example
You can use the
skip-worktree
bit. Turn it on with:After that, git will never stage local changes for
<file>
and will fail (loudly) if git itself has to write to<file>
(say, in a merge or a checkout).If you ever want to stage a future change, you can turn it off, stage the new change, and then turn it back on:
While not perfect, this might be good enough. It will be up to you to notice that
<file>
has unstaged changes, since git will no longer tell you thatNote: My original suggestion was to use
assume-unchanged
. As explained in Git - Difference Between 'assume-unchanged' and 'skip-worktree', it is reallyskip-worktree
that you want. In particular,assume-unchanged
is a promise to Git that you won't change the file, and if you violate that promise Git is allowed to erase your changes or commit them! In contrast, Git will not erase or commit yourskip-worktree
changes.As of Git 2.5 (July 2015), you can use git worktree:
This is essentially just creating a branch, but it puts the new branch into a new folder alongside the parent repo. This is nice because you can do work on this branch, even without committing, then switch back to master with a clean working directory.
These answers are good, but may not best solve @Kevin's problem. I had a similar concern, often editing a config file so the app I was working on would access my own private development database instead of the production one. It's only a matter of time before I accidentally check in and push those config changes! I just needed a light weight way to ignore a file. Here's what I learned:
First, make your needed change to your file. I'll call it
my_config
.Make a patch file of that change with
git diff >../somewhere-else/my_config.patch
Now tell git to ignore that file (without having to change the checked-in .gitignore):
git update-index --assume-unchanged my_config
Now, as long as you don't make changes to
my_config
that you do want to check in, you can work freely. To stop ignoringmy_config
, dogit update-index --no-assume-unchanged my_config
. After pulling in somebody else's changes tomy_config
, you can easily restore your private change withgit apply ../somewhere-else/my_config.patch
, then ...assume-unchanged again, as above, and get back to work!Here are some helpful aliases you can put in your
~/.gitconfig
:Git's "patch mode" is perfect for adding only certain changes from a file to your commit.
To start it, type
git add -p
,git commit -p
(straight to commit message when done), orgit add --interactive
(more prompts).It essentially takes you through each section of code shown in
git diff
and asks you whether you want to stage it or not.When you reach the change, either answer no, or e to open the patch in your $EDITOR.