Redefina a ramificação do repositório local para ser como o repositório remoto HEAD

3858

Como redefinir minha ramificação local para ser exatamente como a ramificação no repositório remoto?

Eu fiz:

git reset --hard HEAD

Mas quando eu corro um git status,

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
      modified:   java/com/mycompany/TestContacts.java
      modified:   java/com/mycompany/TestParser.java

Você pode me dizer por que eu tenho esses 'modificados'? Não toquei nesses arquivos? Se sim, quero removê-los.

hap497
fonte
8
De acordo com a saída do git statusseu segundo comando git reset --hard HEADfalhou. Você não colou sua saída, no entanto. → Pergunta incompleta.
Robert Siemer
2
Você está misturando dois problemas aqui: 1) como redefinir uma ramificação local para o ponto em que o controle remoto está e 2) como limpar sua área de armazenamento temporário (e possivelmente o diretório de trabalho), como git statusdiz o texto nothing to commit, working directory clean. - Por favor especifique!
Robert Siemer

Respostas:

6699

A configuração da ramificação para corresponder exatamente à ramificação remota pode ser feita em duas etapas:

git fetch origin
git reset --hard origin/master

Se você deseja salvar o estado atual de sua filial antes de fazer isso (apenas no caso), você pode:

git commit -a -m "Saving my work, just in case"
git branch my-saved-work

Agora, seu trabalho é salvo na ramificação "meu trabalho salvo", caso você decida que deseja devolvê-lo (ou deseje vê-lo mais tarde ou diferenciá-lo em seu ramo atualizado).

Observe que o primeiro exemplo pressupõe que o nome do repositório remoto seja "origem" e que a ramificação denominada "mestre" no repositório remoto corresponda ao ramo atualmente com check-out no repositório local.

BTW, essa situação em que você se parece parece muito com um caso comum em que um push foi feito na ramificação com check-out atualmente de um repositório não nu. Você entrou recentemente no seu repositório local? Caso contrário, não se preocupe - outra coisa deve ter causado esses arquivos inesperadamente serem modificados. Caso contrário, você deve estar ciente de que não é recomendável enviar para um repositório não nu (e não para a ramificação com check-out atualmente, em particular).

Dan Moulding
fonte
4
Obrigado pela sua resposta. Você disse: 'Observe que o primeiro exemplo assume que o nome do repositório remoto é "origem" e que a ramificação denominada "mestre" no repositório remoto corresponde à ramificação no repositório local. Como posso verificar o nome do repositório remoto e o nome do meu ramo para ter certeza antes de executar 'git reset --hard'? Obrigado novamente.
hap497
21
Se você não nomeou explicitamente o controle remoto, é provável que o nome seja apenas "origem" (o padrão). Você pode usar "git remote" para obter uma lista de todos os nomes remotos. Você pode usar o "git remote <name>" para ver quais ramificações são pressionadas entre si (por exemplo, se sua ramificação "master" foi clonada de "master" no controle remoto chamado "origin", você receberá uma linha que diz "mestre se funde com mestre remoto").
10269 Dan Molding
6
"Não é recomendado para empurrar em um repositório non-bare (e não para o ramo atualmente check-out, em particular" Por que isso?
LeeGee
27
Logo após a busca, acredito que você também pode fazer git reset FETCH_HEAD --hardo mesmo significado.
Jean
6
Não removeu os arquivos que adicionei.
Trismegistos
416

Eu precisava fazer (a solução na resposta aceita):

git fetch origin
git reset --hard origin/master

Seguido por:

git clean -f

remover arquivos locais

Para ver quais arquivos serão removidos (sem realmente removê-los):

git clean -n -f
Akavall
fonte
89
Além disso, git clean -d -fse houver diretórios não rastreados presentes.
garg
54
tambémgit clean -fdx
Swapnil Kotwal
14
Se você deseja uma cópia exata da ramificação remota, siga o git clean -ffdx. Observe que são dois f.
Trismegistos
6
O git clean -ffoi a peça fundamental que eu precisava. Obrigado!
DGO
17
tenha cuidado usando o comando clean. ele pode excluir arquivos ignorados de outros ramos.
Mikoop
307

