Jak sprawić, by Git „zapomniał” o pliku, który był śledzony, ale jest teraz w .gitignore?

5390

Istnieje plik, który był śledzony git, ale teraz plik znajduje się na .gitignoreliście.

Plik ten pojawia się jednak git statuspo edycji. Jak zmusić się gitdo całkowitego zapomnienia o tym?

Ivan
źródło
16
git clean -Xbrzmi podobnie, ale nie ma zastosowania w tej sytuacji (gdy pliki są nadal śledzone przez Git). Piszę to dla każdego, kto szuka rozwiązania, które nie podąży niewłaściwą drogą.
imz - Ivan Zakharyaschev
35
Jedyną prawdziwą odpowiedzią na to pytanie jest poniżej git update-index --assume-unchanged. To rozwiązanie 1) utrzymuje plik na serwerze (indeks), 2) pozwala swobodnie go modyfikować lokalnie.
Qwerty
8
Musisz użyć --skip-worktree, patrz: stackoverflow.com/questions/13630849/...
Doppelganger,
77
Ważnym pytaniem jest: czy plik powinien pozostać w repozytorium, czy nie? Na przykład, jeśli ktoś nowy klonuje repozytorium, powinien otrzymać plik, czy nie? Jeśli TAK następnie git update-index --assume-unchanged <file>jest poprawny, a plik pozostanie w repozytorium, a zmiany nie zostaną dodane git add. Jeśli NIE (na przykład był to jakiś plik pamięci podręcznej, wygenerowany plik itp.), git rm --cached <file>Usunie go z repozytorium.
Martin
9
@Martin @Qwerty Everyon powinien przestać doradzać, w --assume-unchangedkwestii wydajności, aby git nie sprawdzał statusu dużych śledzonych plików, ale preferuje --skip-worktreeto, co dotyczy zmodyfikowanych plików śledzonych, których użytkownik nie chce już zatwierdzać. Zobacz stackoverflow.com/questions/13630849/...
Philippe

Odpowiedzi:

5690

.gitignorezapobiegnie dodawaniu nieśledzonych plików (bez add -f) do zestawu plików śledzonych przez git, jednak git będzie nadal śledził wszystkie pliki, które są już śledzone.

Aby zatrzymać śledzenie pliku, musisz go usunąć z indeksu. Można to osiągnąć za pomocą tego polecenia.

git rm --cached <file>

Jeśli chcesz usunąć cały folder, musisz usunąć z niego wszystkie pliki rekurencyjnie.

git rm -r --cached <folder>

Usunięcie pliku z rewizji głównej nastąpi przy następnym zatwierdzeniu.

OSTRZEŻENIE: Chociaż nie usunie to fizycznego pliku z twojego lokalnego, usunie pliki z innych komputerów programistów na następnym git pull.

CB Bailey
źródło
55
proces, który działał dla mnie był 1. zatwierdzić najpierw oczekujące zmiany 2. git rm - buforowany <plik> i zatwierdzić ponownie 3. dodać plik do .gitignore, sprawdzić status git i zatwierdzić ponownie
mataal
117
Bardzo ważne dodanie. Jeśli plik, który jest ignorowany, zostanie zmodyfikowany (ale mimo to nie powinien zostać zatwierdzony), po modyfikacji i wykonaniu git add .zostanie dodany do indeksu. A następne zatwierdzenie zatwierdziłoby to do repozytorium. Aby tego uniknąć, zaraz po tym wszystkim mataal powiedział jeszcze jedno polecenie:git update-index --assume-unchanged <path&filename>
Dao
32
Metoda @AkiraYamamoto również działała dobrze dla mnie. W moim przypadku git rm -r -q --cached .
pominąłem
85
Spowoduje to jednak usunięcie pliku git pull.
Petr Peller
22
git rm --cached <plik> po prostu usuń plik z repozytorium, git update-index --assume-unchanged <plik> nie pokazano pliku w nieustawionych zmianach i nie powoduje pobrania nowych zmian. Ale chcę, żeby GIT JUŻ Zignorował zawartość pliku PLEEEEEASE
Igor Semin
2608

Poniższa seria poleceń usunie wszystkie elementy z Git Index (nie z katalogu roboczego lub lokalnego repozytorium), a następnie zaktualizuje Git Index, przestrzegając ignorowania git. PS. Indeks = pamięć podręczna

Pierwszy:

git rm -r --cached . 
git add .

Następnie:

git commit -am "Remove ignored files"

Lub jednowarstwowy:

