git pull enquanto não estiver em um diretório git

308

Digamos que eu tenho um diretório /X/Y, que é um repositório git. É possível, de alguma forma, chamar um comando como git pullde dentro /X, mas visando o /X/Ydiretório?

Edição: Eu acho que eu estava pensando especificamente: é possível fazer isso usando o comando a git, mas sem ter que mudar de diretório?

NOTA: Eu aceitei resposta de VonC como é muito mais elegante do que as opções anteriores. Para pessoas executando o Git com mais de 1.8.5, consulte a resposta do bstpierre abaixo .

Gavin Anderegg
fonte
2
Eu gostaria de acrescentar que o uso do git-pull dentro de um gancho não funcionará, a menos que você desative o GIT_DIR. Relevante.
Zpmorgan 28/02/12
Iniciando o git 1.8.5 (Q4 2013), você poderá "usar um comando git, mas sem precisar alterar os diretórios". Veja minha resposta abaixo
VonC:

Respostas:

453

Iniciando o git 1.8.5 (Q4 2013) , você poderá "usar um comando Git, mas sem precisar alterar os diretórios".

Assim como " make -C <directory>", " git -C <directory> ..." diz ao Git para ir lá antes de fazer qualquer outra coisa .

Veja commit 44e1e4 de Nazri Ramliy :

É necessário mais pressionamentos de tecla para chamar o comando Git em um diretório diferente sem sair do diretório atual:

  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

Os métodos mostrados acima são aceitáveis ​​para scripts, mas são muito pesados ​​para chamadas rápidas da linha de comando.

Com esta nova opção, o acima pode ser feito com menos pressionamentos de tecla:

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

Desde o Git 2.3.4 (março de 2015), e o commit 6a536e2 por Karthik Nayak ( KarthikNayak) , git" git -C '<path>'" será tratado como não-op quando <path>estiver vazio.

' git -C ""' morre inutilmente com o erro " Cannot change to ''", enquanto o shell trata o cd "" 'como não operacional.
Tomando o comportamento do shell como um precedente, ensine gita tratar -C "" 'como não operacional também.


4 anos depois, o Git 2.23 (terceiro trimestre de 2019) documenta que ' git -C ""' funciona e não altera o diretório

Está se comportando assim desde 6a536e2 ( git: trate " git -C '<path>'" como um não-op quando <path>estiver vazio, 06-03-2015, Git v2.3.4).

Isso significa que a documentação agora (finalmente) inclui:

Se ' <path>' estiver presente, mas vazio, por exemplo -C "", o diretório de trabalho atual permanecerá inalterado.


Você pode ver git -Cusado com o Git 2.26 (primeiro trimestre de 2020), como exemplo.

Veja commit b441717 , commit 9291e63 , commit 5236fce , commit 10812c2 , commit 62d58cd , commit b87b02c , commit 9b92070 , commit 3595d10 , commit f511bc0 , commit f6041ab , commit f46c243 , commit 99c049b , commit 3738439 , commit 7717242 ( commit 2017) de Denton Liu ( Denton-L) .
(Mesclado por Junio ​​C Hamano - gitster- no commit 381e8e9 , 05 de fevereiro de 2020)

t1507: na linha full_name()

Assinado por: Denton Liu

Antes estávamos correndo test_must_fail full_name. No entanto, test_must_failsó deve ser usado em comandos git.
Inline full_name()para que possamos usar test_must_failo gitcomando diretamente.

