Alternar branch Git sem check-out de arquivos


100

É possível no Git mudar para outro branch sem fazer check-out de todos os arquivos?

Depois de alternar o branch, preciso excluir todos os arquivos, gerá-los novamente, confirmar e voltar. Portanto, verificar os arquivos é uma perda de tempo (e existem cerca de 14.000 arquivos - é uma operação longa).

Para deixar tudo claro:

Preciso de tudo isso para carregar a documentação no GitHub.

Eu tenho um repositório com o branch gh-pages . Quando eu reconstruo a documentação localmente, eu a copio para o diretório do repositório, faço commit e envio para GitHub. Mas não fiquei feliz, porque tinha duas cópias da documentação localmente. E decidi criar um branch vazio e depois de fazer commit, mudar para vazio e deletar arquivos. Mas voltar é uma operação longa - por isso fiz esta pergunta.

Sei que posso simplesmente deixar no branch gh-pages e excluir arquivos, mas não gosto de árvores com trabalho sujo.


Quanto tempo é "long" para você? Em qual plataforma você está trabalhando? Você está trabalhando em uma rede como NFS ou outro compartilhamento de arquivos?
Greg Hewgill de

Qual é o objetivo deste exercício? Você quer ter dois branches, um com commits detalhados, o segundo gravando apenas as mudanças principais (grosso)?
Jakub Narębski

Talvez seja mais barato criar um clone temporário (ou permanente?) De sua cópia de trabalho. Minha resposta relacionada e um artigo mostram como isso funciona, mesmo como um subdiretório do repositório principal.
krlmlr

Respostas:


106

Sim, você pode fazer isso.

git symbolic-ref HEAD refs/heads/otherbranch

Se você precisa fazer um commit neste branch, você vai querer redefinir o índice também, caso contrário, você vai acabar cometendo algo baseado no último branch com check-out.

git reset

1
Use echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEADseguido de git resetpara apontar para um ref em vez de uma ramificação.
cadorn

1
Gravar diretamente no arquivo HEAD é menos confiável. E se você estiver em um subdiretório? Para cabeça destacada (cabeça apontando para SHA1 diretamente), tente o seguinte: git update-ref HEAD refs/heads/otherbranch
Alexander Bird

2
Se você quiser fazer check-out de um novo branch do branch atual, outra maneira de fazer isso é 1. git stash2. git checkout -b otherBranch3.git stash pop
Winny

@AlexanderBird: git update-refé útil, mas também move a ponta do branch atual.
tomekwi

47

Usando apenas comandos git básicos:

Essa resposta é um pouco mais longa do que a de Charles, mas consiste apenas em comandos git básicos que posso entender e, portanto, lembrar, eliminando a necessidade de ficar procurando por eles.

Marque sua localização atual (confirme primeiro, se necessário):

git checkout -b temp

Redefina (move) o marcador para o outro ramo sem alterar o diretório de trabalho:

git reset <branch where you want to go>

agora temp e outro branch apontam para o mesmo commit, e seu diretório de trabalho permanece intocado.

git checkout <branch where you want to go>

uma vez que seu HEAD já está apontando para o mesmo commit, o diretório de trabalho não é tocado

git branch -d temp

Observe que esses comandos também estão disponíveis em qualquer cliente gráfico.


7
Eu preferiria git reset --soft <branch where you want to go>evitar a atualização do índice
JoelFan

7
Eu concordo com sua estratégia de evitar os comandos de encanamento git e favorecer os de porcelana.
user64141

26

Na v2.24 git switché algo como um cofre git checkout.
Portanto, mudei o nome do alias abaixo git hoppara
"pular no galho sem alterar a árvore de trabalho"

Para o benefício do leitor:

Embora eu ache que a solução de Charles Bailey seja a correta, essa solução precisa de um ajuste ao mudar para algo que não seja uma filial local. Também deve haver uma maneira de fazer isso com comandos regulares que seja fácil de entender. Aqui está o que eu descobri:

git checkout --detach
git reset --soft commitish
git checkout commitish

Explicado:

  • git checkout --detaché o mesmo git checkout HEAD^{}que deixa o ramo atual para trás e vai para o "estado principal destacado". Portanto, a próxima modificação do HEADno more afeta qualquer branch. A desanexação HEADnão afeta a árvore de trabalho nem o índice.
  • git reset --soft commitishentão se move HEADpara o SHA do dado commitish. Se você quiser atualizar o índice também, pare --soft, mas eu não recomendo fazê-lo. Isso, novamente, não afeta a árvore de trabalho e ( --soft) não o índice.
  • git checkout commitishem seguida, anexa HEADao commitish(ramo) fornecido novamente. (Se commitishfor um SHA, nada acontece.) Isso também não afeta o índice nem a árvore de trabalho.