git rm -r --cached . && git add . && git commit -am "Remove ignored files"
Matt Frear
źródło
197
Aby podkreślić różnicę między tą odpowiedzią a odpowiedzią: Za pomocą tych poleceń nie trzeba tak naprawdę znać plików, których dotyczy problem. (Wyobraź sobie tymczasowy katalog z dużą ilością losowych plików, które powinny zostać usunięte z indeksu).
Ludwig
53
Taki sam jak zaakceptowana odpowiedź. Pliki zostaną usunięte w dniu git pull.
Petr Peller
73
Byłoby miło mieć to jako standardowe polecenie git. Coś jak git rmignored.
Berik,
12
@gudthing -r oznacza „rekurencyjny”
Mark
14
Dzięki temu możesz w końcu dodać inne bezużyteczne pliki, których obecnie nie ma .gitignore. Które może być trudne do ustalenia, jeśli zależy od tego, jaki hałas git statuswystępuje po tym poleceniu. Polecenie, które usuwa tylko nowo zignorowane pliki, byłoby lepsze. Dlatego wolę odpowiedź
thSoft
1122

git update-index wykonuje dla mnie zadanie:

git update-index --assume-unchanged <file>

Uwaga: To rozwiązanie jest w rzeczywistości niezależne, .gitignoreponieważ gitignore jest przeznaczony tylko dla nieśledzonych plików.

edycja: Od czasu opublikowania tej odpowiedzi utworzono nową opcję, którą należy preferować. Powinieneś użyć tego, --skip-worktreeco jest dla zmodyfikowanych plików śledzonych, których użytkownik nie chce już zatwierdzać i zachować --assume-unchangedwydajność, aby git nie sprawdzał statusu dużych plików śledzonych. Zobacz szczegóły na https://stackoverflow.com/a/13631525/717372 ...

git update-index --skip-worktree <file>
Konstantin
źródło
173
To jest prawdziwa odpowiedź. Niesamowite, bardzo proste, nie zanieczyszcza środowiska git statusi jest bardzo intuicyjne. Dzięki.
Pablo Olmos de Aguilera C.
4
Poszedłem do wystarczająco dobrego rm [...] .rozwiązania, ponieważ przynajmniej mogłem sobie wyobrazić, jak to działa. Nie znalazłem świetnej dokumentacji na temat tego, co update-indexi --assume-unchangedrobię. Czy ktoś może dodać, jak to się ma do innych, ponieważ chciałbym usunąć wszystkie pliki, które zostałyby zignorowane? (Lub link do jasnego wyjaśnienia?)
Brady Trainor
25
git update-index --assume-unchanged <path> …spowoduje, że git zignoruje zmiany w określonych ścieżkach, niezależnie od .gitignore. Jeśli pobierzesz z pilota, a ten pilot ma zmiany w tej ścieżce, git nie powiedzie scalenia z konfliktem i będziesz musiał scalić ręcznie. git rm --cached <path> …spowoduje, że git przestanie śledzić tę ścieżkę. Jeśli nie dodasz ścieżki .gitignore, zobaczysz ją w przyszłości git status. Pierwsza opcja ma mniej hałasu w historii zatwierdzeń git i pozwala na rozpowszechnianie zmian w pliku „ignorowanym” w przyszłości.
ManicDee,
26
Jestem dość zdezorientowany, że nie jest to akceptowana odpowiedź. Przyjęta tutaj odpowiedź wyraźnie nie odpowiada na zadane pytanie. Ta odpowiedź ignoruje zmiany w pliku znajdującym się w repozytorium, ale nie usuwa go z repozytorium.
Dave Cooper
11
Ta odpowiedź byłaby o wiele bardziej przydatna, gdyby dokładnie wyjaśniła, co robi dane polecenie, np. Czym różni się od innych sugerowanych rozwiązań.
LarsH,
283
git ls-files --ignored --exclude-standard -z | xargs -0 git rm --cached
git commit -am "Remove ignored files"

Spowoduje to pobranie listy zignorowanych plików i usunięcie ich z indeksu, a następnie zatwierdzenie zmian.

thSoft
źródło
7
Jeśli chcesz je również usunąć z katalogu roboczego, po prostu uruchom git ls-files --ignored --exclude-standard | xargs git rm . Wierzę, że ta odpowiedź jest najlepsza! Ponieważ jest to bardzo jasne, w stylu uniksowym i robi pożądaną rzecz w bezpośredni sposób, bez komponowania skutków ubocznych innych, bardziej złożonych poleceń.
imz - Ivan Zakharyaschev
6
Świetna odpowiedź; jednak polecenie nie powiedzie się, jeśli masz ścieżki ze spacjami na środku, np .: „Mój katalog / mój_plik_plików.txt”
David Hernandez
8
git ls-files --ignored --exclude-standard | sed 's /.*/"&"/' | xargs git rm --cached
David Hernandez
3
git rmnarzeka, jeśli ls-filesnic nie pasuje. Służy xargs -r git rm ...do informowania, aby xargsnie uruchamiać, git rmjeśli nie pasują żadne pliki.
Wolfgang
10
Lepiej byłoby użyć \ 0 jako separatora:git ls-files --ignored --exclude-standard -z|xargs -0 git rm --cached
Nils-o-mat
83