Quando full_name()foi introduzida em 28fb84382b ("Introduzir <branch>@{upstream}notação", 10/09/2009, Git v1.7.0-rc0 - mesclagem ), a git -Copção ainda não estava disponível (uma vez que foi introduzida em 44e1e4d67d (" git: executada em um diretório fornecido com opção -C ", 09/09/2013, Git v1.8.5-rc0 - mesclagem listada no lote # 5 )).
Como resultado, a função auxiliar removeu a necessidade de manualmente cdtodas as vezes. No entanto, como git -Cestá disponível agora, podemos apenas usá-lo e inline full_name().

VonC
fonte
6
Uau, legal! Isso é muito mais elegante, então vou marcar como aceito para futuros espectadores.
precisa
1
Não funciona para mim: # git --version && git -C ~ / .m2 / checkout master git versão 1.8.3.4 (Apple Git-47) Opção desconhecida: -C use: git [--version] [--help ] [-c name = value] [--exec-path [= <caminho>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir = <caminho>] [--work-tree = <caminho>] [--namespace = <name> ] <comando> [<arg>]
Jan Galinski 30/01
7
@JanGalinski Mas eu mencionei "Starting git 1.8.5". Portanto, o git 1.8.3.x ainda não sabia sobre essa opção.
VonC 30/01
2
No Ubuntu 12.04, tive que instalar uma versão mais recente do git. Fiz assim: apt-get install software-properties-common python-software-propertiesadicione o repositório git add-apt-repository ppa:git-core/ppa. O último passo é a atualização git: apt-get update && apt-get upgrade.
Ph3nx
54

Editar :

Existe um erro git pullou você não pode fazer o que está tentando fazer com esse comando. No entanto, você pode fazê-lo com busca e mesclagem:

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

Resposta original :

Supondo que você esteja executando o bash ou similar, é possível (cd /X/Y; git pull).

A página de manual do git especifica algumas variáveis ​​(consulte "O Repositório do git") que parecem ajudar, mas não posso fazê-las funcionar corretamente (com o meu repositório em / 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.

Executando o comando abaixo enquanto meu cwd está / tmp atualiza esse repositório, mas o arquivo atualizado aparece em / tmp em vez da árvore de trabalho / tmp / ggg2:

GIT_DIR=/tmp/ggg2/.git git pull

Veja também esta resposta a uma pergunta semelhante , que demonstra os sinalizadores --git-dire --work-tree.

bstpierre
fonte
Você tentou usar apenas GIT_WORK_TREE?
Arrowmaster
@ Arrowmaster: sim, se você fizer isso, o git não poderá encontrar o .gitdiretório.
22611 bstpierre
Ah, certo, a página de manual diz que GIT_WORK_TREE não é usado se GIT_DIR não estiver definido. Parece estranho que não esteja funcionando quando ambos são usados.
Arrowmaster
@Arrowmaster: Eu tenho que saber se há um bug aqui em algum lugar. Se sim git --git-dir=/tmp/ggg2/.git --work-tree=/tmp/ggg2 pull, recebo uma mensagem de erro. Mas se eu fizer isso git --git-dir=/tmp/ggg2/.git --work-tree=. pullenquanto estiver no / tmp, ele colocará os arquivos atualizados no / tmp como deveria.
22611 bstpierre
@ bstpierre: Eu não tenho acesso a um sistema com o git instalado agora, mas se o fizesse, tentaria outras alternativas --work-treeagora --work-tree=/tmp/ggg2/e --work-tree=/tmp/ggg2/.como isso pode ser um problema de como está analisando o caminho.
Arrowmaster
32

Você pode envolvê-lo em um script bash ou alias do git:

cd /X/Y && git pull && cd -
leva
fonte
1
Definitivamente, isso funciona, mas estou pensando se há alguma maneira de usar o comando git sem alterar os diretórios. Estou começando a pensar que não há.
Gavin Anderegg 22/02
1
e use o pushd/popdpar em vez decd/cd-
axd 31/07
Ou você poderia usar um subshell para evitar ter que cd de volta:(cd xyz && git pull)
jarmod
30

Este post é um pouco antigo, então poderia haver um erro e foi corrigido, mas eu fiz isso:

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

E funcionou. Levei um minuto para descobrir que ele queria o dotfile e o diretório pai (em uma configuração padrão, eles sempre são pai / filho, mas não em TODAS as configurações, portanto, eles precisam ser especificados explicitamente.

samtresler
fonte
Eu gosto desta solução, porque ele funciona com diretórios como \\ remotemachine \ C $ \ pasta \ etc
twasbrillig
7

Como alguns de meus servidores estão em versões antigas do Ubuntu LTS, não consigo atualizar facilmente o git para a versão mais recente (que suporta a opção -C, conforme descrito em algumas respostas).

Esse truque funciona bem para mim, principalmente porque não tem o efeito colateral de outras respostas que o deixam em um diretório diferente de onde você começou.

pushd /X/Y
git pull
popd

Ou, fazendo isso como uma linha:

pushd /X/Y; git pull; popd

Tanto o Linux como o Windows possuem comandos pushd e popd.

IvanD
fonte
5

Usando a combinação pushd, git pulle popd, podemos alcançar esta funcionalidade:

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

Por exemplo:

pushd "E:\Fake Directory\gitrepo" && git pull && popd
Raman Sahasi
fonte
isso é incrível. Funciona perfeitamente
Stretch0
4

Você pode escrever um script como este:

cd /X/Y
git pull

Você pode nomear algo como gitpull.
Se você preferir, faça diretórios arbitrários em vez de /X/Y:

cd $1
git pull

Então você pode chamá-lo com gitpull /X/Z
Lastly, você pode tentar encontrar repositórios. Eu tenho uma ~/gitpasta que contém repositórios, e você pode usá-lo para fazer um pull em todos eles.

g=`find /X -name .git`
for repo in ${g[@]}
do
    cd ${repo}
    cd ..
    git pull
done
jonescb
fonte
2
Se você quiser fazê-lo a partir da linha de comando, basta fazê-lo em um subnível: (cd /X/Y && git pull).
Cascabel
2

Para alguém como eu que estava tentando fazer isso através de um comando drush (shell Drupal) em um servidor remoto, você não poderá usar a solução que requer o CD no diretório de trabalho:

Em vez disso, você precisa usar a solução que divide a atração em uma busca e mesclagem:

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
fonte
1

Esse pode ser um problema semelhante, mas você também pode simplesmente encadear seus comandos. por exemplo

Em uma linha

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

Ou via SSH.

ssh [email protected] -t "cd ~/Sites/thedir/web;git pull origin master"
John Ballinger
fonte