Domanda

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.

È stato utile?

Soluzione

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

Altri suggerimenti

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.

This is even easier if you use gitx (R).

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)

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

There are multiple ways [although may not be clean and neat and would require your attention]

  1. 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
  2. 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 like git commit -a or git add . run on all except the file under question. Another alternative would be to use git gui or git citool where you can visually ensure your file isn't in 'staged' area and hence never gets committed
  3. 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 can git stash pop and continue working and committing.

Hope that helps :)

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top