Zawsze używam tego polecenia, aby usunąć te nieśledzone pliki. Jednoliniowy, uniksowy styl, czyste wyjście:

git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

Zawiera listę wszystkich zignorowanych plików, zamiast tego zastępuje każdą linię wyjściową linią cytowaną, aby obsługiwać ścieżki ze spacjami w środku, i przekazuje wszystko, git rm -r --cachedaby usunąć ścieżki / pliki / katalogi z indeksu.

David Hernandez
źródło
3
Świetne rozwiązanie! Działa idealnie i wydaje się bardziej poprawne niż usuwanie wszystkich plików, a następnie dodawanie ich z powrotem.
Jon Catmull
5
Ja też uważam to za „najczystsze”. Może to być oczywiste, ale samo uruchomienie pierwszej części git ls-files --ignored --exclude-standardpozwala najpierw zrozumieć / zweryfikować, jakie pliki .gitignorezostaną wykluczone / usunięte przez nowy , zanim przejdziesz dalej i wykonasz finał git rm.
JonBrave,
Należy pamiętać, że w nazwach plików występują błędy, które zawierają pewne „nieprzyjemne” znaki, np \n. Zamieściłem moje rozwiązanie, aby to zrobić.
JonBrave,
3
Kolejne zastrzeżenie: po pociągnięciu spowoduje to usunięcie pliku w katalogach roboczych innych osób, prawda?
LarsH,
próbowałem, ale nie działało dla mnie: sed: 1: "s/.*/": unterminated substitute in regular expressionw poleceniu filter-branch na repozytorium ze spacjami. (Wydaje się, że działa poza gałęzią filtrów). Kiedyś git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cachedz @ JonBrave za odpowiedź zamiast.
goofology,
70

przenieś to, zatwierdz, a następnie przenieś z powrotem. To działało dla mnie w przeszłości. Prawdopodobnie istnieje bardziej „bardziej gitarzysta” sposób na osiągnięcie tego.

Joel Hooks
źródło
2
Działa to świetnie, jeśli chcesz zignorować kilka plików, które nie były wcześniej ignorowane. Chociaż, jak powiedziałeś, prawdopodobnie jest na to lepszy sposób.
Oskar Persson
Właśnie to zrobiłem. Po prostu przenieś pliki do folderu poza git, a następnie wykonaj „git add.”, „Git commit”. (To usunęło pliki), a następnie dodaj gitignore, odwołując się do plików / folderów, zatwierdź ponownie, aby dodać plik gitignore do git, a następnie skopiuj / przenieś z powrotem do folderów i należy je zignorować. Uwaga: wygląda na to, że pliki zostały usunięte z GIT, więc prawdopodobnie usunę je z innych kas / wyciągów, jak wspomniano w powyższych rozwiązaniach, ale ponieważ robisz ich kopie na początku, nie jest to tak duży problem IMHO. daj znać reszcie zespołu ...
Del
Jest to najprostszy sposób na pozbycie się nieprawidłowo popełnionych folderów.
Martlark,
1
Wydaje się, że to jedyny sposób, który widzę. Jest to ogromny błąd (nie „funkcja”) w git, który po dodaniu pliku / folderu do .gitignore nie tylko ignoruje ten plik od tego momentu - na zawsze - wszędzie.
JosephK
Działa
66

Jeśli nie możesz git rmśledzić pliku, ponieważ inne osoby mogą go potrzebować (ostrzeżenie, nawet jeśli Ty git rm --cached , gdy ktoś inny dostanie tę zmianę, jego pliki zostaną usunięte w systemie plików). Często są one wykonywane z powodu nadpisywania plików konfiguracyjnych, poświadczeń uwierzytelnienia itp. Informacje na temat sposobów obejścia problemu można znaleźć na stronie https://gist.github.com/1423106 .

