Domanda Come modificare un commit specificato in git?


Di solito invio una lista di commit per la revisione. Se ho:

  • HEAD 
  • Commit3 
  • Commit2 
  • Commit1

So che posso modificare head commit con git commit --amend, ma come posso modificare Commit1, dato che non è il HEAD commettere?


1699
2017-07-27 05:19


origine


risposte:


È possibile utilizzare git rebase, ad esempio, se si desidera modificare nuovamente il commit bbc643cd, correre

$ git rebase --interactive 'bbc643cd^'

Nell'editor predefinito, modifica pick a edit nella riga di cui si desidera modificare il commit. Apporta le tue modifiche e poi confermale con lo stesso messaggio che avevi prima:

$ git commit --all --amend --no-edit

per modificare il commit e dopo

$ git rebase --continue

per tornare al comando precedente.

AVVERTIMENTONota che questo cambierà SHA-1 di quel commit così come tutti i bambini - In altre parole, questo riscrive la storia da quel punto in avanti. Puoi rompere repos facendo questo se si spinge usando il comando git push --force


2232
2017-07-27 05:28



Usa l'incredibile rebase interattivo:

git rebase -i @~9   # Show the last 9 commits in a text editor

Trova il commit che vuoi, cambia pick a e (edit), e salvare e chiudere il file. Git riavvolgerà quel commit, permettendoti di:

  • uso git commit --amend apportare modifiche, o
  • uso git reset @~ per scartare l'ultimo commit, ma non le modifiche ai file (ad esempio, portarti al punto in cui ti trovavi quando avevi modificato i file, ma non avevi ancora eseguito il commit).

Quest'ultimo è utile per fare cose più complesse come la suddivisione in più commit.

Quindi, corri git rebase --continuee Git riprodurrà le successive modifiche in cima al tuo commit modificato. Potrebbe essere richiesto di risolvere alcuni conflitti di unione.

Nota: @ è una scorciatoia per HEAD, e ~ è il commit prima del commit specificato.

Leggi di più riscrivere la storia nei documenti Git.


Non aver paura di rebase

ProTip: non aver paura di sperimentare con comandi "pericolosi" che riscrivono la storia * - Git non cancella i tuoi commit per 90 giorni per impostazione predefinita; puoi trovarli nel reflog:

$ git reset @~3   # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* Attenzione per opzioni come --hard e --force però - possono scartare i dati.
* Inoltre, non riscrivere la cronologia su alcun ramo su cui stai collaborando.



In molti sistemi, git rebase -i aprirà Vim di default. Vim non funziona come la maggior parte degli editor di testo moderni, quindi dai un'occhiata come rebase usando Vim. Se preferisci usare un altro editor, cambialo con git config --global core.editor your-favorite-text-editor.


304
2018-04-29 17:50



Interactive rebase con --autosquash è qualcosa che uso frequentemente quando ho bisogno di correggere i precedenti commit più in profondità nella storia. In sostanza, accelera il processo illustrato dalla risposta di ZelluX ed è particolarmente utile quando hai più di un commit che devi modificare.

Dalla documentazione:

--autosquash

Quando il messaggio del registro di commit inizia con "squash! ..." (o "fixup! ..."), e c'è un commit il cui titolo inizia con lo stesso ..., modifica automaticamente l'elenco di rebase -i in modo che il commit contrassegnato per lo schiacciamento arriva subito dopo il commit da modificare

Supponi di avere una cronologia simile a questa:

$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1

e hai le modifiche che vuoi modificare in Commit2, quindi invia le modifiche usando

$ git commit -m "fixup! Commit2"

in alternativa puoi usare il commit-sha invece del messaggio di commit, quindi "fixup! e8adec4 o anche solo un prefisso del messaggio di commit.

Quindi avviare un rebase interattivo sul commit prima

$ git rebase e8adec4^ -i --autosquash

il tuo editor si aprirà con i commit già correttamente ordinati

pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3

tutto ciò che devi fare è salvare ed uscire


57
2017-09-29 17:59



Correre:

$ git rebase --interactive commit_hash^

ogni ^ indica il numero di commit che vuoi modificare, se è solo uno (l'hash di commit che hai specificato), quindi devi aggiungerne uno ^.

Usando Vim cambi le parole pick a reword per i commit che vuoi cambiare, salvare e uscire (:wq). Quindi git ti chiederà di confermare ogni commit che hai contrassegnato come rielaborato in modo da poter cambiare il messaggio di commit.

Ogni messaggio di commit che devi salvare e uscire (:wq) per passare al messaggio di commit successivo

Se si desidera uscire senza applicare le modifiche, premere :q!

MODIFICARE: per navigare vim usate j salire, k andare giù, h andare a sinistra, e l andare a destra (tutto questo in NORMAL modalità, premere ESC andare a NORMAL modalità ). Per modificare un testo, premere i in modo che tu entri nel INSERT modalità, dove si inserisce il testo. stampa ESC tornare a NORMAL modalità :)