Primeiro, redefina para o anteriormente buscado HEADdo ramo upstream correspondente:

git reset --hard @{u}

A vantagem de especificar @{u}ou sua forma detalhada @{upstream}é que o nome do repositório remoto e da ramificação não precisa ser especificado explicitamente.

Em seguida, conforme necessário, remova arquivos não rastreados, opcionalmente também com -x:

git clean -df

Por fim, conforme necessário, obtenha as alterações mais recentes:

git pull
Acumenus
fonte
54
Esta parece ser uma resposta melhor do que a aceita, porque dinamicamente retorna para o ramo a montante atual ao invés de sempre a estática alguém comoorigin/master
Jon z
@ Jonz local, o @{upstream}é muito útil e pode ser usado em aliases: #alias resetthisbranch="git reset --hard @{upstream}"
Siddhartha
1
@GangadharJannu git reset --hardrequer uma confirmação, caso contrário, não saberia para o que redefinir você. @{u}aponta para um commit específico - o chefe do ramo rastreado, desde a última vez que você fez um git fetch.
Kristoffer Bakkejord 16/10/19
1
Graças @KristofferBakkejord para a explicação, mas mesmo sem cometer hash de que podemos fazer git reset --hardque ele não irá repor a filial remota
Gangadhar Jannu
3
Para qualquer pessoa que quase tenha aberto uma nova pergunta aqui, se você for do Powershell, use aspas ( git reset --hard "@{u}"). Levei um tempo para descobrir isso.
MPStoering
112

git reset --hard HEADna verdade, apenas redefine para o último estado confirmado. Nesse caso, HEAD refere-se ao HEAD do seu ramo.

Se você tiver vários commits, isso não funcionará ..

O que você provavelmente deseja fazer é redefinir a cabeça de origem ou o nome do repositório remoto. Eu provavelmente faria apenas algo como

git reset --hard origin/HEAD

Tenha cuidado, porém. As redefinições rígidas não podem ser desfeitas com facilidade. É melhor fazer o que Dan sugere e ramificar uma cópia de suas alterações antes de redefinir.

Mikael Ohlson
fonte
2
Houve uma sugestão incorreta na minha resposta que Dan pegou antes. Eu o editei, pois não quero desviar ninguém. Quanto ao material origin / master ou origin / HEAD, espero que isso dependa de você fazer ou não uma busca primeiro. Se você acabou de clonar a origem e ela não tinha outros ramos, o que eu acho bastante comum, deve redefinir tudo. Mas é claro que Dan está certo.
Mikael Ohlson
73

Todas as sugestões acima estão corretas, mas muitas vezes para realmente redefinir seu projeto, você também precisa remover os arquivos que estão no seu .gitignore.

Para obter o equivalente moral de apagar o diretório do projeto e clonar novamente a partir do controle remoto é:

git fetch
git reset --hard
git clean -x -d -f

Aviso : git clean -x -d -fé irreversível e você pode perder arquivos e dados (por exemplo, coisas que você ignorou .gitignore).

Christopher Smith
fonte
12
Aviso: "git limpo -x -d -f" é irreversível e você pode perder arquivos e dados em .gitignore
Akarsh Satija
Um pouco mais curto: git clean -xdfisso é igual a git clean -x -d -f.
Kiryl
git clean -ffxd para remover tudo o que não está no repositório #
Trismegistos
44

Use os comandos abaixo. Esses comandos também removerão todos os arquivos não rastreados do git local

git fetch origin
git reset --hard origin/master
git clean -d -f
Jamsheer
fonte
6
Esta é uma resposta mais completa, porque sem o git clean -d -fainda teremos algumas coisas da ramificação antiga no diretório local. Obrigado cara.
Flavio
3
Isso é o que realmente faz com que seja exatamente como o controle remoto. A limpeza é importante.
David S.
1
git clean -ffxd para realmente remover tudo #
Trismegistos
1
Isso é exatamente o que eu precisava. Obrigado
AllJs
38

A questão combina duas questões aqui:

  1. como redefinir uma filial local para o ponto em que o controle remoto está
  2. como limpar sua área de seleção (e, possivelmente, o diretório de trabalho), para que git statusdiznothing to commit, working directory clean.