Podsumowując:

  • Niech Twoja aplikacja wyszuka zignorowany plik config-overide.ini i użyje go w zatwierdzonym pliku config.ini (lub alternatywnie poszukaj ~ / .config / myapp.ini lub $ MYCONFIGFILE)
  • Zatwierdź plik config-sample.ini i zignoruj ​​plik config.ini, w razie potrzeby przygotuj skrypt lub podobną kopię pliku.
  • Spróbuj użyć gitattributes clean / smudge magic, aby zastosować i usunąć zmiany, na przykład rozmazuj plik konfiguracyjny jako kasa z alternatywnej gałęzi i wyczyść plik konfiguracyjny jako kasa z HEAD. To trudne zadanie, nie polecam go początkującym użytkownikom.
  • Zachowaj plik konfiguracyjny w dedykowanym oddziale wdrażania, który nigdy nie jest scalany z głównym. Kiedy chcesz wdrożyć / skompilować / przetestować, łączysz się z tym oddziałem i dostajesz ten plik. Jest to zasadniczo podejście do rozmazywania / czyszczenia, z wyjątkiem korzystania z zasad scalania przez ludzi i modułów dodatkowych.
  • Anti-recommentation: Nie używaj zakładania niezmienionego, skończy się to tylko łzami (ponieważ kłamstwo samo w sobie spowoduje złe rzeczy, takie jak zmiana utracona na zawsze).
Seth Robertson
źródło
7
git nie usunąłby pliku, gdyby był brudny w momencie usuwania. A jeśli nie jest brudny, odzyskanie pliku byłoby tak proste, jak git checkout <oldref> -- <filename>- ale wtedy zostanie sprawdzone i zignorowane.
amenthes
Jeśli chodzi o twoją ostatnią uwagę (około --assume-unchanged): albo jest to kult ładunku i powinien zostać odrzucony, albo możesz wyjaśnić, dlaczego (o czym jestem przekonany) i stanie się przydatny.
RomainValeri
57

Użyj tego, gdy:

1. Chcesz wyśledzić wiele plików lub

2. Zaktualizowałeś plik gitignore

Link do źródła: http://www.codeblocq.com/2016/01/Untrack-files-already-added-to-git-repository-based-on-gitignore/

Załóżmy, że już dodałeś / zatwierdziłeś niektóre pliki do swojego repozytorium git, a następnie dodajesz je do swojego .gitignore; pliki te będą nadal obecne w indeksie repozytorium. W tym artykule zobaczymy, jak się ich pozbyć.

Krok 1: Zatwierdź wszystkie zmiany

Przed kontynuowaniem upewnij się, że wszystkie zmiany zostały zatwierdzone, w tym plik .gitignore.

Krok 2: Usuń wszystko z repozytorium

Aby wyczyścić repozytorium, użyj:

git rm -r --cached .
  • rm to polecenie usuwania
  • -r pozwoli na rekurencyjne usunięcie
  • –Buforowane usunie tylko pliki z indeksu. Twoje pliki nadal tam będą.

rmKomenda może być pamiętliwy. Jeśli chcesz spróbować tego, co robi wcześniej, dodaj flagę -nlub, --dry-runaby to sprawdzić.

Krok 3: Dodaj wszystko ponownie

git add .

Krok 4: Zatwierdź

git commit -m ".gitignore fix"

Twoje repozytorium jest czyste :)

Wciśnij zmiany na pilocie, aby zobaczyć, że zmiany również tam obowiązują.

Dheeraj Bhaskar
źródło
1
Nie usunie plików ze zdalnego repozytorium? Co jeśli chcę zachować pliki zarówno w repozytorium lokalnym, jak i repozytorium zdalnym, ale sprawić, aby git „zapomniał” o nich?
Avishay28
AFAIK to nie usunie plików z historii, ponieważ nie używamy żadnych poleceń zmieniających historię (popraw mnie, jeśli się mylę). To tylko dodaje nowe zatwierdzenie, usuwając pliki ignorowane w gitignore z git. Te pliki będą tam w historyczne zobowiązania
Dheeraj Bhaskar
49

Osiągnąłem to za pomocą git filter-branch . Dokładne polecenie, którego użyłem, pochodzi ze strony podręcznika:

OSTRZEŻENIE : spowoduje to usunięcie pliku z całej historii

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD

To polecenie odtworzy całą historię zatwierdzeń, wykonując git rmprzed każdym zatwierdzeniem, a zatem usunie określony plik. Nie zapomnij wykonać kopii zapasowej przed uruchomieniem polecenia, ponieważ zostanie utracone.

drrlvn
źródło
9
Spowoduje to zmianę wszystkich identyfikatorów zatwierdzeń, a tym samym zerwanie scalania z oddziałów poza kopią repozytorium.
bdonlan,
19
OSTRZEŻENIE: spowoduje to usunięcie pliku z całej historii. Właśnie tego szukałem, aby usunąć całkowicie niepotrzebny i zbyt duży plik (dane wyjściowe, które nigdy nie powinny były zostać zatwierdzone), który został popełniony dawno temu w historii wersji.
zebediah49 13.03.13
48

Co mi nie zadziałało

(Pod Linuksem) chciałem użyć tutaj postów sugerujących takie ls-files --ignored --exclude-standard | xargs git rm -r --cachedpodejście. Jednak (niektóre) pliki, które mają zostać usunięte, miały osadzoną nową linię / LF / \nw swoich nazwach. Żadne z rozwiązań:

git ls-files --ignored --exclude-standard | xargs -d"\n" git rm --cached
git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

poradzić sobie z tą sytuacją (otrzymuj błędy dotyczące plików nie znaleziono)

Więc oferuję

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached
git commit -am "Remove ignored files"

Używa -zargumentu do plików ls , a -0argumentu do xargs, aby bezpiecznie / poprawnie zaspokoić „nieprzyjemne” znaki w nazwach plików.

Na stronie podręcznika git-ls-files (1) stwierdza:

Gdy opcja -z nie jest używana, znaki TAB, LF i odwrotnego ukośnika w ścieżkach są reprezentowane odpowiednio jako \ t, \ n i \\.

więc myślę, że moje rozwiązanie jest potrzebne, jeśli w nazwach plików znajduje się którykolwiek z tych znaków.

JonBrave
źródło
1
Dla mnie to najlepsze rozwiązanie. Ma znacznie lepszą wydajność niż git add .. Zawiera także najlepsze ulepszenia z niektórych powyższych komentarzy.
Nils-o-mat
Czy możesz dodać git commit -am "Remove ignored files"później thSoft do swojej odpowiedzi? Twoje odpowiedzi razem pomogły mi przejść przez: j
kando
Nie rozumiem celu git commit -a. Dla mnie git rm --cachedwpływa dokładnie na indeks, więc nie ma potrzeby ustawiania plików po ...
Jean Paul,
23
  1. Zaktualizuj .gitignoreplik - na przykład dodaj folder, którego nie chcesz śledzić .gitignore.

  2. git rm -r --cached .- Usuń wszystkie śledzone pliki, w tym poszukiwane i niepożądane. Twój kod będzie bezpieczny, dopóki zapisałeś go lokalnie.

  3. git add .- Wszystkie pliki zostaną dodane z powrotem, z wyjątkiem tych w .gitignore.


Czapka dla @AkiraYamamoto za wskazanie nam właściwego kierunku.

Chen_Wayne
źródło
1
Co powiesz na zaniżone ze względu na fakt, że tak naprawdę nie zadziała, ponieważ potrzebujesz -r, aby zrestartować rekurencyjnie :) (Ktoś nie skopiował poprawnie)
Aran Mulholland
1
Ostrzeżenie: Ta technika nie powoduje, że git zignoruje plik, zamiast tego powoduje, że git usuwa plik. Oznacza to, że jeśli użyjesz tego rozwiązania, za każdym razem, gdy ktokolwiek spróbuje pobrać git, plik zostanie usunięty. Więc to nie jest faktycznie ignorowane. Zobacz rozwiązanie sugerujące git update-index --assume-niezmienione zamiast rozwiązania pierwotnego pytania.
2017
16

Myślę, że może git nie może całkowicie zapomnieć o pliku z powodu jego koncepcji ( sekcja „Migawki, nie różnice” ).

Ten problem nie występuje na przykład podczas korzystania z CVS. CVS przechowuje informacje jako listę zmian opartych na plikach. Informacje dla CVS to zestaw plików i zmiany wprowadzane w każdym pliku w czasie.

Ale w Git za każdym razem, gdy zatwierdzasz lub zapisujesz stan swojego projektu, zasadniczo robi zdjęcie, jak wyglądają wszystkie twoje pliki w tym momencie i przechowuje odniesienie do tej migawki. Tak więc, jeśli dodałeś plik raz, zawsze będzie on obecny w tej migawce.

Te 2 artykuły były dla mnie pomocne:

git zakłada-niezmieniony vs. pomiń-roboczy i jak ignorować zmiany w śledzonych plikach za pomocą Git

Na tej podstawie wykonuję następujące czynności, jeśli plik jest już śledzony:

git update-index --skip-worktree <file>

Od tego momentu wszystkie lokalne zmiany w tym pliku będą ignorowane i nie będą przekazywane zdalnie. Jeśli plik zostanie zmieniony zdalnie, nastąpi konflikt, kiedy git pull. Skrytka nie będzie działać. Aby rozwiązać ten problem, skopiuj zawartość pliku w bezpieczne miejsce i wykonaj następujące kroki:

git update-index --no-skip-worktree <file>
git stash
git pull 

Zawartość pliku zostanie zastąpiona treścią zdalną. Wklej zmiany z bezpiecznego miejsca do pliku i wykonaj ponownie:

git update-index --skip-worktree <file>

Jeśli wszyscy, którzy pracują z projektem, wykonają git update-index --skip-worktree <file>, problemy pullpowinny być nieobecne. To rozwiązanie jest odpowiednie dla plików konfiguracyjnych, gdy każdy programista ma własną konfigurację projektu.

