git pull пока не в каталоге git

308

Допустим, у меня есть каталог /X/Y, который является git-репозиторием. Можно ли как-то вызвать команду как git pullизнутри /X, но нацеленную на /X/Yкаталог?

РЕДАКТИРОВАТЬ: я думаю, мне было интересно: возможно ли это сделать с помощью команды git, но без необходимости изменять каталоги?

ПРИМЕЧАНИЕ: я принял ответ VonC, так как он намного элегантнее предыдущих вариантов. Если вы пользуетесь Git старше 1.8.5, см . Ответ bstpierre ниже .

Гэвин Андерегг
источник
2
Я хотел бы добавить, что при использовании git-pull внутри ловушки не будет работать, если вы не сбросили GIT_DIR. Соответствующий.
zpmorgan
Начиная с git 1.8.5 (4 квартал 2013 года), вы сможете «использовать команду git, но без необходимости менять каталоги». Смотрите мой ответ ниже
VonC

Ответы:

453

Начиная с git 1.8.5 (4 квартал 2013 года) , вы сможете «использовать команду Git, но без необходимости менять каталоги».

Точно так же, как « make -C <directory>», « git -C <directory> ...» говорит Git идти туда, прежде чем делать что-либо еще .

Смотрите коммит 44e1e4 от Назри Рамлия :

Требуется больше нажатий клавиш для вызова команды Git в другом каталоге, не выходя из текущего каталога:

  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

Описанные выше методы приемлемы для сценариев, но слишком громоздки для быстрых вызовов командной строки.

С помощью этой новой опции, вышеупомянутое может быть сделано с меньшим количеством нажатий клавиш:

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

Так как Git 2.3.4 (март 2015 г.), а также совершать 6a536e2 по Karthik Наяка ( KarthikNayak) , gitбудет относиться к « git -C '<path>'» как не-оп , когда <path>пусто.

' git -C ""' бесполезно умирает с ошибкой " Cannot change to ''', в то время как оболочка рассматривает cd" "" как бездействие.
Принимая поведение оболочки в качестве прецедента, научите gitобращаться с -C "" 'также как с запретом.


4 года спустя Git 2.23 (Q3 2019) документирует, что ' git -C ""' работает и не меняет каталог

Он ведет себя так с 6a536e2 ( git: обрабатывать " git -C '<path>'" как запрет, когда <path>пусто, 2015-03-06, Git v2.3.4).

Это означает, что документация теперь (наконец) включает в себя:

Если ' <path>' присутствует, но пусто, например -C "", то текущий рабочий каталог остается без изменений.


В git -Cкачестве примера вы можете увидеть использование с Git 2.26 (Q1 2020).

См. Коммит b441717 , коммит 9291e63 , коммит 5236fce , коммит 10812c2 , коммит 62d58cd , коммит b87b02c , коммит 9b92070 , коммит 3595d10 , коммит f511bc0 , коммит f6041ab , коммит f46c243 , коммит 99c049b , коммит 3738439 , коммит 7717249 , коммит 20af8, дек 8 от Denton Лю ( Denton-L) .
(Слиты Junio C Hamano - gitster- в фиксации 381e8e9 , 05 Feb 2020)

t1507: в линию full_name()

Подписано: Дентон Лю

Раньше мы бегали test_must_fail full_name. Тем не менее, test_must_failследует использовать только для команд git.
Встроенный, full_name()так что мы можем использовать test_must_failпо gitкоманде напрямую.

Когда эта функцияfull_name() была введена в 28fb84382b («Ввести <branch>@{upstream}нотацию», 2009-09-10, Git v1.7.0-rc0 - merge ), эта git -Cопция еще не была доступна (поскольку она была введена в 44e1e4d67d (" git: запустить в заданном каталоге). с опцией -C ", 2013-09-09, Git v1.8.5-rc0 - объединение, указанное в пакете № 5 )).
В результате вспомогательная функция устраняет необходимость cdкаждый раз вручную . Тем не менее, поскольку git -Cэто доступно сейчас, мы можем просто использовать это вместо и встроенный full_name().

VonC
источник
6
Вау круто! Это намного элегантнее, поэтому я отмечу, что это принято для будущих зрителей.
Гэвин Андерегг
1
У меня не работает: # git --version && git -C ~ / .m2 / checkout master git версия 1.8.3.4 (Apple Git-47) Неизвестная опция: -C использование: git [--version] [--help ] [-c имя = значение] [--exec-путь [= <путь>]] [--html-путь] [--man-путь] [--info-путь] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir = <путь>] [--work-tree = <путь>] [--namespace = <имя> ] <команда> [<args>]
Ян Галински
7
@JanGalinski Но я упомянул "Запуск git 1.8.5". Так что git 1.8.3.x пока не знает об этой опции.
VonC
2
На Ubuntu 12.04 мне пришлось установить более новую версию git. Я сделал это так: apt-get install software-properties-common python-software-propertiesзатем добавьте git-репо add-apt-repository ppa:git-core/ppa. Последним шагом является обновление мерзавца: apt-get update && apt-get upgrade.
ph3nx
54