A resposta completa é:

  1. git fetch --prune (opcional) Atualiza a captura instantânea local do repositório remoto. Comandos adicionais são apenas locais.
    git reset --hard @{upstream}Coloca o ponteiro local da ramificação onde está o instantâneo do controle remoto, além de definir o índice e o diretório de trabalho nos arquivos dessa confirmação.
  2. git clean -d --force Remove arquivos e diretórios não rastreados que impedem o git de dizer "diretório de trabalho limpo".
Robert Siemer
fonte
1
A @{upstream}sintaxe exige que o upstream seja definido, o que acontece por padrão se você git checkout <branchname>. - Caso contrário, substitua-o por origin/<branchname>.
Robert Siemer
Adicione -xpara git cleanremover tudo o que não está no commit (ou seja, mesmo arquivos ignorados com o mecanismo .gitignore).
Robert Siemer 31/01
22

Isso é algo que enfrento regularmente, e generalizei o script que Wolfgang forneceu acima para trabalhar com qualquer ramo

Também adicionei um prompt "você tem certeza" e alguma saída de feedback

#!/bin/bash
# reset the current repository
# WF 2012-10-15
# AT 2012-11-09
# see http://stackoverflow.com/questions/1628088/how-to-reset-my-local-repository-to-be-just-like-the-remote-repository-head
timestamp=`date "+%Y-%m-%d-%H_%M_%S"`
branchname=`git rev-parse --symbolic-full-name --abbrev-ref HEAD`
read -p "Reset branch $branchname to origin (y/n)? "
[ "$REPLY" != "y" ] || 
echo "about to auto-commit any changes"
git commit -a -m "auto commit at $timestamp"
if [ $? -eq 0 ]
then
  echo "Creating backup auto-save branch: auto-save-$branchname-at-$timestamp"
  git branch "auto-save-$branchname-at-$timestamp" 
fi
echo "now resetting to origin/$branchname"
git fetch origin
git reset --hard origin/$branchname
Andrew Tulloch
fonte
3
convém usar "git remote" para obter o nome do controle remoto. Em certos casos, não será "origem"
Yurik 07/10
17

Desde que o repositório remoto seja origine você esteja interessado em branch_name:

git fetch origin
git reset --hard origin/<branch_name>

Além disso, você redefine a ramificação atual de originpara HEAD.

git fetch origin
git reset --hard origin/HEAD

Como funciona:

git fetch origin baixa a versão mais recente do controle remoto sem tentar mesclar ou refazer nada.

Em seguida, git resetredefine o <branch_name>ramo para o que você acabou de buscar. A --hardopção altera todos os arquivos da sua árvore de trabalho para corresponder aos arquivos origin/branch_name.

eigenharsha
fonte
14

Eu fiz:

git branch -D master
git checkout master

redefinir totalmente ramificação


Observe que você deve fazer o checkout para outro ramo para poder excluir o ramo necessário

user2846569
fonte
5
Você deve ler a pergunta mais uma vez, não há nada sobre afetar o controle remoto, mas definir o mesmo que o controle remoto; portanto, você não deve fazer nada com o controle remoto, e isso ajudou no meu caso e não acima.
User2846569
Se você deseja configurá-lo para o mesmo que remoto, você deve pelo menos fazer uma busca em algum momento, não concorda?
Tim
2
você deve pelo menos tentar isso ou ler documentos: kernel.org/pub/software/scm/git/docs/git-checkout.html
user2846569
Caminho a percorrer, eu tinha um arquivo .pck corrompido no ramo e o restante das opções não funcionou, obrigado !!
LuckyBrain
14

Aqui está um script que automatiza o que a resposta mais popular sugere ... Consulte https://stackoverflow.com/a/13308579/1497139 para obter uma versão melhorada que suporta ramificações

#!/bin/bash
# reset the current repository
# WF 2012-10-15
# see /programming/1628088/how-to-reset-my-local-repository-to-be-just-like-the-remote-repository-head
timestamp=`date "+%Y-%m-%d-%H_%M_%S"`
git commit -a -m "auto commit at $timestamp"
if [ $? -eq 0 ]
then
  git branch "auto-save-at-$timestamp" 