Nie jest to wygodne za każdym razem, gdy plik jest zmieniany na pilocie, ale może chronić go przed nadpisaniem przez zawartość zdalną.

Boolean_Type
źródło
16

Wykonaj kolejno następujące kroki, wszystko będzie dobrze.

1. usuń błędnie dodane pliki z katalogu / magazynu . Możesz użyć polecenia „rm -r” (dla systemu Linux) lub usunąć je, przeglądając katalogi. Lub przenieś je w inne miejsce na komputerze. [Może być konieczne zamknięcie IDE, jeśli uruchamiasz w celu przeniesienia / usunięcia ]

2. dodaj pliki / katalogi do gitignorepliku teraz i zapisz go.

3. teraz usuń je z pamięci podręcznej git za pomocą tych poleceń (jeśli istnieje więcej niż jeden katalog, usuń je jeden po drugim, powtarzając to polecenie)

git rm -r --cached path-to-those-files

4.Now zrobić popełnić i Push , użyj tych poleceń. Spowoduje to usunięcie tych plików ze zdalnego programu git i spowoduje, że git przestanie śledzić te pliki.

git add .
git commit -m "removed unnecessary files from git"
git push origin
Shamsul Arefin Sajib
źródło
13

Odpowiedź kopiuj / wklej to git rm --cached -r .; git add .; git status

To polecenie zignoruje pliki, które zostały już zatwierdzone w repozytorium Git, ale teraz je dodaliśmy .gitignore.

youhans
źródło
9

Odpowiedź Matta Feara była najskuteczniejsza IMHO. Poniżej znajduje się tylko skrypt PowerShell dla tych w systemie Windows, aby usuwać tylko pliki z repozytorium git, które pasują do ich listy wykluczeń.

# Get files matching exclusionsfrom .gitignore
# Excluding comments and empty lines
$ignoreFiles =  gc .gitignore | ?{$_ -notmatch  "#"} |  ?{$_ -match  "\S"} | % {
                    $ignore = "*" + $_ + "*"
                    (gci -r -i $ignore).FullName
                }
$ignoreFiles = $ignoreFiles| ?{$_ -match  "\S"}

# Remove each of these file from Git 
$ignoreFiles | % { git rm $_}

git add .
Ameer Deen
źródło
W jakiej sytuacji ta lista plików nie będzie równa rekurencyjnej - buforowanej?
John Zabroski
8

Przenieś lub skopiuj plik w bezpieczne miejsce, aby go nie zgubić. Następnie uruchom plik i zatwierdź. Plik będzie nadal wyświetlany, jeśli powrócisz do jednego z wcześniejszych zatwierdzeń lub do innej gałęzi, w której nie został usunięty. Jednak we wszystkich przyszłych zatwierdzeniach plik nie będzie ponownie wyświetlany. Jeśli plik znajduje się w git ignoruj, możesz przenieść go z powrotem do folderu, a git go nie zobaczy.

Apreche
źródło
34
git rm --cachedusunie plik z indeksu bez usuwania go z dysku, więc nie trzeba go przenosić / kopiować
bdonlan,
7

Użycie git rm --cachedpolecenia nie odpowiada na pierwotne pytanie:

Jak zmusić się gitdo całkowitego zapomnienia o [pliku]?

W rzeczywistości, to rozwiązanie spowoduje, że plik do usuniętego w każdym innym przypadku repozytorium podczas wykonywania git pull!

Prawidłowy sposób zmuszenia gita do zapomnienia o pliku jest udokumentowany przez GitHub tutaj .

Polecam lekturę dokumentacji, ale w zasadzie:

git fetch --all
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch full/path/to/file' --prune-empty --tag-name-filter cat -- --all
git push origin --force --all
git push origin --force --tags
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now

po prostu zastąp full/path/to/filepełną ścieżką do pliku. Upewnij się, że dodałeś plik do swojego .gitignore.

Będziesz także musiał (tymczasowo) zezwolić na wypychanie do repozytorium bez szybkiego przewijania do przodu , ponieważ zmieniasz historię git.

Skeets
źródło
5

BFG został zaprojektowany specjalnie do usuwania niechcianych danych, takich jak hasła lub dużych plików z repo Git, więc ma prostą flagę, która usunie wszelkie duże historyczne (nie-in-your-current-commit) pliki: „--strip-blobs- większy niż'

$ java -jar bfg.jar --strip-blobs-bigger-than 100M

Jeśli chcesz określić pliki według nazwy, możesz to zrobić również:

$ java -jar bfg.jar --delete-files *.mp4

BFG jest 10-1000x szybszy niż gałąź filtru git i ogólnie znacznie łatwiejszy w użyciu - sprawdź pełne instrukcje użytkowania i przykłady, aby uzyskać więcej szczegółów.

