O que você quer fazer é altamente perturbador se você tiver publicado o histórico para outros desenvolvedores. Consulte "Recuperando da Rebase Upstream" na git rebase
documentação para obter as etapas necessárias após reparar seu histórico.
Você tem pelo menos duas opções: git filter-branch
e um rebase interativo, ambos explicados abaixo.
Usando git filter-branch
Eu tive um problema semelhante com dados volumosos de teste binário de uma importação do Subversion e escrevi sobre a remoção de dados de um repositório git .
Digamos que seu histórico do git seja:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Observe que git lola
é um alias não padrão, mas altamente útil. Com a --name-status
opção, podemos ver modificações na árvore associadas a cada confirmação.
No commit "descuidado" (cujo nome do objeto SHA1 é ce36c98), o arquivo oops.iso
é o rasgo do DVD adicionado por acidente e removido no próximo commit, cb14efd. Usando a técnica descrita na postagem de blog acima mencionada, o comando a ser executado é:
git filter-branch --prune-empty -d /dev/shm/scratch \
--index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
--tag-name-filter cat -- --all
Opções:
--prune-empty
remove confirmações que ficam vazias ( ou seja , não alteram a árvore) como resultado da operação do filtro. No caso típico, esta opção produz um histórico mais limpo.
-d
nomeia um diretório temporário que ainda não existe para usar na construção do histórico filtrado. Se você estiver executando em uma distribuição moderna do Linux, especificar uma árvore /dev/shm
resultará em uma execução mais rápida .
--index-filter
é o evento principal e é executado no índice em cada etapa do histórico. Você deseja remover oops.iso
onde quer que seja encontrado, mas não está presente em todas as confirmações. O comando git rm --cached -f --ignore-unmatch oops.iso
exclui o DVD-rip quando está presente e não falha caso contrário.
--tag-name-filter
descreve como reescrever nomes de tags. Um filtro de cat
é a operação de identidade. Seu repositório, como o exemplo acima, pode não ter nenhuma tag, mas eu incluí esta opção para generalidade total.
--
especifica o final das opções para git filter-branch
--all
a seguir --
é uma abreviação para todas as referências. Seu repositório, como a amostra acima, pode ter apenas uma referência (mestre), mas eu incluí esta opção para generalidade total.
Depois de alguma agitação, a história é agora:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A login.html
| * cb14efd Remove DVD-rip
| | D oops.iso
| * ce36c98 Careless
|/ A oops.iso
| A other.html
|
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Observe que a nova confirmação "descuidado" é adicionada apenas other.html
e que a confirmação "Remover DVD-rip" não está mais na ramificação principal. A ramificação rotulada refs/original/refs/heads/master
contém as confirmações originais caso você cometa um erro. Para removê-lo, siga as etapas em "Lista de verificação para reduzir um repositório".
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
Para uma alternativa mais simples, clone o repositório para descartar os bits indesejados.
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
O uso de um file:///...
URL de clone copia objetos em vez de criar apenas links físicos.
Agora sua história é:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Os nomes dos objetos SHA1 para as duas primeiras confirmações ("Índice" e "Página de administração") permaneceram os mesmos porque a operação de filtro não modificou essas confirmações. “Careless” perdido oops.iso
e “página de login” tem um novo pai, para que seus SHA1s fez a mudança.
Rebase interativo
Com um histórico de:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
você deseja remover oops.iso
do “Careless” como se nunca o tivesse adicionado e, em seguida, “Remove DVD-rip” é inútil para você. Portanto, nosso plano para uma reestruturação interativa é manter a "Página do administrador", editar "Descuidado" e descartar "Remover o rasgo do DVD".
A execução $ git rebase -i 5af4522
inicia um editor com o seguinte conteúdo.
pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Executando nosso plano, modificamos para
edit ce36c98 Careless
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
# ...
Ou seja, excluímos a linha com “Remove DVD-rip” e alteramos a operação em “Careless” para edit
melhor que para pick
.
Ao sair do editor, a opção salvar é exibida no prompt de comando com a seguinte mensagem.
Stopped at ce36c98... Careless
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Como a mensagem nos diz, estamos no commit "descuidado" que queremos editar, então executamos dois comandos.
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
O primeiro remove o arquivo incorreto do índice. O segundo modifica ou altera “Careless” para ser o índice atualizado e -C HEAD
instrui o git a reutilizar a antiga mensagem de confirmação. Por fim, git rebase --continue
prossegue com o restante da operação de rebase.
Isso fornece um histórico de:
$ git lola --name-status
* 93174be (HEAD, master) Login page
| A login.html
* a570198 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
qual é o que você quer.