fi
git fetch origin
git reset --hard origin/master
Wolfgang Fahl
fonte
10

Se você teve um problema como eu, que já cometeu algumas alterações, mas agora, por qualquer motivo, deseja se livrar dele, a maneira mais rápida é usar o git resetseguinte:

git reset --hard HEAD~2

Eu tinha 2 confirmações não necessárias, daí o número 2. Você pode alterá-lo para o seu próprio número de confirmações para redefinir.

Portanto, respondendo à sua pergunta - se você tiver 5 confirmações à frente do repositório remoto HEAD, execute este comando:

git reset --hard HEAD~5

Observe que você perderá as alterações feitas, portanto, tenha cuidado!

Karol
fonte
7

As respostas anteriores assumem que o ramo a ser redefinido é o ramo atual (com check-out). Nos comentários, o OP hap497 esclareceu que o ramo está realmente com check-out, mas isso não é explicitamente exigido pela pergunta original. Como há pelo menos uma pergunta "duplicada", redefinir a ramificação completamente para o estado do repositório , o que não pressupõe que a ramificação tenha sido retirada, eis uma alternativa:

Se a ramificação "mybranch" não estiver com check-out no momento, para redefini-la para a cabeça remota da ramificação "myremote / mybranch", você poderá usar este comando de baixo nível :

git update-ref refs/heads/mybranch myremote/mybranch

Esse método deixa o ramo com check-out como está e a árvore de trabalho intocada. Ele simplesmente move a cabeça de mybranch para outro commit, seja qual for o segundo argumento. Isso é especialmente útil se várias ramificações precisarem ser atualizadas para novas cabeças remotas.

Entretanto, tenha cuidado ao fazer isso e use gitkuma ferramenta semelhante para verificar novamente a origem e o destino. Se você fizer isso acidentalmente na ramificação atual (e o git não o impedir), você poderá ficar confuso, porque o novo conteúdo da ramificação não corresponde à árvore de trabalho, que não foi alterada (para corrigir, atualizar a ramificação novamente, para onde estava antes).

Rainer Blome
fonte
7

Isto é o que eu uso frequentemente:

git fetch upstream develop;
git reset --hard upstream/develop;
git clean -d --force;

Note-se que é uma boa prática para não fazer alterações ao seu mestre local / desenvolver ramo, mas em vez de checkout para outro ramo para qualquer mudança, com o nome de filial prefixado pelo tipo de mudança, por exemplo feat/, chore/, fix/, etc. Assim, você só precisa puxe as alterações, não envie nenhuma alteração do mestre. O mesmo vale para outros ramos com os quais outros contribuem. Portanto, o descrito acima só deve ser usado se você confirmar alterações em um ramo em que outros se comprometeram e precisar redefinir. Caso contrário, no futuro, evite enviar para um ramo para o qual outros enviam, em vez disso, faça o checkout e envie para o referido ramo por meio do ramo com check-out.

Se você deseja redefinir sua filial local para a confirmação mais recente na filial upstream, o que funciona para mim até agora é:

Verifique seus controles remotos, verifique se o upstream e a origem são o que você espera, se não como o esperado, use git remote add upstream <insert URL>, por exemplo, o repositório original do GitHub do qual você retirou e / ou git remote add origin <insert URL of the forked GitHub repo>.

git remote --verbose

git checkout develop;
git commit -m "Saving work.";
git branch saved-work;
git fetch upstream develop;
git reset --hard upstream/develop;
git clean -d --force

No GitHub, você também pode fazer checkout da ramificação com o mesmo nome da local, para salvar o trabalho lá, embora isso não seja necessário se o desenvolvimento da origem tiver as mesmas alterações que a ramificação local de trabalho salvo. Estou usando o ramo de desenvolvimento como exemplo, mas pode ser qualquer nome de ramo existente.

git add .
git commit -m "Reset to upstream/develop"
git push --force origin develop

Então, se você precisar mesclar essas alterações com outra ramificação enquanto houver conflitos, preservando as alterações no desenvolvimento, use:

git merge -s recursive -X theirs develop