Esta solução aceita tudo que se refere a um commit, então isso é ideal para alguns gitalias. O que rev-parsesegue é apenas um teste para ter certeza de que nada quebra na cadeia, de forma que erros de digitação não mudem acidentalmente para o estado de cabeça destacado (a recuperação de erros seria muito mais complexa).

Isso leva ao seguinte git hop treeishalias:

git config --global alias.hop '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f'

Para sua informação, você pode encontrá-lo na minha lista de gitapelidos .


Você não quer usar em $@vez de $*? A diferença é que $ @ não expande os argumentos entre aspas, que possuem espaços dentro.
kyb

1
@kyb O truque da função foi roubado de outra resposta do SO . E $@definitivamente não significa aqui. $*é usado em vez de $1, de modo que git switch -f bse torna o mesmo git switch '-f b'que deveria ser um erro. Desta forma, posso encurtar o alias, deixando de lado algum tratamento de erros como!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
Tino

Muito boa solução. Especialmente, que pode ser usado para ramos remotos!
Nils-o-mat

14

Não seria uma solução melhor ter dois diretórios de trabalho (duas áreas de trabalho) com um repositório, ou mesmo dois repositórios?

Há a ferramenta git-new-workdir na contrib/seção para ajudá-lo com isso.


O git-new-workdir é o mesmo que o comando worktree do próprio git? Eu uso o worktree quando quero fazer check-out de um branch em uma pasta diferente (sem ter que clonar todo o repositório).
Ryuu

O git-new-worktreescript é anterior ao git worktreesubcomando; este comando não estava disponível quando a resposta foi escrita. O script, por exemplo, requer suporte de link simbólico; IMHO é melhor usar o suporte nativo.
Jakub Narębski

8

Acho que você está procurando o comando do encanamento git read-tree. Isso atualizará o índice, mas não atualizará nenhum arquivo em seu diretório de trabalho. Por exemplo, supondo que branchseja o nome do ramo a ser lido:

git read-tree branch

Se você quiser se comprometer com o branch que acabou de ler, também precisará:

git symbolic-ref HEAD refs / heads / branch

não, eu só preciso trocar o branch, nenhuma outra mudança - então a referência simbólica é boa o suficiente
tig

read-treegera o erro: fatal: Not a valid object name branchse não houver nenhum git switch branchainda
Andry

7

Você pode substituir seu arquivo HEAD com um nome de branch diferente:

echo "ref: refs / heads / MyOtherBranch"> .git / HEAD


13
Provavelmente é melhor usar o comando symbolic-ref para fazer isso para você: git symbolic-ref HEAD refs/heads/MyOtherBranch kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html
Greg Hewgill

@GregHewgill, esta é a única maneira que conheço de mover o HEAD para um hash de commit. Você pode fazer isso com git symbolic-ref?
tomekwi

0

Com tantos arquivos, talvez seja melhor manter apenas dois repositórios, um para cada branch. Você pode puxar as alterações para frente e para trás conforme necessário. Isso vai ser menos surpreendente do que tentar pregar peças no git.


Você pode usar git-new-worktreepara isso (em contrib/)
Jakub Narębski

Eu sempre fiz algo semelhante, que é copiar meu diretório local antes de fazer qualquer "coisa git assustadora" como um novato (como mudar de branch, etc). Eu encorajaria as pessoas a seguir esse caminho até que você se sinta confiante em seu git-fu, mas se afastar dele quando possível. Manter dois repositórios distintos está ok, mas adiciona uma camada de complicação e não permite que você aproveite os muitos recursos úteis do git (fusão, seleção seletiva, etc).
David

0

Se você está simplesmente tentando mudar para onde um branch remoto aponta, você pode fazer isso com "git push" sem tocar em sua cópia local.

http://kernel.org/pub/software/scm/git/docs/git-push.html

O formato de um parâmetro <refspec> é um plus + opcional, seguido pela fonte ref <src>, seguida por dois pontos:, seguida pela referência de destino <dst>. É usado para especificar com qual objeto <src> o <dst> ref no repositório remoto deve ser atualizado.

por exemplo, para atualizar foo para cometer c5f7eba, faça o seguinte:

git push origin c5f7eba:foo

Não tenho certeza se é isso que você quer ou não.


A pergunta já teve uma resposta: stackoverflow.com/questions/1282639/…
tig

0

você pode fazer uso de

      1. git checkout -f <new-branch>
      2. git cherry-pick -x <previous-branch-commit-id>

previous-branch-commit-id é o commit de onde você deseja copiar os dados antigos.


-1

digamos que você queira estar no ramo A, mas com os arquivos do ramo B

encontre a referência do commit atual do branch A com o log do git, por exemplo, "99ce9a2",

git checkout A
git reset --hard B
git reset 99ce9a2

você agora deve estar na ramificação A, com uma estrutura de pasta correspondente a B, que aparece como alterações não planejadas (um histórico não mudou).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.