1

I have a folder let's say,

src/main/resources/basic_abc

For running my code locally, I need to rename it to

src/main/resources/basic

This is a change I want to perform each time I work on this repository. I don't want git to keep on tracking this folder and telling me that basic_abc was renamed to basic. How can I stop git from tracking this rename change?

Furthermore, if I run the command git status, it really gives a messy output since there is a large number of files in this folder.

How could I avoid it?

joangm_
  • 27
  • 1
  • 12
Dawson Smith
  • 473
  • 1
  • 6
  • 15
  • 1
    The short answer is "you can't". In particular, Git doesn't track *folders* at all, only *files*, and it then does rename *detection* on the *files*. You can completely disable rename detection in `git status` output in Git since 2.18, though. This may suffice, in some limited cases, to get you close enough to what you want, perhaps also using `--skip-worktree` as mentioned in [joanis' answer](https://stackoverflow.com/a/70957498/1256452). This is not an intended use case though, so it's probably not a good long-term approach. – torek Feb 03 '22 at 08:01

3 Answers3

2

Telling Git to ignore that basic_abc/ is gone

Caveat This solution only works as long as you don't change branches in your sandbox. Jump near the end of this answer for details. end caveat

You can use git update-index --skip-worktree <file> to tell Git to ignore changes you've made locally to a file, so that git status and all other commands will just treat it as unchanged.

I tested, and this also works for a file that was removed. What I did not find is a way to do it for a whole directory, but it's not hard to script on the bash command line.

One file:

git update-index --skip-worktree basic_abc/file1

All the files in basic_abc/:

git status --porcelain |
   grep " D src/main/resources/basic_abc" |
   sed "s/^ D //" |
   xargs git update-index --skip-worktree

Explanations:

  • git status is run with --porcelain so that you have stable machine-readable output.
  • If needed, fix the grep expression so it finds exactly the files you want Git to pretend were not deleted/moved.
  • The sed command keeps just the filename.
  • And xargs calls git update-index --skip-worktree on the results of that pipeline.

Telling Git to ignore that basic/ has appeared

As @EddieDeng said, you can use .git/info/exclude or .gitignore to accomplish this, see his answer.

Reverting the --skip-worktree operation

You didn't ask, but the next logical question, when you've made changes to files in basic_abc/ basic, will be how to commit them. I'm mentioning it here because once you've run that --skip-worktree loop, renaming basic back to basic_abc and running git status or git add won't work!

Fortunately, that question is already half answered here on SO: How to list files ignored with 'skip-worktree' shows how to list the skipped files, and this command can revert them to not being skipped:

git ls-files -v . |
   grep "S src/main/resources/basic_abc" |
   sed "s/^S //" |
   xargs git update-index --no-skip-worktree

I'm not sure whether the git ls-files -v . output is as stable as the git status --porcelain output is, especially since the -t/-v/-f options are marked semi-deprecated in the manual, but this works at the moment, and I don't know how else to extract that list from Git.

The caveats, or why you should probably not do this

Thanks to @bk2204 for linking to Git FAQ: How do I ignore changes to a tracked file?, where it basically says "don't".

There are problems with update-index, because it only updates the index, and not some other persistent flag. See @torek's excellent write up on these problems.

The key point I want to highlight here is that as soon as you checkout another branch in your sandbox, you will lose the skip-worktree bits set previously.

Just tested:

# do the --skip-worktree operation above
git checkout some-feature-branch
git checkout master

and now my sandbox has both basic/* and basic_abc/*, i.e., two full copies of all those files.

So my final point is, only use this solution if you're not planning to change branches in that sandbox. (And since I change branches all the time, for me, that's the same as "don't use this solution".)

A better solution?

I think the best approach would be to rethink your setup altogether. Instead of modifying your sandbox, you should write some install/deploy script that creates the run-time structure you need outside of your sandbox. Then you have a clear separation and full flexibility: source code is under Git management, deployed code has whatever structure it needs, outside Git management. And you could use symlinks to make that deployed structure lightweight and dynamically updateable, if you wanted to avoid the actual copying.

joanis
  • 10,635
  • 14
  • 30
  • 40
  • The [Git FAQ](https://git-scm.com/docs/gitfaq#ignore-tracked-files) is very clear that `git update-index` doesn't work for ignoring tracked files and shouldn't be used for that purpose. – bk2204 Feb 02 '22 at 22:47
  • @bk2204 Well, OK, that's a pretty clear warning, but in my defense, `--skip-worktree` is fairly often given here as the answer to similar questions. But you prompted me to do more research, thank you for that, and I see there are problems with this solution if you're going to switch to other branches. I'll add caveats to my answer. – joanis Feb 03 '22 at 13:47
  • But I'd also like to know, how would you solve OP's problem? – joanis Feb 03 '22 at 13:48
1

I think this can be done by ignoring a directory "locally".

  • create a new "basic" directory
  • copy all contents in "basic_abc" into it
  • goto \.git\info in your project directory, open the exclude file.
  • add a new line saying src/main/resources/basic.
  • execute git status again, you will see git does not consider the new "basic" directory as an untracked file. But you need to synchronize its content with the "basic_abc" directory manually. As long as in the remote repository there is no directory or file named "basic" you are good to go.

The exclude file is for a "local git ignore". It has the same format as the .gitignore file but only works on your machine.

Eddie Deng
  • 1,399
  • 1
  • 18
  • 30
1

You could use git rm <folder> --cached - when needed you can simply add the folder again with git add <folder>. Note though that if you do a git commit -a before re-adding the folder, the removal will appear in that commit.

Important notice:

THE --cached argument IS IMPORTANT - WITHOUT THAT, git will DELETE the folder FROM YOUR HARD DISK.

TheEagle
  • 5,808
  • 3
  • 11
  • 39