De outras respostas aqui, eu fiquei meio confuso com como git rebase -i
poderia ser usado para remover uma confirmação, então espero que seja correto anotar meu caso de teste aqui (muito semelhante ao OP).
Aqui está um bash
script que você pode colar para criar um repositório de teste na /tmp
pasta:
set -x
rm -rf /tmp/myrepo*
cd /tmp
mkdir myrepo_git
cd myrepo_git
git init
git config user.name me
git config user.email me@myself.com
mkdir folder
echo aaaa >> folder/file.txt
git add folder/file.txt
git commit -m "1st git commit"
echo bbbb >> folder/file.txt
git add folder/file.txt
git commit -m "2nd git commit"
echo cccc >> folder/file.txt
git add folder/file.txt
git commit -m "3rd git commit"
echo dddd >> folder/file.txt
git add folder/file.txt
git commit -m "4th git commit"
echo eeee >> folder/file.txt
git add folder/file.txt
git commit -m "5th git commit"
Neste ponto, temos um file.txt
com este conteúdo:
aaaa
bbbb
cccc
dddd
eeee
Nesse ponto, HEAD está no 5º commit, HEAD ~ 1 seria o quarto - e HEAD ~ 4 seria o 1º commit (portanto, HEAD ~ 5 não existiria). Digamos que queremos remover o terceiro commit - podemos emitir este comando no myrepo_git
diretório:
git rebase -i HEAD~4
( Observe que git rebase -i HEAD~5
resulta em "fatal: precisava de uma única revisão; HEAD ~ 5 upstream inválido". ) Um editor de texto (veja a captura de tela na resposta do @Dennis ' ) será aberto com o seguinte conteúdo:
pick 5978582 2nd git commit
pick 448c212 3rd git commit
pick b50213c 4th git commit
pick a9c8fa1 5th git commit
# Rebase b916e7f..a9c8fa1 onto b916e7f
# ...
Portanto, obtemos todos os commits desde (mas não incluindo ) nosso pedido HEAD ~ 4. Exclua a linha pick 448c212 3rd git commit
e salve o arquivo; você receberá esta resposta de git rebase
:
error: could not apply b50213c... 4th git commit
When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Could not apply b50213c... 4th git commit
Neste ponto, abra myrepo_git / folder/file.txt
em um editor de texto; você verá que foi modificado:
aaaa
bbbb
<<<<<<< HEAD
=======
cccc
dddd
>>>>>>> b50213c... 4th git commit
Basicamente, git
vê que quando HEAD chegou ao segundo commit, havia conteúdo de aaaa
+ bbbb
; e, em seguida, possui um patch adicionado cccc
+ dddd
que não sabe como anexar ao conteúdo existente.
Portanto, aqui git
não é possível decidir por você - é você quem deve tomar uma decisão: removendo o terceiro commit, você mantém as alterações introduzidas por ele (aqui, a linha cccc
) - ou não. Caso contrário, remova as linhas extras - incluindo a cccc
- folder/file.txt
usando um editor de texto, para que fique assim:
aaaa
bbbb
dddd
... e depois salve folder/file.txt
. Agora você pode emitir os seguintes comandos no myrepo_git
diretório:
$ nano folder/file.txt # text editor - edit, save
$ git rebase --continue
folder/file.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add
Ah - por isso, a fim de marca que nós resolvemos o conflito, que deve git add
o folder/file.txt
, antes de fazer git rebase --continue
:
$ git add folder/file.txt
$ git rebase --continue
Aqui um editor de texto é aberto novamente, mostrando a linha 4th git commit
- aqui temos a chance de alterar a mensagem de confirmação (que neste caso pode ser significativamente alterada para 4th (and removed 3rd) commit
ou similar). Digamos que você não queira - então basta sair do editor de texto sem salvar; Depois de fazer isso, você receberá:
$ git rebase --continue
[detached HEAD b8275fc] 4th git commit
1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.
Neste ponto, agora você tem um histórico como este (que você também pode inspecionar com digamos gitk .
ou outras ferramentas) do conteúdo folder/file.txt
(com, aparentemente, timestamps inalterados dos commits originais):
1st git commit | +aaaa
----------------------------------------------
2nd git commit | aaaa
| +bbbb
----------------------------------------------
4th git commit | aaaa
| bbbb
| +dddd
----------------------------------------------
5th git commit | aaaa
| bbbb
| dddd
| +eeee
E se anteriormente, decidimos manter a linha cccc
(o conteúdo do terceiro commit do git que removemos), teríamos:
1st git commit | +aaaa
----------------------------------------------
2nd git commit | aaaa
| +bbbb
----------------------------------------------
4th git commit | aaaa
| bbbb
| +cccc
| +dddd
----------------------------------------------
5th git commit | aaaa
| bbbb
| cccc
| dddd
| +eeee
Bem, esse era o tipo de leitura que eu esperava ter encontrado, para começar a entender como git rebase
funciona em termos de exclusão de confirmações / revisões; espero que ajude outras pessoas também ...