git pull, gdy nie ma go w katalogu git

308

Powiedzmy, że mam katalog /X/Y, który jest repozytorium git. Czy można w jakiś sposób wywołać komendę git pullwewnętrzną /X, ale celując w /X/Ykatalog?

EDYCJA: Myślę, że zastanawiałem się konkretnie: czy można to zrobić za pomocą polecenia git, ale bez konieczności zmiany katalogów?

UWAGA: Zaakceptowałem odpowiedź VonC, ponieważ jest ona znacznie bardziej elegancka niż poprzednie opcje. Dla osób korzystających z Git starszych niż 1.8.5, patrz odpowiedź bstpierre poniżej .

Gavin Anderegg
źródło
2
Chciałbym dodać, że podczas używania polecenia git-pull w haczyku nie będzie działać, chyba że odłączysz GIT_DIR. Istotnych.
zpmorgan
Począwszy od gita 1.8.5 (IV kwartał 2013 r.) Będziesz mógł „używać polecenia git, ale bez konieczności zmiany katalogów”. Zobacz moją odpowiedź poniżej
VonC

Odpowiedzi:

453

Począwszy od gita 1.8.5 (IV kwartał 2013 r.) , Będziesz mógł „używać polecenia Git, ale bez konieczności zmiany katalogów”.

Podobnie jak „ make -C <directory>”, git -C <directory> ...” każe Gitowi udać się tam, zanim zrobi cokolwiek innego .

Zobacz commit 44e1e4 autorstwa Nazri Ramliy :

Więcej naciśnięć klawiszy wymaga wywołania polecenia Git w innym katalogu bez opuszczania bieżącego katalogu:

  1. (cd ~/foo && git status)
    git --git-dir=~/foo/.git --work-tree=~/foo status
    GIT_DIR=~/foo/.git GIT_WORK_TREE=~/foo git status
  2. (cd ../..; git grep foo)
  3. for d in d1 d2 d3; do (cd $d && git svn rebase); done

Metody pokazane powyżej są dopuszczalne dla skryptów, ale są zbyt kłopotliwe dla szybkich wywołań z wiersza poleceń.

Dzięki tej nowej opcji można to zrobić przy mniejszej liczbie naciśnięć klawiszy:

  1. git -C ~/foo status
  2. git -C ../.. grep foo
  3. for d in d1 d2 d3; do git -C $d svn rebase; done

Ponieważ Git 2.3.4 (marzec 2015), a także zobowiązać 6a536e2 przez Karthik Nayaka ( KarthikNayak) , gitbędzie leczyć " git -C '<path>'" jako nie-op, gdy <path>jest pusta.

git -C ""” niepomyślnie umiera z błędem „ Cannot change to ''”, podczas gdy powłoka traktuje cd „” jako brak możliwości działania.
Biorąc zachowanie powłoki za precedens, naucz gitrównież traktować -C „” jako brak możliwości.


4 lata później Git 2.23 (III kwartał 2019 r.) Dokumentuje, że „ git -C ""” działa i nie zmienia katalogu

Zachowuje się tak od 6a536e2 ( git: traktuj „ git -C '<path>'” jako brak możliwości, gdy <path>jest pusty, 2015-03-06, Git v2.3.4).

Oznacza to, że dokumentacja teraz (wreszcie) obejmuje:

Jeśli „ <path>” jest obecne, ale puste, np -C "". Bieżący katalog roboczy pozostaje niezmieniony.


git -CJako przykład możesz użyć Git 2.26 (Q1 2020).

Patrz popełnienia b441717 , popełnienia 9291e63 , popełnienia 5236fce , popełnienia 10812c2 , popełnienia 62d58cd , popełnienia b87b02c , popełnienia 9b92070 , popełnienia 3595d10 , popełnienia f511bc0 , popełnienia f6041ab , popełnienia f46c243 , popełnienia 99c049b , popełnienia 3738439 , popełnienia 7717242 , popełnienia b8afb90 (20 grudnia 2019), autor: Denton Liu ( Denton-L) .
(Połączone przez Junio ​​C Hamano - gitster- w commit 381e8e9 , 05 lutego 2020)

t1507: inline full_name()

Podpisano: Denton Liu

