Dodać wszystkie pliki do zatwierdzenia oprócz jednego pliku?

569

Mam kilka plików w zestawie zmian, ale chcę specjalnie zignorować pojedynczy zmodyfikowany plik. Wygląda tak po git status:

# modified:   main/dontcheckmein.txt
# deleted:    main/plzcheckmein.c
# deleted:    main/plzcheckmein2.c
...

Czy mogę to zrobić, git addale po prostu zignoruj ​​jeden plik tekstowy, którego nie chcę dotykać? Coś jak:

git add -u -except main/dontcheckmein.txt
użytkownik291701
źródło

Odpowiedzi:

850
git add -u
git reset -- main/dontcheckmein.txt
Ben Jackson
źródło
28
Jak wykluczyć cały folder? - główny czy główny / lub główny / *?
Alan Coromano
8
@MariusKavansky Możesz użyć wszystkich tych formularzy. Jeśli używasz main/*, konieczne jest dodanie --przed nim, aby poinformować git, że jest to ścieżka. Pozostałe dwa warianty działają bez uwzględnienia dwóch myślników. (Testowane w wierszu polecenia w systemie Windows 7 z msysGit)
dennisschagt
2
Jeśli masz jakieś foldery, które chcesz wykluczyć, które zawierają dużą liczbę plików lub innych folderów: tymczasowo dodaj je do swojego gitignore. wykonanie git resetdla tych folderów później będzie nadal działać, ale dodanie dużych folderów zajmie trochę czasu.
Michael Trouw
2
Więc nie ma jednej linijki?
BroVic
5
@Ben Jackson byłby miły komentować każdą linię, nie sądzisz?
ed1nh0
140

1) Aby rozpocząć ignorowanie zmian w jednym już wersjonowanym pliku

git update-index --assume-unchanged "main/dontcheckmein.txt"

i cofnąć to git update-index --no-assume-unchanged "main/dontcheckmein.txt"

github docs, aby zignorować pliki

2) Całkowite zignorowanie konkretnego pojedynczego pliku, uniemożliwiając jego utworzenie w repozytorium

Najpierw spójrz na ten post stackflowflow : Git globalne ignorowanie nie działa

W .gitignoredodaj ścieżkę względną do pliku bez prowadzenia ./.

Tak więc, jeśli twój plik znajduje się w MyProject/MyFolder/myfile.txt(gdzie .gitjest również w MyProjectfolderze), dodaj MyFolder/myfile.txtdo .gitignorepliku at .

Możesz potwierdzić, jakie reguły są powiązane z ignorowaniem przez git check-ignore "MyFolder/myfile.txt"

O globalnym ignorowaniu

Ten link mówi ~/.gitignore_global, ale plik jest powiązany z twoim projektem. Tak więc, jeśli umieścić wyklucza wzór MyFolder/myfile.txtw ~/.gitignore_global, to będzie działać, ale nie będzie sensu ...

Z drugiej strony, jeśli skonfigurujesz projekt z tym, git config core.excludesfile .gitignoregdzie .gitignorejest MyProject, plik lokalny zastąpi się ~/.gitignore_global, co może mieć bardzo przydatne reguły ...

Więc teraz, myślę, że najlepiej zrobić jakiś skrypt, aby mieszać .gitignorez ~/.gitignore_globalco .gitignore.

Ostatnie ostrzeżenie
Jeśli plik, który chcesz zignorować, znajduje się już w repozytorium, ta metoda nie będzie działać, chyba że to zrobisz: git rm "MyFolder/myfile.txt"ale najpierw wykonaj kopię zapasową, ponieważ zostanie ona również usunięta lokalnie! Możesz skopiować go później ...

Moc Wodnika
źródło
5
Możesz użyć git rm --cached MyFolder/myyfile.txtdo usunięcia pliku z repozytorium, ale zachowaj go lokalnie. Wyjaśnienie na help.github.com
dennisschagt
87

Dla pliku

git add -u
git reset -- main/dontcheckmein.txt

Dla folderu

git add -u
git reset -- main/*
Rituraj ratan
źródło
9
dlaczego konieczne jest -u? dlaczego nie git add . && git reset -- main/*?
2
Opcja -u aktualizuje indeks dokładnie tam, gdzie ma już wpis pasujący do <pathspec>. To usuwa, a także modyfikuje wpisy indeksu, aby pasowały do ​​drzewa roboczego, ale nie dodaje nowych plików. Jeśli nie podano <spathspec>, gdy użyta jest opcja -u, wszystkie śledzone pliki w całym pracującym drzewie są aktualizowane (stare wersje Git były używane do ograniczenia aktualizacji do bieżącego katalogu i jego podkatalogów).
Farhad Mammadli,
6
Czy ktoś może wyjaśnić, dlaczego -u jest konieczne w języku zrozumiałym dla profesjonalistów niebędących gitami?
Patrick,
2
-u służy do odniesienia do twojej bieżącej gałęzi, do której naciskasz. Nie będziesz już musiał wpisywać git push origin masternastępnego wypychania, tylko git pushgit będzie wiedział, że to w gałęzi master. Mam nadzieję, że to pomoże.
Pepeng Hapon,
69

Teraz gitobsługuje exclude certain paths and filesmagię pathspec :(exclude)i jej krótką formę :!. Możesz więc łatwo to osiągnąć, wykonując następujące polecenie.

git add --all -- :!main/dontcheckmein.txt
git add -- . :!main/dontcheckmein.txt

W rzeczywistości możesz podać więcej:

git add --all -- :!path/to/file1 :!path/to/file2 :!path/to/folder1/*
git add -- . :!path/to/file1 :!path/to/file2 :!path/to/folder1/*
kocie oczy
źródło
1
Najlepsza odpowiedź, dzięki! Przynajmniej w moim przypadku: musiałem po prostu wykluczyć typ pliku.
Andre Polykanine,
15
To jest doskonałe! Zauważ, że w Linuksie musisz zacytować :!...klauzule, aby powłoka nie narzekała. Tak więc, na przykład: git add --all -- ':!path/to/file1' ':!path/to/file2' ':!path/to/folder1/*'.
Martin_W
Czy jest coś takiego :!/path/to/(file1|file2)?
seeker_of_bacon
To koliduje z czymś w Zsh, nie działa dla mnie na macOS i najnowszym git.
Merlin,
1
Czy ktoś może wskazać, gdzie jest to oficjalnie udokumentowane?
samurai_jane
20

Chociaż Ben Jackson ma rację, pomyślałem, że dodam również to, jak korzystam z tego rozwiązania. Poniżej znajduje się bardzo prosty skrypt, którego używam (nazywam gitadd), aby dodać wszystkie zmiany oprócz kilku wybranych, które trzymam na liście w pliku o nazwie .gittrackignore(bardzo podobny do działania .gitignore).

#!/bin/bash
set -e

git add -A
git reset `cat .gittrackignore`

I tak .gittrackignorewygląda mój obecny .

project.properties

Pracuję nad projektem Androida, który kompiluję z wiersza poleceń podczas wdrażania. Ten projekt zależy od SherlockActionBar, więc należy się do niego odwoływać w project.properties, ale to komplikuje się w kompilacji, więc teraz po prostu wpisuję gitaddi dodam wszystkie zmiany do git bez konieczności cofania dodawania project.properties za każdym razem.

Anthony Naddeo
źródło
Nie wiedziałam, co --było do czasu twojego komentarza. Według stron podręcznika man jest opcjonalny i nie zmienia wyniku polecenia (przynajmniej w tym przypadku). To pytanie wydaje się wspierać, że stackoverflow.com/questions/17800994/... . Popraw mnie, jeśli się mylę, ale wygląda na to, że oznacza to „traktuj wszystko --jako argumenty, a nie opcje / przełączniki”
Anthony Naddeo,
Ładne zastosowanie --w git checkoutWidzę w tym pytaniu. Nie wiedziałem też, co to za podwójna kreska, aż do tej naszej wymiany. Zastanawiam się, czy git checkoutniejednoznaczność między gałęziami a plikami może mieć wpływ również w tej lub innej formie git reset.
Giulio Piancastelli,
10

Zrobiłem to, aby zachować zmianę w pliku, ale nie zatwierdzić

git add .

git reset -- main/dontcheckmein.txt

git commit -m "commit message"

aby sprawdzić, czy plik jest wykluczony, wykonaj

git status

gsumk
źródło
4

Służy git add -Ado dodawania wszystkich zmodyfikowanych i nowo dodanych plików jednocześnie.

Przykład

git add -A
git reset -- main/dontcheckmein.txt
Dhanuka Nuwan
źródło
4
git add .
git reset main/dontcheckmein.txt
Daniel Danielecki
źródło
1

W konkretnym przypadku w pytaniu najłatwiej byłoby dodać wszystkie pliki z rozszerzeniem .c i pominąć wszystko inne:

git add *.c

Z git-scm (lub / i man git add):

git dodaj <ścieżka>

Pliki do dodania treści. Fileglobs (np. * .C) można podać, aby dodać wszystkie pasujące pliki. <...>

Pamiętaj, że oznacza to, że możesz również zrobić coś takiego:

git add **/main/*

aby dodać wszystkie pliki (które nie są ignorowane) znajdujące się w mainfolderze. Możesz nawet zaszaleć dzięki bardziej wyszukanym wzorom:

git add **/s?c/*Service*

Powyżej doda wszystkie pliki, które są w s(any char)cfolderze i mają Servicegdzieś w nazwie pliku.

Oczywiście nie jesteś ograniczony do jednego wzorca na polecenie. Oznacza to, że możesz poprosić git o dodanie wszystkich plików z rozszerzeniem .c i .h :

git add *.c *.h

Ten link może dać ci więcej pomysłów na globalne wzorce.

Uważam, że jest to szczególnie przydatne, gdy dokonuję wielu zmian, ale nadal chcę, aby moje zobowiązania pozostały atomowe i odzwierciedlały stopniowy proces, a nie mnogość zmian, nad którymi mógłbym wówczas pracować. Oczywiście w pewnym momencie koszt opracowania skomplikowanych wzorów przewyższa koszt dodawania plików prostszymi metodami lub nawet jednego pliku na raz. Jednak przez większość czasu jestem w stanie łatwo zlokalizować tylko potrzebne mi pliki za pomocą prostego wzoru i wykluczyć wszystko inne.

Nawiasem mówiąc, być może będziesz musiał zacytować swoje globalne wzorce, aby działały, ale nigdy tak nie było.

cegas
źródło
0

Używam git add --patchcałkiem sporo i chciałem czegoś takiego, aby uniknąć konieczności ciągłego dprzeszukiwania tych samych plików. Wymyśliłem bardzo zuchwałą parę aliasów git, aby wykonać zadanie:

[alias]
    HELPER-CHANGED-FILTERED = "!f() { git status --porcelain | cut -c4- | ( [[ \"$1\" ]] && egrep -v \"$1\" || cat ); }; f"
    ap                      = "!git add --patch -- $(git HELPER-CHANGED-FILTERED 'min.(js|css)$' || echo 'THIS_FILE_PROBABLY_DOESNT_EXIST' )"

W moim przypadku chciałem po prostu cały czas ignorować niektóre zminimalizowane pliki, ale możesz sprawić, aby używał zmiennej środowiskowej, tak jak $GIT_EXCLUDE_PATTERNw przypadku bardziej ogólnego przypadku.

Chris
źródło
0

Zmiany do zatwierdzenia: (użyj „git reset HEAD ...”, aby wycofać się ze sceny)

Colin Rickels
źródło
0

Możesz spróbować: git add * && git reset main/dontcheckmein.txt

Rodrigo
źródło