AGGIORNARE: Ecco un ottimo collegamento dall'elenco di Github Come annullare (quasi) qualsiasi cosa con git 


30
2017-07-02 19:11



Se per qualche motivo non ti piacciono gli editor interattivi, puoi usare git rebase --onto.

Dì che vuoi modificare Commit1. In primo luogo, ramo da prima  Commit1:

git checkout -b amending [commit before Commit1]

In secondo luogo, afferrare Commit1 con cherry-pick:

git cherry-pick Commit1

Ora modifica le tue modifiche, creando Commit1':

git add ...
git commit --amend -m "new message for Commit1"

E infine, dopo aver nascosto qualsiasi altra modifica, trapianta il resto dei tuoi impegni fino a master in cima al tuo nuovo commit:

git rebase --onto amending Commit1 master

Leggi: "rebase, sul ramo amending, tutto si impegna tra Commit1 (non incluso) e master (incluso) ". Cioè, Commit2 e Commit3, tagliando completamente il vecchio Commit. Potresti semplicemente selezionarli, ma in questo modo è più facile.

Ricordati di pulire i tuoi rami!

git branch -d amending

12
2017-10-22 12:19



È arrivato a questo approccio (ed è probabilmente esattamente come usare rebase interattivo) ma per me è abbastanza semplice.

Nota: presento questo approccio per illustrare cosa è possibile fare piuttosto che un'alternativa quotidiana. Dal momento che ha molti passaggi (e forse alcuni avvertimenti.)

Dì che vuoi cambiare commit 0 e tu sei attualmente su feature-branch

some-commit---0---1---2---(feature-branch)HEAD

Fai il checkout a questo commit e crea un quick-branch. Puoi anche clonare il tuo ramo di funzionalità come punto di ripristino (prima di iniziare).

?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch

Ora avrai qualcosa di simile a questo:

0(quick-branch)HEAD---1---2---(feature-branch)

Cambiamenti di scena, nascondono tutto il resto.

git add ./example.txt
git stash

Applica modifiche e ricontrolla a feature-branch

git commit --amend
git checkout feature-branch

Ora avrai qualcosa di simile a questo:

some-commit---0---1---2---(feature-branch)HEAD
           \
             ---0'(quick-branch)

rebase feature-branch su quick-branch (risolvi eventuali conflitti lungo la strada). Applicare la scorta e rimuovere quick-branch.

git rebase quick-branch
git stash pop
git branch -D quick-branch

E finisci con:

some-commit---0'---1'---2'---HEAD(feature-branch)

Git non duplicherà (anche se non posso davvero dire fino a che punto) il commit 0 durante la ridefinizione.

Nota: tutti gli hash di commit vengono modificati a partire dal commit che originariamente intendevamo modificare.


6
2018-06-01 11:57



Per ottenere un comando non interattivo, inserisci uno script con questo contenuto nel tuo PERCORSO:

#!/bin/sh
#
# git-fixup
# Use staged changes to modify a specified commit
set -e
cmt=$(git rev-parse $1)
git commit --fixup="$cmt"
GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"

Usalo mettendo in scena le tue modifiche (con git add) e quindi eseguire git fixup <commit-to-modify>. Naturalmente, sarà ancora interattivo se si ottengono conflitti.


4
2018-01-16 15:27



Comando completamente non interattivo(1)

Ho solo pensato di condividere uno pseudonimo che sto usando per questo. È basato su non interattiva rebase interattivo. Per aggiungerlo al tuo git, esegui questo comando (spiegazione fornita di seguito):

git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'

Il più grande vantaggio di questo comando è il fatto che lo sia no-vim.


(1)dato che non ci sono conflitti durante il rebase, ovviamente

uso

git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111

Il nome amend-to sembra appropriato IMHO. Confronta il flusso con --amend:

git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>

Spiegazione

  • git config --global alias.<NAME> '!<COMMAND>' - crea un alias git globale chiamato <NAME> che eseguirà il comando non-git <COMMAND>
  • f() { <BODY> }; f - una funzione bash "anonima".
  • SHA=`git rev-parse "$1"`; - converte l'argomento in git revision e assegna il risultato alla variabile SHA
  • git commit --fixup "$SHA" - fixup-commit per SHA. Vedere git-commit docs
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" la parte è stata coperta da altre risposte.
    • --autosquash è ciò che è usato in congiunzione con git commit --fixup, vedi git-rebase docs per maggiori informazioni
    • GIT_SEQUENCE_EDITOR=true è ciò che rende il tutto non interattivo. Questo hack ho imparato da questo post del blog.

4
2018-02-27 01:47