Źródło: https://confluence.atlassian.com/bitbucket/reduce-repository-size-321848262.html

Meir Gerenstadt
źródło
5

Jeśli nie chcesz korzystać z CLI i pracujesz w systemie Windows, bardzo prostym rozwiązaniem jest użycie TortoiseGit , ma akcję „Usuń (zachowaj lokalną)” w menu, która działa dobrze.

Peter T.
źródło
5

Podobało mi się odpowiedź JonBrave'a, ale mam dość bałaganiarskich katalogów roboczych, które zatwierdzają - trochę mnie przeraża, więc oto co zrobiłem:

git config --global alias.exclude-ignored '! git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached && git ls-files -z --ignored --exclude-standard | xargs -0 git stage && git stage .gitignore && git commit -m "nowy gitignore i usuń zignorowane pliki z indeksu"

rozbicie go:

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached 
git ls-files -z --ignored --exclude-standard | xargs -0 git stage 
git stage .gitignore 
git commit -m "new gitignore and remove ignored files from index"
  • usuń zignorowane pliki z indeksu
  • stage .gitignore i właśnie usunięte pliki
  • popełnić
Jay Irvine
źródło
4

Nie jest to już problemem w najnowszym git (v2.17.1 w momencie pisania).

.gitignoreWreszcie ignoruje śledzone, ale usuniętych plików. Możesz to sprawdzić samodzielnie, uruchamiając następujący skrypt. Ostateczne git statusoświadczenie powinno zawierać „nic do popełnienia”.

# Create empty repo
mkdir gitignore-test
cd gitignore-test
git init

# Create a file and commit it
echo "hello" > file
git add file
git commit -m initial

# Add the file to gitignore and commit
echo "file" > .gitignore
git add .gitignore
git commit -m gitignore

# Remove the file and commit
git rm file
git commit -m "removed file"

# Reintroduce the file and check status.
# .gitignore is now respected - status reports "nothing to commit".
echo "hello" > file
git status
Lloyd
źródło
Cieszę się, że teraz to robi. Jednak OP pytał o to, by nie śledzić modyfikacji plików obecnych w .gitignore, a nie usuwanych plików wciąż pokazujących status.
mrturtle
2

W przypadku już popełnionego DS_Store:

find . -name .DS_Store -print0 | xargs -0 git rm --ignore-unmatch

Zignoruj ​​je przez:

echo ".DS_Store" >> ~/.gitignore_global
echo "._.DS_Store" >> ~/.gitignore_global
echo "**/.DS_Store" >> ~/.gitignore_global
echo "**/._.DS_Store" >> ~/.gitignore_global
git config --global core.excludesfile ~/.gitignore_global

Wreszcie dokonaj zatwierdzenia!


źródło
2

Szczególnie w przypadku plików opartych na IDE używam tego:

Na przykład slnx.sqlite, właśnie się go pozbyłem, jak poniżej:

git rm {PATH_OF_THE_FILE}/slnx.sqlite -f
git commit -m "remove slnx.sqlite"

Pamiętaj tylko, że niektóre z tych plików przechowują niektóre lokalne ustawienia użytkownika i preferencje dla projektów (np. Jakie pliki otworzyłeś). Tak więc za każdym razem, gdy nawigujesz lub zmieniasz IDE, plik ten jest zmieniany, a zatem sprawdza go i pokazuje, jak są niezatwierdzone zmiany.

ciekawy Chłopak
źródło
2

Przyjęta odpowiedź nie powoduje, że Git „zapomina” o pliku ... ”(historycznie). Powoduje to, że git ignoruje plik w teraźniejszości / przyszłości.

Ta metoda powoduje, że git całkowicie zapomina zignorowane pliki ( przeszłość / teraźniejszość / przyszłość), ale nie robi tego usuwa niczego z katalogu roboczego (nawet po ponownym pobraniu ze zdalnego).

Metoda ta wymaga wykorzystania /.git/info/exclude(preferowane) lub wcześniej istniejących .gitignore w każdym z zatwierdzeń, które pliki mają być ignorowane / zapomniane. 1

Wszystkie metody wymuszania git ignorują zachowanie po fakcie skutecznie ponownie zapisują historię, a zatem mają znaczące konsekwencje dla publicznych / wspólnych / wspólnych repozytoriów, które mogą zostać wyciągnięte po tym procesie. 2)

Porady ogólne: zacznij od czystego repozytorium - wszystko zostało popełnione, nic nie czeka w katalogu roboczym lub indeksie i wykonaj kopię zapasową !

Również komentarze / historię zmian od tej odpowiedzi ( oraz historii zmian w tej kwestii ) może być przydatna / oświecenie.

