Como descartar alterações remotas e marcar um arquivo como "resolvido"?

197

Eu tenho alguns arquivos locais, puxo da ramificação remota e há conflitos. Sei que gostaria de manter minhas alterações locais e ignorar as alterações remotas que causam conflitos. Existe um comando que eu possa usar para dizer "marcar todos os conflitos como resolvidos, usar local"?

Tom DeMille
fonte
1
A resposta abaixo foi super esclarecedora para mim. Existem alguns pontos sutis que realmente esclarecem as coisas para mim, recomendo a usuários não-especialistas do GIT que leiam todos os comentários abaixo do post abaixo e obrigado Brian!
Tom DeMille

Respostas:

332

git checkouttem a --oursopção de verificar a versão do arquivo que você tinha localmente (ao contrário --theirs, que é a versão que você puxou). Você pode passar .para git checkoutpedir para verificar tudo na árvore. Em seguida, é necessário marcar os conflitos como resolvidos, com os quais você pode fazer git adde comprometer seu trabalho assim que terminar:

git checkout --ours .  # checkout our local version of all files
git add -u             # mark all conflicted files as merged
git commit             # commit the merge

Observe .o git checkoutcomando. Isso é muito importante e fácil de perder. git checkouttem dois modos; uma na qual alterna ramificações e outra na qual verifica os arquivos do índice para a cópia de trabalho (algumas vezes, puxando-os para o índice a partir de outra revisão primeiro). A maneira como ele distingue é se você passou um nome de arquivo; se você não passou um nome de arquivo, ele tenta alternar ramificações (embora, se você não passar uma ramificação, apenas tentará verificar a ramificação atual novamente), mas se recusa a fazê-lo se houver arquivos modificados que isso afetaria. Portanto, se você quiser um comportamento que substitua os arquivos existentes, precisará passar .um nome de arquivo ou um nome de arquivo para obter o segundo comportamento git checkout.

Também é um bom hábito ter, ao passar um nome de arquivo, para compensá-lo --, como git checkout --ours -- <filename>. Se você não fizer isso, e o nome do arquivo coincidir com o nome de uma ramificação ou marca, o Git pensará que você deseja verificar essa revisão, em vez de verificar o nome do arquivo, e use a primeira forma do checkoutcomando .

Vou expandir um pouco sobre como os conflitos e a fusão funcionam no Git. Quando você mescla o código de outra pessoa (o que também acontece durante um pull; um pull é essencialmente uma busca seguida por uma mesclagem), há poucas situações possíveis.

O mais simples é que você está na mesma revisão. Nesse caso, você "já está atualizado" e nada acontece.

Outra possibilidade é que a revisão deles seja simplesmente uma descendente sua; nesse caso, você terá, por padrão, uma "mesclagem de avanço rápido", na qual você HEADserá atualizado apenas para o commit deles, sem que ocorra uma fusão (isso pode ser desativado se você realmente deseja gravar uma mesclagem usando --no-ff).

Então você entra nas situações em que você realmente precisa mesclar duas revisões. Nesse caso, existem dois resultados possíveis. Uma é que a mesclagem acontece de maneira limpa; todas as alterações estão em arquivos diferentes ou estão nos mesmos arquivos, mas suficientemente afastadas para que ambos os conjuntos de alterações possam ser aplicados sem problemas. Por padrão, quando uma mesclagem limpa acontece, ela é automaticamente confirmada, embora você possa desativá-la --no-commitse precisar editá-la antecipadamente (por exemplo, se você renomear a função foopara bare outra pessoa adicionar um novo código que chama foo, ela será mesclada corretamente , mas produza uma árvore quebrada; portanto, você pode limpá-la como parte do commit de mesclagem para evitar que haja comprometimentos).

A possibilidade final é que haja uma verdadeira fusão e que haja conflitos. Neste caso, o Git fará tanto da fusão, uma vez que pode, e arquivos de produzir com marcadores de conflito ( <<<<<<<, =======e >>>>>>>) em sua cópia de trabalho. No índice (também conhecido como "área de preparação"; o local em que os arquivos são armazenados git addantes de enviá-los), você terá 3 versões de cada arquivo com conflitos; existe a versão original do arquivo do ancestral dos dois ramos que você está mesclando, a versão de HEAD(seu lado da mesclagem) e a versão do ramo remoto.

Para resolver o conflito, você pode editar o arquivo que está na sua cópia de trabalho, removendo os marcadores de conflito e corrigindo o código para que funcione. Ou, você pode conferir a versão de um ou dos outros lados da mesclagem, usando git checkout --oursou git checkout --theirs. Depois de colocar o arquivo no estado desejado, você indica que terminou de mesclar o arquivo e está pronto para confirmar o uso git add, e então pode confirmar a mesclagem git commit.

Brian Campbell
fonte
7
Você provavelmente deve observar que git add --alladiciona todos os arquivos ao repositório, portanto, isso pode adicionar mais arquivos do que o pretendido, a menos que seus .gitignorepadrões estejam em um estado perfeito. git add -uprovavelmente é mais adequado para essa situação, é menos provável que você edite os arquivos rastreados que não deseja adicionar ao resolver uma mesclagem.
CB Bailey
OPA, desculpe. Foi isso que eu quis dizer. Corrigido agora.
Brian Campbell
1
obrigado pela sua resposta detalhada. Na verdade, tentei o git checkout --ours e recebi uma mensagem de erro (que não me lembro agora). Os arquivos em questão são dll (temos alguns que escondemos, principalmente referências de terceiros) e eu queria apenas dizer 'ok, minha cópia é a que eu quero, mas o erro foi algo como' não é possível fazer checkout durante a mesclagem ' ..... Vou manter este artigo como referência e da próxima vez que tentar, tente novamente e veja se funciona ou se posso postar essa mensagem. Obrigado novamente
Tom DeMille
mas sua explicação me esclarece muito sobre o processo, obrigado novamente ... Pergunta de acompanhamento: Alguma maneira de o git excluir os arquivos .orig depois que a mesclagem for resolvida?
Tom DeMille
2
Você precisa fazer git checkout --ours .. O .é importante; passar um nome de arquivo (nesse caso, o diretório inteiro) seleciona entre dois modos diferentes de operação de checkout, um que alterna ramificações e outro que move arquivos do índice para a cópia de trabalho. Eu concordo, é muito confuso. Você também pode fazer um git checkout --ours -- <filename>check-out de um arquivo individual por vez.
Brian Campbell
23

Verifique a origem do conflito: se é o resultado de a git merge, consulte a resposta de Brian Campbell .

Mas se é o resultado de a git rebase, para descartar alterações remotas (deles) e usar alterações locais , você teria que fazer um:

git checkout --theirs -- .

Consulte " Por que é o significado de‘ ours’e‘ theirs’revertida" "para ver como ourse theirssão trocados durante uma rebase (porque o montante ramo é check-out).

VonC
fonte