how to omit the "-f" for "git add", if the previous version is already in git?

Viewed 60

I would like to track only a very restricted set of files, explicitly added to the repository using "git add -f". But how can I avoid having to use the "-f" again and again for files that are already in?

Sample:

% cat .gitignore 
/*

% git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   playlists/README

% git add playlists/README
The following paths are ignored by one of your .gitignore files:
playlists
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"

% git check-ignore -v playlists/README
% echo $?
1

% git commit -a -m "fixed some typo"
[master 039d616] fixed some typo
 1 file changed, 1 deletion(-)

% git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

% git version
git version 2.37.2

The playlists/README was explicitly mentioned on the command line, and yet I have to use "-f"? git commit wasn't so picky.

Of course I checked the man page. It says

   A gitignore file specifies intentionally untracked files that Git should
   ignore. Files already tracked by Git are not affected; see the NOTES
   below for details.

But the "NOTES below" didn't tell. playlists/README is already tracked, and yet it was affected. Please excuse if I am too blind to see.

Every insightful comment is highly appreciated

Additional information: Using

*
!*/

in .gitignore I get

% git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   .gitignore
        modified:   playlists/README

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        code/
        debian.old/
        origin/


It took 3.75 seconds to enumerate untracked files. 'status -uno'
may speed it up, but you have to be careful not to forget to add
new files yourself (see 'git help status').
no changes added to commit (use "git add" and/or "git commit -a")

git add was very weird:

% git add .
warning: adding embedded git repository: code
hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint: 
hint:   git submodule add <url> code
hint: 
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint: 
hint:   git rm --cached code
hint: 
hint: See "git help submodule" for more information.
warning: adding embedded git repository: debian.old/raw-xbmc/raw-xbmc-13alpha8
warning: adding embedded git repository: origin

% git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   .gitignore
        new file:   code
        new file:   debian.old/raw-xbmc/raw-xbmc-13alpha8
        new file:   origin
        modified:   playlists/README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
  (commit or discard the untracked or modified content in submodules)
        modified:   debian.old/raw-xbmc/raw-xbmc-13alpha8 (modified content, untracked content)

Apparently unwanted files haven't been added.

2 Answers

(Not an answer, I'm abusing the answer box to provide a formatted comment). Upd: reproduced. Shell script:

#! /bin/sh
set -e

git --version
git init test-add-gitignore-repo
cd test-add-gitignore-repo

echo
echo stage 1
mkdir testdir
echo test >testdir/test.txt
echo "/*" >.gitignore
git status

echo
echo stage 2
git add -f testdir/test.txt
git commit -m Test
git status

echo
echo stage 3
echo test2 >testdir/test.txt
git status

echo
echo stage 4
git add testdir/test.txt || :
git status

cd ..
rm -rf test-add-gitignore-repo

Output:

git version 2.30.2
Initialized empty Git repository in /home/phd/tmp/test-add-gitignore-repo/.git/

stage 1
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)

stage 2
[master (root-commit) 9ca248a] Test
 1 file changed, 1 insertion(+)
 create mode 100644 testdir/test.txt
On branch master
nothing to commit, working tree clean

stage 3
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   testdir/test.txt

no changes added to commit (use "git add" and/or "git commit -a")

stage 4
The following paths are ignored by one of your .gitignore files:
testdir
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   testdir/test.txt

I think you get this repeated warning because /* rule instructs git to ignore the complete playlist/ directory, and even the presence of a tracked file inside that directory isn't accounted as a known exception to this rule (git doesn't track directories, and I think a directory has no existence in the index).

The behavior on directories is hinted at by the documentation on .gitignore rules (emphasis mine) :

  • An optional prefix "!" which negates the pattern; any matching file excluded by a previous pattern will become included again. It is not possible to re-include a file if a parent directory of that file is excluded. Git doesn’t list excluded directories for performance reasons, so any patterns on contained files have no effect, no matter where they are defined. [...]

To have the "ignore everything except the files I explicitly added with -f (at any directory level)" behavior, try the following gitignore file :

# ignore all files, but keep going down in directories
*
!*/

Another way to avoid the warning with a specific target on the playlist/ directory could be :

/*
!/playlist
/playlist/*
Related