git reset
é tudo sobre mudança HEAD
, e geralmente o ramo ref .
Pergunta: e a árvore de trabalho e o índice?
Quando empregado com --soft
, move HEAD
, na maioria das vezes atualizando o ramo ref, e somente oHEAD
.
Isso difere de commit --amend
:
- não cria um novo commit.
- na verdade, ele pode mover HEAD para qualquer confirmação (como
commit --amend
é apenas não mover HEAD, enquanto permite refazer a confirmação atual)
Acabei de encontrar este exemplo de combinação:
- uma fusão clássica
- uma mesclagem de subárvore
tudo em um (polvo, pois há mais de dois ramos mesclados) confirma a mesclagem.
Tomas "wereHamster" Carnecky explica em seu artigo "Subtree Octopus merge" :
- A estratégia de mesclagem de subárvore pode ser usada se você deseja mesclar um projeto em um subdiretório de outro projeto e, posteriormente, manter o subprojeto atualizado. É uma alternativa aos submódulos git.
- A estratégia de mesclagem de polvo pode ser usada para mesclar três ou mais ramificações. A estratégia normal pode mesclar apenas dois ramos e, se você tentar mesclar mais do que isso, o git volta automaticamente à estratégia do polvo.
O problema é que você pode escolher apenas uma estratégia. Mas eu queria combinar os dois para obter um histórico limpo, no qual todo o repositório seja atualizado atomicamente para uma nova versão.
Eu tenho um superprojeto, vamos chamá-lo projectA
e um subprojeto projectB
, que eu mesclei em um subdiretório de projectA
.
(essa é a parte de mesclagem da subárvore)
Também estou mantendo alguns commits locais.
ProjectA
é atualizado regularmente, projectB
tem uma nova versão a cada dois dias ou semanas e geralmente depende de uma versão específica do projectA
.
Quando eu decido atualizar os dois projetos, eu simplesmente não extrao projectA
e, projectB
como isso criaria dois commits para o que deveria ser uma atualização atômica de todo o projeto .
Em vez disso, eu criar um único merge comprometer que combina projectA
, projectB
e meus commits locais .
A parte complicada aqui é que essa é uma mesclagem de polvo (três cabeças), mas projectB
precisa ser mesclada com a estratégia da subárvore . Então é isso que eu faço:
# Merge projectA with the default strategy:
git merge projectA/master
# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master
Aqui, o autor usou ae reset --hard
, em seguida, read-tree
para restaurar o que as duas primeiras mesclagens fizeram na árvore e no índice de trabalho, mas é aí que reset --soft
pode ajudar:
Como refazer essas duas mesclagens que funcionaram, ou seja, minha árvore de trabalho e índice são tudo bem, mas sem ter que gravar esses dois commits?
# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}
Agora, podemos retomar a solução de Tomas:
# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD
# And finally do the commit:
git commit
Então, cada vez:
- você está satisfeito com o que termina (em termos de árvore de trabalho e índice)
- você não está satisfeito com todos os commits que levaram para chegar lá:
git reset --soft
é a resposta.
git reset --soft
: stackoverflow.com/questions/6869705/…Caso de Uso - Combine uma série de confirmações locais
"Opa. Esses três commits podem ser apenas um."
Portanto, desfaça os últimos 3 (ou qualquer outro) commit (sem afetar o índice nem o diretório de trabalho). Em seguida, confirme todas as alterações como uma.
Por exemplo
Agora todas as suas alterações estão preservadas e prontas para serem confirmadas como uma só.
Respostas curtas para suas perguntas
Esses dois comandos são realmente os mesmos (
reset --soft
vscommit --amend
)?Algum motivo para usar um ou outro em termos práticos?
commit --amend
adicionar / rm arquivos desde a última confirmação ou alterar sua mensagem.reset --soft <commit>
para combinar várias confirmações seqüenciais em uma nova.E, mais importante, existem outros usos
reset --soft
além de alterar um commit?fonte
reset --soft
além de alterar um commit - Não"git reset
) são boas quando você (a) deseja reescrever a história, (b) não se preocupa com os commits antigos (para evitar a confusão de rebase interativa) e (c) tem mais de um comprometimento para alterar (caso contrário,commit --amend
é mais simples).Eu o uso para alterar mais do que apenas o último commit.
Digamos que eu cometi um erro ao confirmar A e depois cometi o B. Agora, só posso alterar o B. Assim faço
git reset --soft HEAD^^
, corrigo e re-confirmo A e, em seguida, re-confirmo B.Claro, não é muito conveniente para grandes confirmações ... mas você não deve fazer grandes confirmações de qualquer maneira ;-)
fonte
git commit --fixup HEAD^^
git rebase --autosquash HEAD~X
funciona bem também.git rebase --interactive HEAD^^
onde você escolhe editar as confirmações A e B. Dessa forma, mantém as mensagens de confirmação de A e B; se necessário, você também pode modificá-las.git reset A
, fazer e adicionar alterações,git commit --amend
,git cherry-pick <B-commit-hash>
.Outro uso potencial é como uma alternativa ao armazenamento em cache (do qual algumas pessoas não gostam, consulte, por exemplo, https://codingkilledthecat.wordpress.com/2012/04/27/git-stash-pop-considered-harmful/ ).
Por exemplo, se estou trabalhando em uma ramificação e preciso corrigir algo com urgência no mestre, posso fazer:
depois faça o checkout master e faça a correção. Quando termino, volto ao meu ramo e faço
para continuar trabalhando de onde parei.
fonte
--soft
é realmente desnecessário aqui, a menos que você realmente se importe com a possibilidade de realizar as alterações imediatamente. Agora eu apenas usogit reset HEAD~
ao fazer isso. Se eu tiver algumas alterações preparadas quando preciso alternar ramificações, e quiser mantê-las dessa maneira, então eu façogit commit -m "staged changes"
, entãogit commit -am "unstaged changes"
, mais tardegit reset HEAD~
seguidas porgit reset --soft HEAD~
para restaurar completamente o estado de trabalho. Embora, para ser honesto eu fazer ambas as coisas muito menos agora que eu sei sobregit-worktree
:)Você pode usar
git reset --soft
para alterar a versão que deseja ter como pai das alterações que você possui no seu índice e na árvore de trabalho. Os casos em que isso é útil são raros. Às vezes, você pode decidir que as alterações que você tem na sua árvore de trabalho devem pertencer a um ramo diferente. Ou você pode usar isso como uma maneira simples de recolher vários commits em um (semelhante ao squash / fold).Veja esta resposta de VonC para um exemplo prático: Squash os dois primeiros commits no Git?
fonte
git reset --soft anotherBranch
e depois comprometo lá? Mas você realmente não muda o ramo ckeckout, então se comprometerá com o Branch ou com o outroBranch ?Um uso possível seria quando você deseja continuar seu trabalho em uma máquina diferente. Funcionaria assim:
Faça check-out de uma nova ramificação com um nome semelhante a stash,
Empurre seu galho para cima,
Mude para a sua outra máquina.
Puxe para baixo o seu estoque e os galhos existentes,
Você deve estar em sua filial existente agora. Mesclar as alterações do ramo stash,
Redefina manualmente sua ramificação existente para 1 antes da mesclagem,
Remova o seu esconderijo,
Remova também seu ramo stash da origem,
Continue trabalhando com suas alterações como se você as tivesse ocultado normalmente.
Eu acho que, no futuro, GitHub e companhia. deve oferecer essa funcionalidade de "esconderijo remoto" em menos etapas.
fonte
Um uso prático é se você já se comprometeu com seu repo local (por exemplo, git commit -m), então você pode reverter esse último commit, executando git reset --soft HEAD ~ 1
Também para o seu conhecimento, se você já organizou suas alterações (ou seja, com o git add.), Pode reverter o estadiamento fazendo git reset --misted HEAD ou geralmente também apenas usei
git reset
por fim, o git reset --hard limpa tudo, incluindo as alterações locais. O cabeçalho ~ after diz a você quantos commits devem ir do topo.
fonte
git reset --soft HEAD ~1
dá-mefatal: Cannot do soft reset with paths.
eu acho que nós precisamos remover o espaço após a cabeça de modo que seriagit reset --soft HEAD~1
Um ótimo motivo para usar '
git reset --soft <sha1>
' é mover-seHEAD
em um repositório simples.Se você tentar usar a opção
--mixed
ou--hard
, receberá um erro, pois está tentando modificar e trabalhar em árvore e / ou índice que não existe.Nota: você precisará fazer isso diretamente do repositório simples.
Nota novamente: você precisará garantir que a ramificação que deseja redefinir no repositório simples seja a ramificação ativa. Caso contrário, siga a resposta do VonC sobre como atualizar a ramificação ativa em um repo bare quando você tiver acesso direto ao repo.
fonte
O SourceTree é uma GUI do git, que possui uma interface bastante conveniente para preparar apenas os bits que você deseja. Não possui nada remotamente semelhante para alterar uma revisão adequada.
Portanto,
git reset --soft HEAD~1
é muito mais útil do quecommit --amend
neste cenário. Posso desfazer a confirmação, recuperar todas as alterações na área de preparação e continuar ajustando os bits em etapas usando o SourceTree.Realmente, parece-me que
commit --amend
é o comando mais redundante dos dois, mas o git é git e não se esquiva de comandos semelhantes que fazem coisas ligeiramente diferentes.fonte
Embora eu realmente goste das respostas neste tópico, eu uso
git reset --soft
para um cenário um pouco diferente, mas muito prático, no entanto.Eu uso um IDE para desenvolvimento, que tem uma boa ferramenta diff para mostrar alterações (em etapas e em etapas) após a minha última confirmação. Agora, a maioria das minhas tarefas envolve várias confirmações. Por exemplo, digamos que eu faça 5 confirmações para concluir uma tarefa específica. Eu uso a ferramenta diff no IDE durante cada confirmação incremental de 1 a 5 para examinar minhas alterações desde a última confirmação. Acho uma maneira muito útil de revisar minhas alterações antes de confirmar.
Mas no final da minha tarefa, quando eu quero ver todas as minhas alterações juntas (desde antes do 1º commit), para fazer uma auto-revisão de código antes de fazer uma solicitação pull, eu só veria as alterações do commit anterior (após o commit 4) e não alterações de todos os commits da minha tarefa atual.
Então, eu uso
git reset --soft HEAD~4
para voltar 4 commits. Isso me permite ver todas as alterações juntas. Quando estou confiante em minhas alterações, posso fazergit reset HEAD@{1}
e enviá-lo para o controle remoto com confiança.fonte
git add --patch
egit commit
crie repetidamente a série de consolidação que você teria construído se soubesse o que estava fazendo o tempo todo. Seus primeiros commits são como as anotações em sua mesa ou o primeiro rascunho de um memorando, eles estão lá para organizar seu pensamento, não para publicação.git reset @{1}
restaurar sua série de primeiro rascunho, você pode criar uma série para publicação a partir degit add -p
egit commit
.Outro caso de uso é quando você deseja substituir a outra ramificação pela sua em uma solicitação pull, por exemplo, digamos que você tenha um software com os recursos A, B, C em desenvolvimento.
Você está desenvolvendo com a próxima versão e você:
Recurso removido B
Adicionado recurso D
No processo, desenvolva apenas hotfixes adicionados ao recurso B.
Você pode mesclar o desenvolvimento para o próximo, mas às vezes isso pode ser confuso, mas também é possível usar
git reset --soft origin/develop
e criar uma confirmação com suas alterações, e a ramificação é mesclável sem conflitos e mantém as alterações.Acontece que
git reset --soft
é um comando útil. Pessoalmente, eu o uso muito para compactar confirmações que não "concluíram o trabalho" como "WIP"; portanto, quando abro a solicitação de recebimento, todas as confirmações são compreensíveis.fonte