Git - Temporarily ignore trivial changes to files
GitIgnoreGit Problem Overview
I'm looking for a way to 'hide' minor changes made to a few files in Git, such that they will not show up in git status until a different change is made to those files.
Example: I have a java file where the only change made is the removal of an unused import (a contributor forgot to run an organize imports before committing). Now I have removed that import and the change (obviously) shows up in git. Since I have no other change to make to that file, I don't really like committing the file as part of another (unrelated) change or committing this change stand-alone. Sure, I could revert the change and only applying it whenever I will have to make changes to that file, but I could "risk" forgetting it.
Does a command exists for such a task? It would work somewhat like the assume-unchanged command but in a not permanent way.
What would be the proper way to resolve this if no such command is available?
Thanks in advance.
Git Solutions
Solution 1 - Git
In my use case (developing using an edited config file on my personal machine, running on another machine with the unchanged config), this was the solution for me:
start ignoring changes to a file:
git update-index --assume-unchanged path/to/file
keep tracking again:
git update-index --no-assume-unchanged path/to/file
Solution 2 - Git
The drawback of using git update-index --assume-unchanged
is that (as the git manual states), you're promising git that you're not going to change the file.
> When the "assume unchanged" bit is on, the user promises not to change the file and allows Git to assume that the working tree file matches what is recorded in the index.
If you violate this promise and change the file anyway it can have undesirable consequences. E.g. on some implementations, doing a git stash
will throw away the changes you made to the file (why shouldn't it if you promised you weren't going to change it?).
Using the --skip-worktree option instead tells git to pretend the working version is up to date with the index version.
> When reading an entry, if it is marked as skip-worktree, then Git pretends its working directory version is up to date and read the index version instead.
This seems to be the more reliable way to ignore changes without the risk that some git commands might throw your changes away:
git update-index --skip-worktree path/to/file
To track the file again:
git update-index --no-skip-worktree path/to/file
To list the files where you've set the skip-worktree
:
git ls-files -v | grep ^S
Solution 3 - Git
Keep your changes that are not ready in a separate branch. git rebase
this branch atop new changes in the main history as necessary.
Be it development in progress, temporary things, even things that are never to be included in the main project history -- the same process works equally well.
If/when the changes of the branch are ready to be included in the main history; merge it in. If not, keep them in the separate branch and continue rebasing.
(side note: git merge --no-ff
may be of use to create a merge-commit even if a fast-forward merge is possible -- depending on the rules of your project, this may be preferable)
Solution 4 - Git
Just don't add the trivial changes.
It's good practice to carefully review the things that you add before committing.
You can even ignore some changes in a file while adding others, using
git add -p.
Solution 5 - Git
I added all the answers here to add some code that made my life a little bit more comfortable. Expects BSD coreutils (like on MacOS).
git-overlook
#!/usr/bin/env bash
path="$1"
root="$(git rev-parse --show-toplevel)"
if [ -z "$path" ]; then
echo "Specify a path" 1>&2
exit 1;
fi;
if [ ! -d .git/overlook ]; then
mkdir $root/.git/overlook
fi;
record="$root/.git/overlook/$(echo $path | sed 's/\./___/g' | sed 's/\//____/g')"
touch "$record"
git update-index --skip-worktree "$path"
git-relook
#!/usr/bin/env bash
path="$1"
root="$(git rev-parse --show-toplevel)"
record="$root/.git/overlook/$(echo $path | sed 's/\./___/g' | sed 's/\//____/g')"
if [ -f "$record" ]; then
git update-index --no-skip-worktree "$path"
rm "$record"
fi;
And finally a .git/hooks/pre-commit
#!/bin/bash
set -eu
root="$(git rev-parse --show-toplevel)"
get_record_name() {
record="$root/.git/overlook/$(echo $1 | sed 's/\./___/g' | sed 's/\//____/g')"
echo "$record"
}
for file in $(git ls-files -v | grep ^S | sed 's/S //'); do
record="$(get_record_name $file)"
record_mtime="$(stat -f %m $record)"
file_mtime="$(stat -f %m $file)"
if [ "$record_mtime" -lt "$file_mtime" ]; then
echo "File $file is overlooked but has been modified since. Please run either git overlook $file or git relook $file" 1>&2
exit 1
else
echo "File $file is overlooked but hasn't been modified"
fi;
done;
This makes it so that I can run git overlook path/to/file
and then I can go about committing on my merry way until I've changed the file that was overlooked, at which point I have to either overlook it again or bring it back in with git relook path/to/file
. Obviously it doesn't help me if the overlooked file is the only change I made and then I don't see it in git status
.
It makes some files in .git/overlook
to keep track of stuff but as far as I know git
will peacefully coexist with them.
Solution 6 - Git
There are multiple ways [although may not be clean and neat and would require your attention]
- Add the file in concern to
.gitignore
in your repo so that it doesn't show up for commit. Be careful to remove this from.gitignore
when you are ready to commit the file - Ensure you do not 'stage' the file while committing rest of your changes. You may want to write a wrapper over
git
which will ensure commands likegit commit -a
orgit add .
run on all except the file under question. Another alternative would be to usegit gui
orgit citool
where you can visually ensure your file isn't in 'staged' area and hence never gets committed - Another way would be to commit all your 'committable' changes and then
git stash save
your only working file. Later when you are ready to change the file, you cangit stash pop
and continue working and committing.
Hope that helps :)