Sposta il puntatore del ramo su un commit diverso senza checkout


760

Per spostare il puntatore del ramo di un ramo estratto, è possibile utilizzare il git reset --hardcomando. Ma come spostare il puntatore del ramo di un ramo non estratto per puntare a un commit diverso (mantenendo tutte le altre cose come il ramo remoto monitorato)?


11
Sembra che tutto ciò che volevi fare fosse un ramo di un commit diverso da quello da cui è stato creato da ora. Se la mia comprensione è corretta, allora perché non creare semplicemente un nuovo ramo dall'impegno che si desidera creare dall'uso git branch <branch-name> <SHA-1-of-the-commit>e scaricare il vecchio ramo?
Yasouser,

6
@yasouser - Non sono sicuro di quale sia la buona idea di scaricare il ramo "master".
Bulwersator,

Risposte:


578

Puoi farlo per riferimenti arbitrari. Ecco come spostare un puntatore a ramo:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

La forma generale:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Se lo desideri, puoi scegliere i nits sul messaggio di reflog: credo che branch -funo sia diverso da reset --hardquello, e questo non è esattamente nessuno dei due.


39
A cosa serve il messaggio? Dove viene archiviato e come leggerlo in seguito?
Mot

4
NOTA: questo non funziona su repository nudi. Sui repository nudi, devi usare 'git branch -f master <commit>' per aggiornare il ramo (vedi la risposta sotto).
Giugno Rodi,

37
Se, come me, usi accidentalmente <branch> invece di refs / heads / <branch>, finirai con un nuovo file nella tua directory .git in .git / <branch> e riceverai messaggi come "refname 'master' è ambiguo" quando si tenta di lavorare con esso. È possibile eliminare il file dalla directory .git da correggere.
David Minor,

34
Non è stato spiegato con soddisfazione perché questo è meglio di git branch -f. Per essere precisi, questo metodo sembra essere: (A) più difficile da usare (B) più difficile da ricordare e (C) più pericoloso
Steven Lu

10
"cosa si intende esattamente per riferimenti arbitrari" - Le filiali non sono l'unico tipo di riferimento che indica un commit. Ci sono tag e puoi anche creare arbitrariamente refs / whatevs / myref refs che non sono né rami né tag. Credo che risponda anche alla domanda di Steven Lu su cosa potrebbe essere "migliore". Sono d'accordo ramo -f è più semplice se si lavora con rami.
Adam A

965
git branch -f <branch-name> <new-tip-commit>

24
O per arbitri arbitrari, git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>. (Se lo desideri, puoi scegliere i nits sul messaggio di reflog: credo che branch -funo sia diverso da reset --hardquello, e questo non è esattamente nessuno dei due.)
Cascabel

4
Jefromi, ti preghiamo di scrivere una risposta separata in modo da poter ottenere voti. :)
Mot

16
Questa è una risposta migliore poiché gestisce il caso del 99% ed è effettivamente conforme alla documentazione. git help branchdice "-f, --force Ripristina <branchname> su <startpoint> se <branchname> esiste già. Senza -f git branch si rifiuta di cambiare un ramo esistente."
AlexChaffee,

12
Lo sto facendo git branch -f master <hash>e mi sta dicendo che fatal: Cannot force update the current branch.Ummmm devo fare cosa ora, controlla qualche altro ramo casuale prima che mi venga permesso di usare questo comando?
Qwertie

20
Questo non funzionerà se il ramo che stai tentando di spostare è il tuo ramo attuale ( HEADpunta ad esso).
Vladimir Panteleev,

135

Puoi anche passare git reset --hardun riferimento di commit.

Per esempio:

git checkout branch-name
git reset --hard new-tip-commit

Trovo di fare qualcosa del genere semi-frequentemente:

Supponendo questa storia

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master

Ciò ha più senso in quanto in genere si utilizza HEAD o HEAD ^ per spostare indietro la punta del ramo nel tempo. Quindi questo è coerente per specificare il commit in anticipo.
justingordon,

11
Questo va bene se l'albero di lavoro è pulito. Se hai molte modifiche graduali o non programmate, probabilmente è meglio fare git update-refcome discusso sopra.
un secchione pagato l'

16
Hai notato che la tua "risposta" non aggiunge nulla che non fa già parte della domanda ?? - OP ha detto: se è stato verificato ... è possibile utilizzare git reset --hard ...Non è necessario ripeterlo qui! :-(
Robert Siemer,

6
@Robert: non sono d'accordo. La domanda non diceva come usarlo e questo lo fa. È stato bello non andare a cercarlo come.
Wilson F,

7
@WilsonF, forse è stato bello per te trovarlo qui, ma non risponde affatto alla domanda. Forse è la risposta di qualche altra domanda, ma qui è sbagliata .
Robert Siemer,

52

Solo per arricchire la discussione, se vuoi spostare il myBranchramo al tuo attuale commit, ometti il ​​secondo argomento dopo-f

Esempio:

git branch -f myBranch


In genere lo faccio quando mi trovo rebasein uno stato HEAD distaccato :)


13