Редактировать :

Либо есть ошибка git pull, либо вы не можете делать то, что пытаетесь сделать с помощью этой команды. Однако вы можете сделать это с помощью fetch и merge:

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

Оригинальный ответ :

Предполагая, что вы работаете с Bash или подобным, вы можете это сделать (cd /X/Y; git pull).

Страница man git указывает некоторые переменные (см. «Репозиторий git»), которые, похоже, должны помочь, но я не могу заставить их работать правильно (с моим репозиторием в / 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.

Выполнение команды ниже, в то время как мой cwd является / tmp, обновляет этот репозиторий, но обновленный файл появляется в / tmp вместо рабочего дерева / tmp / ggg2:

GIT_DIR=/tmp/ggg2/.git git pull

Смотрите также этот ответ на подобный вопрос , который демонстрирует --git-dirи --work-treeфлаги.

bstpierre
источник
Вы пытались использовать только GIT_WORK_TREE?
Arrowmaster
@Arrowmaster: да, если вы это сделаете, git не сможет найти .gitкаталог.
bstpierre
Ах да, справочная страница говорит, что GIT_WORK_TREE не используется, если GIT_DIR не установлен. Кажется странным, что это не работает тогда, когда оба используются.
Arrowmaster
@Arrowmaster: Мне интересно, есть ли где-нибудь ошибка здесь. Если я это сделаю git --git-dir=/tmp/ggg2/.git --work-tree=/tmp/ggg2 pull, я получу сообщение об ошибке. Но если я это сделаю, git --git-dir=/tmp/ggg2/.git --work-tree=. pullнаходясь в / tmp, обновленные файлы будут помещены в / tmp, как и должно быть.
bstpierre
@bstpierre: У меня нет доступа к системе с установленным git прямо сейчас, но если бы я это сделал, я бы попробовал другие альтернативы --work-treeпрямо сейчас, например, --work-tree=/tmp/ggg2/и --work-tree=/tmp/ggg2/.так как это могло бы быть проблемой с тем, как анализировать путь.
Arrowmaster
32

Вы можете обернуть его в скрипт bash или псевдоним git:

cd /X/Y && git pull && cd -
takeshin
источник
1
Это определенно работает, но мне интересно, есть ли способ использовать команду git без изменения каталогов. Я начинаю думать, что нет.
Гэвин Андерегг
1
и использовать pushd/popdпару вместоcd/cd-
AxD
Или вы можете использовать подоболочку, чтобы избежать необходимости (cd xyz && git pull)
переписываться
30

Этот пост немного устарел, поэтому, возможно, там была ошибка, и она была исправлена, но я просто сделал это:

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

И это сработало. Мне потребовалась минута, чтобы понять, что ему нужны точечный файл и родительский каталог (в стандартной настройке это всегда родитель / потомок, но не во ВСЕХ установках, поэтому их нужно указывать явно.

samtresler
источник
Мне нравится это решение, потому что оно работает с каталогами, такими как \\ remotemachine \ C $ \ folder \ etc
twasbrillig
7

Поскольку некоторые из моих серверов работают на старых версиях Ubuntu LTS, я не могу легко обновить git до последней версии (которая поддерживает опцию -C, как описано в некоторых ответах).

Этот трюк хорошо работает для меня, особенно потому, что у него нет побочного эффекта некоторых других ответов, которые оставляют вас в другом каталоге, с которого вы начали.

pushd /X/Y
git pull
popd

Или, делая это как однострочник:

pushd /X/Y; git pull; popd

В Linux и Windows есть команды pushd и popd.

IvanD
источник
5

Используя комбинацию pushd, git pullи popdмы можем достичь этой функции:

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

Например:

pushd "E:\Fake Directory\gitrepo" && git pull && popd
Раман Сахаси
источник
это потрясающе. Работает отлично
Stretch0
4

Вы можете написать скрипт так:

cd /X/Y
git pull

Вы можете назвать это как-то так gitpull.
Если вы предпочитаете, чтобы он делал произвольные каталоги вместо /X/Y:

cd $1
git pull

Затем вы можете позвонить с помощью gitpull /X/Z
Наконец, вы можете попробовать найти хранилища. У меня есть ~/gitпапка, которая содержит репозитории, и вы можете использовать это, чтобы вытащить их все.

g=`find /X -name .git`
for repo in ${g[@]}
do
    cd ${repo}
    cd ..
    git pull
done
jonescb
источник
2
Если вы хотите сделать это из командной строки, просто сделать это в субоболочке: (cd /X/Y && git pull).
Каскабель
2

Для любого, как я, который пытался сделать это с помощью команды drush (оболочка Drupal) на удаленном сервере, вы не сможете использовать решение, которое требует, чтобы вы записали компакт-диск в рабочий каталог:

Вместо этого вам нужно использовать решение, которое разбивает тягу на извлечение и объединение:

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
источник
1

Это может быть похожая проблема, но вы также можете просто связать команды. например

На одной линии

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

Или через SSH.

ssh username@atyourserver.com -t "cd ~/Sites/thedir/web;git pull origin master"
Джон Баллинджер
источник