Wcześniej biegaliśmy test_must_fail full_name. Jednak test_must_failnależy go używać tylko w poleceniach git.
Wbudowany full_name(), abyśmy mogli bezpośrednio korzystać test_must_failz gitpolecenia.

Kiedy full_name()został wprowadzony w 28fb84382b ( „Wprowadzenie <branch>@{upstream}zapisu”, 2009-09-10, Git v1.7.0-RC0 - scalanie ), przy czym git -Copcja nie była dostępna jeszcze (ponieważ został wprowadzony w 44e1e4d67d (” git: prowadzony w danym katalogu z opcją -C, 2013-09-09, Git v1.8.5-rc0 - scalenie wymienione w partii nr 5 )).
W rezultacie funkcja pomocnika eliminuje potrzebę ręcznego za cdkażdym razem. Ponieważ jednak git -Cjest już dostępny, możemy go po prostu użyć zamiast tego full_name().

VonC
źródło
6
O, nieźle! Jest to o wiele bardziej eleganckie, więc oznaczę to jako akceptowane dla przyszłych widzów.
Gavin Anderegg
1
Nie działa dla mnie: # git --version && git -C ~ / .m2 / checkout master git wersja 1.8.3.4 (Apple Git-47) Nieznana opcja: -C użycie: git [--version] [--help ] [-c name = wartość] [--exec-path [= <ścieżka>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir = <ścieżka>] [--work-tree = <ścieżka>] [--namespace = <nazwa> ] <polecenie> [<args>]
Jan Galiński
7
@JanGalinski Ale wspomniałem o „Zaczynaniu gita 1.8.5”. Więc git 1.8.3.x nie wiedziałby jeszcze o tej opcji.
VonC
2
Na Ubuntu 12.04 musiałem zainstalować nowszą wersję git. Zrobiłem tak: apt-get install software-properties-common python-software-propertiesdodaj repozytorium git add-apt-repository ppa:git-core/ppa. Ostatnim krokiem jest aktualizacja git: apt-get update && apt-get upgrade.
ph3nx
54

Edytuj :

Wystąpił błąd git pulllub nie możesz zrobić tego, co próbujesz zrobić za pomocą tego polecenia. Możesz to jednak zrobić za pomocą funkcji pobierania i scalania:

cd /X
git --git-dir=/X/Y/.git fetch
git --git-dir=/X/Y/.git --work-tree=/X/Y merge origin/master

Oryginalna odpowiedź :

Zakładając, że używasz bash lub podobnego, możesz to zrobić (cd /X/Y; git pull).

Strona man git określa niektóre zmienne (patrz „Repozytorium git”), które wydają się, że powinny pomóc, ale nie mogę sprawić, by działały poprawnie (z moim repozytorium w / tmp / ggg2):

GIT_WORK_TREE=/tmp/ggg2 GIT_DIR=/tmp/ggg2/.git git pull
fatal: /usr/lib/git-core/git-pull cannot be used without a working tree.

Uruchomienie poniższej komendy, gdy mój cwd to / tmp aktualizuje repozytorium, ale zaktualizowany plik pojawia się w / tmp zamiast drzewa roboczego / tmp / ggg2:

GIT_DIR=/tmp/ggg2/.git git pull

Zobacz także tę odpowiedź na podobne pytanie , które pokazuje flagi --git-diri --work-tree.

bstpierre
źródło
Czy próbowałeś użyć tylko GIT_WORK_TREE?
Arrowmaster
@Arrowmaster: tak, jeśli to zrobisz, git nie może znaleźć .gitkatalogu.
bstpierre
Ach tak, strona podręcznika mówi, że GIT_WORK_TREE nie jest używany, jeśli GIT_DIR nie jest ustawiony. Wydaje się dziwne, że nie działa wtedy, gdy oba są używane.
Arrowmaster
@Arrowmaster: Muszę się zastanawiać, czy gdzieś tu jest błąd. Jeśli to zrobię git --git-dir=/tmp/ggg2/.git --work-tree=/tmp/ggg2 pull, pojawia się komunikat o błędzie. Ale jeśli zrobię to, git --git-dir=/tmp/ggg2/.git --work-tree=. pullgdy jestem w / tmp, wstawi zaktualizowane pliki do / tmp tak, jak powinno.
bstpierre
@bstpierre: Nie mam dostępu do systemu z zainstalowanym teraz git ale gdybym to zrobił bym próbować innych alternatyw ze --work-treeteraz jak --work-tree=/tmp/ggg2/i --work-tree=/tmp/ggg2/.ponieważ może to być problem z tym, jak jego parsowania ścieżkę.
Arrowmaster
32