In gitk --all:

  • fare clic con il tasto destro sul commit desiderato
  • -> crea un nuovo ramo
  • inserisci il nome di una filiale esistente
  • premi Invio sulla finestra di dialogo che conferma la sostituzione del vecchio ramo con quel nome .

Fai attenzione che la ricostruzione, invece di modificare il ramo esistente , perderà le informazioni sul ramo di tracciamento . (Questo in genere non è un problema per casi d'uso semplici in cui esiste un solo telecomando e il tuo ramo locale ha lo stesso nome del ramo corrispondente nel telecomando. Vedi i commenti per maggiori dettagli, grazie @mbdevpl per aver sottolineato questo aspetto negativo.)

Sarebbe bello se gitkavesse una funzione in cui la finestra di dialogo avesse 3 opzioni: sovrascrivi, modifica esistenti o annulla.


Anche se di solito sei un drogato da riga di comando come me, git guie gitksei abbastanza ben progettato per il sottoinsieme dell'utilizzo di git che consentono. Consiglio vivamente di usarli per quello che sono bravi (cioè mettere in scena selettivamente hunk dentro / fuori dall'indice in git gui, e anche solo impegnarsi. (Ctrl-s per aggiungere una firma: linea, ctrl-invio per impegnarsi .)

gitk è ottimo per tenere traccia di alcuni rami mentre si ordinano le modifiche in una bella serie di patch da inviare a monte, o qualsiasi altra cosa in cui è necessario tenere traccia di ciò che si è nel mezzo con più rami.

Non ho nemmeno un browser di file grafico aperto, ma adoro gitk / git gui.


1
Così facile! Potrei essermi appena convertito da Gitg a Gitk.
Michael Cole,

In questo modo, tuttavia, le informazioni sul ramo di tracciamento vengono perse.
mbdevpl,

@mbdevpl: non sono un esperto di git. Penso di capire cosa intendi, ma non le implicazioni. L'ho usato abbastanza spesso e sono ancora riuscito a spingere quei rami su rami con lo stesso nome su un telecomando. Che cosa fa per te l'associazione tra una filiale e la sua filiale di localizzazione remota?
Peter Cordes,


1
@PeterCordes Ineed, quando i nomi dei rami non corrispondono, conta. Anche quando c'è più di un telecomando. Inoltre, quando si utilizza git prompt per visualizzare lo stato della diramazione, mostrerà la distanza di commit alla diramazione di tracciamento (se impostata). Inoltre, l' git statusoutput è interessato. Inoltre, in alcuni casi git fetche git pushnon funzionerà senza specificare esplicitamente remoto se non si imposta il ramo di tracciamento. Non conosco tutti i casi, ma per me la regola generale è che per comodità e velocità di lavoro, è meglio avere i rami di tracciamento in ordine.
mbdevpl,

7

La soluzione consigliatagit branch -f branch-pointer-to-move new-pointer in TortoiseGit :

  • "Git Mostra registro"
  • Seleziona "Tutte le filiali"
  • Sulla riga in cui si desidera spostare il puntatore del ramo (new-pointer):
    • Fare clic con il tasto destro, "Crea Branch in questa versione"
    • Accanto a "Branch", inserisci il nome del ramo da spostare (branch-pointer-to-move)
    • In "Base attiva", controlla che il nuovo puntatore sia corretto
    • Controlla "Forza"
    • Ok

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


4

Onestamente, sono sorpreso di come nessuno abbia pensato al git pushcomando:

git push -f . <destination>:<branch>

Il punto (.) Fa riferimento al repository locale e potrebbe essere necessaria l'opzione -f perché la destinazione potrebbe essere "dietro la sua controparte remota" .

Sebbene questo comando venga utilizzato per salvare le modifiche nel server, il risultato è esattamente lo stesso di se si sposta il ramo remoto ( <branch>) nello stesso commit del ramo locale ( <destination>)


Puoi anche farlo senza -fevitare di intasare nulla di locale; per esempio, git fetch origin && git push . origin/develop:developè una versione fail-fast non necessaria di checkout digit checkout develop && git pull --ff-only
btown l'

1

Apri il file .git/refs/heads/<your_branch_name>e modifica l'hash memorizzato in quello in cui vuoi spostare la testa del tuo ramo. Modifica e salva il file con qualsiasi editor di testo. Assicurati solo che il ramo da modificare non sia quello attivo corrente.

Disclaimer: probabilmente non è un modo consigliabile per farlo, ma ottiene il lavoro fatto.


1
Non sono sicuro se questo è il modo caotico o malvagio per farlo. 🤔 😉
Keith Russell

@KeithRussell può essere entrambi: P
Guillermo Gutiérrez

0

Nel caso in cui il commit a cui vuoi puntare sia davanti al ramo corrente (che dovrebbe essere il caso a meno che tu non voglia annullare gli ultimi commit del ramo corrente), puoi semplicemente fare:

git merge <commit>

Domanda posta su cosa fare se la filiale non è stata estratta.
Keith Russell,

Oops, ho perso quel punto. In tal caso, potresti fare git push . <commit>:<branch>come già suggerito.
Jean Paul
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.