#commit up-to-date .gitignore (if not already existing)
#this command must be run on each branch

git add .gitignore
git commit -m "Create .gitignore"

#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch

git ls-files -z --ignored --exclude-standard | xargs -0 git rm --cached

#Commit to prevent working directory data loss!
#this commit will be automatically deleted by the --prune-empty flag in the following command
#this command must be run on each branch

git commit -m "ignored index"

#Apply standard git ignore behavior RETROACTIVELY to all commits from all branches (--all)
#This step WILL delete ignored files from working directory UNLESS they have been dereferenced from the index by the commit above
#This step will also delete any "empty" commits.  If deliberate "empty" commits should be kept, remove --prune-empty and instead run git reset HEAD^ immediately after this command

git filter-branch --tree-filter 'git ls-files -z --ignored --exclude-standard | xargs -0 git rm -f --ignore-unmatch' --prune-empty --tag-name-filter cat -- --all

#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch

git ls-files --other --ignored --exclude-standard

Na koniec postępuj zgodnie z resztą tego przewodnika GitHub (zaczynając od kroku 6), który zawiera ważne ostrzeżenia / informacje o poniższych poleceniach .

git push origin --force --all
git push origin --force --tags
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now

Inni deweloperzy, którzy pobierają teraz zmodyfikowane zdalne repozytorium, powinni wykonać kopię zapasową, a następnie:

#fetch modified remote

git fetch --all

#"Pull" changes WITHOUT deleting newly-ignored files from working directory
#This will overwrite local tracked files with remote - ensure any local modifications are backed-up/stashed

git reset FETCH_HEAD

Przypisy

1 Ponieważ /.git/info/excludemożna zastosować do wszystkich historycznych zatwierdzeń przy użyciu powyższych instrukcji, być może szczegóły dotyczące umieszczania .gitignorepliku w historycznych zatwierdzeniach, które go potrzebują, wykraczają poza zakres tej odpowiedzi. Chciałem, żeby właściwość .gitignoreznajdowała się w głównym zatwierdzeniu, jakby to była pierwsza rzecz, którą zrobiłem. Inni mogą się tym nie przejmować, ponieważ /.git/info/excludemogą osiągnąć to samo, bez względu na to, gdzie .gitignoreistnieje w historii zatwierdzeń, a wyraźne ponowne zapisanie historii jest bardzo drażliwym tematem, nawet jeśli zdaje sobie sprawę z konsekwencji .

FWIW, potencjalne metody mogą obejmować git rebaselub git filter-branchkopiowanie zewnętrznego .gitignore do każdego zatwierdzenia, podobnie jak odpowiedzi na to pytanie

2 Wymuszanie zachowania git ignore po fakcie przez zatwierdzenie wyników działania samodzielnego git rm --cachedpolecenia może spowodować usunięcie nowo zignorowanego pliku w przyszłych ściągnięciach ze zdalnego sterowania wymuszonego. --prune-emptyFlag w następującej git filter-branchkomendy pozwala uniknąć tego problemu poprzez automatyczne usunięcie poprzedniego „usunąć wszystkie pliki ignorowane” indeksu tylko popełnić. Ponowne pisanie historii gitów zmienia także skróty zatwierdzania, które sieją spustoszenie w przyszłych ściągnięciach z repozytoriów publicznych / wspólnych / współpracujących. Proszę zrozumieć konsekwencje w pełni przed zrobieniem tego do takiego repozytorium. W tym przewodniku GitHub określono:

Powiedz swoim współpracownikom, aby utworzyli bazy , a nie scalali, wszelkie gałęzie, które utworzyli ze starej (skażonej) historii repozytorium. Jedno zatwierdzenie scalania może przywrócić część lub całą skażoną historię, którą właśnie zadałeś sobie trud oczyszczenia.

Alternatywnymi rozwiązaniami, które nie wpływają na zdalne repo, są git update-index --assume-unchanged </path/file>lub git update-index --skip-worktree <file>, których przykłady można znaleźć tutaj .

goofologia
źródło
0

Jeśli ktoś ma problemy z systemem Windows i chcesz zignorować cały folder, „cd”, aby wybrać „folder” i wykonaj „Git Bash Here”.

git ls-files -z | xargs -0 git update-index --assume-unchanged
RajVimalC
źródło
0

W moim przypadku miałem kilka plików .lock w kilku katalogach, które musiałem usunąć. Uruchomiłem następujące i działało bez konieczności wchodzenia do każdego katalogu, aby je usunąć:

git rm -r --cached **/*.lock

W ten sposób wszedłem do każdego folderu w „katalogu głównym”, w którym byłem, i wykluczyłem wszystkie pliki, które pasowały do ​​wzorca.

Mam nadzieję, że to pomaga innym!

DC.Skells
źródło