Możesz zawinąć go w skrypt bash lub alias git:

cd /X/Y && git pull && cd -
zabiera
źródło
1
To zdecydowanie załatwia sprawę, ale zastanawiam się, czy jest jakiś sposób na użycie polecenia git bez zmiany katalogów. Zaczynam myśleć, że nie ma.
Gavin Anderegg
1
i użyj pushd/popdpary zamiastcd/cd-
axd
Możesz też użyć podpowłoki, aby uniknąć konieczności cofania płyty:(cd xyz && git pull)
jarmod
30

Ten post jest trochę stary, więc mógł wystąpić błąd i został naprawiony, ale właśnie to zrobiłem:

git --work-tree=/X/Y --git-dir=/X/Y/.git pull origin branch

I zadziałało. Zajęło mi chwilę, aby dowiedzieć się, że chciał plik dot i plik nadrzędny (w standardowej konfiguracji są one zawsze nadrzędne / podrzędne, ale nie we WSZYSTKICH konfiguracjach, więc należy je wyraźnie określić).

samtresler
źródło
Podoba mi się to rozwiązanie, ponieważ działa z katalogami takimi jak \\ remotemachine \ C $ \ folder \ etc
twasbrillig
7

Ponieważ niektóre moje serwery mają starsze wersje Ubuntu LTS, nie mogę łatwo zaktualizować gita do najnowszej wersji (która obsługuje opcję -C, jak opisano w niektórych odpowiedziach).

Ta sztuczka działa dla mnie dobrze, szczególnie dlatego, że nie ma skutków ubocznych niektórych innych odpowiedzi, które pozostawiają cię w innym katalogu niż miejsce, w którym zacząłeś.

pushd /X/Y
git pull
popd

Lub robiąc to jako jedno-liniowy:

pushd /X/Y; git pull; popd

Zarówno Linux, jak i Windows mają polecenia pushd i popd.

IvanD
źródło
5

Stosując kombinację pushd, git pulli popdmożemy osiągnąć tę funkcjonalność:

pushd <path-to-git-repo> && git pull && popd

Na przykład:

pushd "E:\Fake Directory\gitrepo" && git pull && popd
Raman Sahasi
źródło
to jest niesamowite. Działa doskonale
Stretch0,
4

Możesz napisać taki skrypt:

cd /X/Y
git pull

Możesz nazwać to jakoś gitpull.
Jeśli wolisz, aby robił to dowolnymi katalogami zamiast /X/Y:

cd $1
git pull

Następnie możesz to nazwać za pomocą gitpull /X/Z
Wreszcie, możesz spróbować znaleźć repozytoria. Mam ~/gitfolder, który zawiera repozytoria, i możesz użyć tego, aby pociągnąć je wszystkie.

g=`find /X -name .git`
for repo in ${g[@]}
do
    cd ${repo}
    cd ..
    git pull
done
jonescb
źródło
2
Jeśli chcesz to zrobić z wiersza poleceń, zrób to w podpowłoce: (cd /X/Y && git pull).
Cascabel
2

Dla każdego takiego jak ja, który próbował to zrobić za pomocą komendy drush (powłoka Drupal) na zdalnym serwerze, nie będziesz mógł skorzystać z rozwiązania, które wymaga dysku CD do katalogu roboczego:

Zamiast tego musisz użyć rozwiązania, które rozbija pull na pobieranie i scalanie:

drush @remote exec git --git-dir=/REPO/PATH --work-tree=/REPO/WORKDIR-PATH fetch origin
drush @remote exec git --git-dir=/REPO/PATH --work-tree=/REPO/WORKDIR-PATH merge origin/branch
dkinzer
źródło
1

Może to być podobny problem, ale możesz też po prostu połączyć łańcuch poleceń. na przykład

W jednej linii

cd ~/Sites/yourdir/web;git pull origin master

Lub przez SSH.

ssh [email protected] -t "cd ~/Sites/thedir/web;git pull origin master"
John Ballinger
źródło