Enquanto uso

git merge -s recursive -X ours develop

para preservar as alterações conflitantes de branch_name. Caso contrário, use uma ferramenta de fusão com git mergetool.

Com todas as mudanças juntas:

git commit -m "Saving work.";
git branch saved-work;
git checkout develop;
git fetch upstream develop;
git reset --hard upstream/develop;
git clean -d --force;
git add .;
git commit -m "Reset to upstream/develop";
git push --force origin develop;
git checkout branch_name;
git merge develop;

Observe que, em vez de fazer upstream / desenvolvimento, você pode usar um hash de confirmação, outro nome de filial, etc. Use uma ferramenta CLI como Oh My Zsh para verificar se sua ramificação está verde, indicando que não há nada a confirmar e se o diretório de trabalho está limpo ( que é confirmado ou também verificável por git status). Observe que isso pode realmente adicionar commits comparação para montante desenvolver se houver qualquer coisa adicionado automaticamente por um cometa, por exemplo, diagramas UML, cabeçalhos de licença, etc., então, nesse caso, você poderia, então, puxar as mudanças em origin developque upstream develop, se necessário.

James Ray
fonte
6

A resposta

git clean -d -f

foi subestimado ( -d para remover diretórios). Obrigado!

Anael
fonte
E para uma pasta de repositório completa, 100% limpa, sem arquivos extras, execute git clean -xdf. Isso excluirá todos os arquivos que o git não está ciente e fará com que sua pasta corresponda exatamente ao que está na lista de objetos do git. Observe que você pode adicionar -n(por exemplo git clean -nxdf) para executar um "what-if" e ele informará o que será excluído sem realmente fazer nada. ( git clean )
qJake
5

Se você deseja voltar ao HEADestado para o diretório ativo e o índice, deve git reset --hard HEAD, em vez de fazê-lo HEAD^. (Isso pode ter sido um erro de digitação, assim como o traço único versus o duplo --hard).

Quanto à sua pergunta específica sobre por que esses arquivos aparecem no status modificado, parece que talvez você tenha feito uma reinicialização suave em vez de uma reinicialização completa. Isso fará com que os arquivos que foram alterados no HEADcommit apareçam como se estivessem preparados, o que provavelmente é o que você está vendo aqui.

Emil Sit
fonte
4

Nenhuma quantidade de redefinição e limpeza pareceu afetar os arquivos não rastreados e modificados no meu repositório git local (tentei todas as opções acima). Minha única solução para isso foi rm o repositório local e cloná-lo novamente do controle remoto.

Felizmente eu não tinha nenhum outro ramo com o qual eu me importasse.

xkcd: Git

Martin
fonte
1

A única solução que funciona em todos os casos que eu vi é excluir e reclinar. Talvez exista outra maneira, mas, obviamente, dessa maneira não deixa chance de estado antigo ser deixado lá, então eu prefiro. Bash one-liner que você pode definir como macro se você costuma bagunçar tudo no git:

REPO_PATH=$(pwd) && GIT_URL=$(git config --get remote.origin.url) && cd .. && rm -rf $REPO_PATH && git clone --recursive $GIT_URL $REPO_PATH && cd $REPO_PATH

* assume que seus arquivos .git não estão corrompidos

sudo
fonte
4
você também pode apenas reinstalar o sistema operacional se quiser ter certeza!
Sebastian Scholle
1

Você esqueceu de criar um ramo de recursos e se comprometeu diretamente com o mestre por engano?

Você pode criar a ramificação de recursos agora e restaurar o mestre sem afetar a árvore de trabalho (sistema de arquivos local) para evitar o desencadeamento de compilações, testes e problemas com bloqueios de arquivos:

git checkout -b feature-branch
git branch -f master origin/master
Grastveit
fonte
1

Apenas 3 comandos farão funcionar

git fetch origin
git reset --hard origin/HEAD
git clean -f
Deep Nirmal
fonte
-3

Se você não se importa em salvar suas alterações locais, ainda assim deseja atualizar seu repositório para corresponder à origem / HEAD, basta ocultar suas alterações locais e, em seguida, puxar:

git stash
git pull
Micah Walter
fonte