È possibile spostare / rinominare i file in Git e mantenerne la cronologia?


667

Vorrei rinominare / spostare una sottostruttura di progetto in Git spostandola da

/project/xyz

per

/components/xyz

Se uso una pianura git mv project components, allora tutta la cronologia di commit per xyz projectviene persa. C'è un modo per spostare questo in modo tale che la storia venga mantenuta?



2
Voglio solo notare che ho appena provato a spostare i file tramite il filesystem e dopo aver eseguito il commit (tramite intellij) posso quindi vedere l'intera cronologia (inclusa la cronologia quando si trovava in una posizione diversa) quando visualizzo la cronologia (di nuovo in intellij). Suppongo che Intellij non stia facendo nulla di particolarmente speciale per farlo, quindi è bello sapere che almeno la storia può essere tracciata.
BT,

Per le regole seguite da Git quando rileva una ridenominazione di directory, vedi la mia risposta di seguito
VonC

Ho scritto una risposta qui. Spero che funzioni. stackoverflow.com/questions/10828267/…
Mahmut EFE

Risposte:


651

Git rileva i nomi piuttosto che persistere con il commit, quindi se usi git mvo mvmeno.

Il logcomando accetta un --followargomento che continua la cronologia prima di un'operazione di ridenominazione, ovvero cerca contenuti simili utilizzando l'euristica:

http://git-scm.com/docs/git-log

Per cercare la cronologia completa, utilizzare il comando seguente:

git log --follow ./path/to/file

63
Sospetto che questa sia una considerazione delle prestazioni. Se non è necessaria la cronologia completa, la scansione del contenuto richiederà sicuramente più tempo. Il modo più semplice è impostare un alias git config alias.logf "log --follow"e scrivere git logf ./path/to/file.
Troels Thomsen,

13
@TroelsThomsen questa e-mail di Linus Torvalds, collegata da questa risposta , indica che si tratta di una scelta intenzionale di progettazione di Git poiché è presumibilmente molto più potente del rintracciamento dei nomi, ecc.
Emil Lundberg,

127
Questa risposta è un po 'fuorviante. Git "rileva i nomi", ma molto tardi nel gioco; la domanda è: come ti assicuri che Git tenga traccia dei nomi, e qualcuno che sta leggendo questo può facilmente dedurre che Git li rileva automaticamente per te e se ne accorge. Non è così. Git non ha una vera gestione dei nomi, e invece ci sono strumenti di unione / registro che tentano di capire cosa è successo - e raramente riescono a farlo bene. Linus ha un argomento errato ma veemente sul perché Git non dovrebbe mai farlo nel modo giusto e rintracciare i nomi in modo esplicito. Quindi, siamo bloccati qui.
Chris Moschini,

29
Importante: se si rinomina una directory, ad esempio durante la ridenominazione di un pacchetto Java, assicurarsi di eseguire due commit, prima per il comando 'git mv {vecchio} {nuovo}', in secondo luogo per gli aggiornamenti di tutti i file Java che fanno riferimento al directory del pacchetto modificata. Altrimenti git non può tracciare i singoli file anche con il parametro --follow.
nn4l

44
Sebbene Linus probabilmente commetta pochissimi errori, questo sembra essere uno. La semplice ridenominazione di una cartella comporta il caricamento di un delta enorme su GitHub. Il che mi rende cauto nel rinominare le mie cartelle ... ma questa è una giacca piuttosto grande per un programmatore. Occasionalmente, DEVO ridefinire il significato di qualcosa o cambiare il modo in cui le cose sono classificate. Linus: "In altre parole, ho ragione. Ho sempre ragione, ma a volte ho più ragione delle altre volte. E dannazione, quando dico che" i file non contano ", ho davvero ragione ( tm)." ... ho i miei dubbi su quello.
Gabe Halsmer,

94

È possibile rinominare un file e mantenere intatta la cronologia, anche se provoca la ridenominazione del file nell'intera cronologia del repository. Questo è probabilmente solo per gli ossessivi amanti di git-log e ha alcune serie implicazioni, tra cui:

  • Potresti riscrivere una cronologia condivisa, che è il più importante NON FARE mentre usi Git. Se qualcun altro ha clonato il repository, lo spezzerai facendo questo. Dovranno ri-clonare per evitare mal di testa. Questo potrebbe essere OK se la ridenominazione è abbastanza importante, ma dovresti prenderlo in considerazione attentamente: potresti finire per sconvolgere un'intera comunità opensource!
  • Se hai fatto riferimento al file utilizzando il suo vecchio nome in precedenza nella cronologia del repository, stai effettivamente rompendo le versioni precedenti. Per ovviare a questo, dovrai fare un po 'più di salto con il cerchio. Non è impossibile, solo noioso e forse non ne vale la pena.

Ora, poiché sei ancora con me, probabilmente sei uno sviluppatore solista che rinomina un file completamente isolato. Spostiamo un file usando filter-tree!

Supponi di voler spostare un file oldin una cartella dire assegnargli il nomenew

Questo potrebbe essere fatto con git mv old dir/new && git add -u dir/new, ma che rompe la storia.

Anziché:

git filter-branch --tree-filter 'if [ -f old ]; then mkdir dir && mv old dir/new; fi' HEAD

sarà rifare ogni commit nel ramo, eseguendo il comando delle zecche per ogni iterazione. Un sacco di cose possono andare storte quando lo fai. Normalmente provo a vedere se il file è presente (altrimenti non è ancora lì per spostarsi) e quindi eseguo i passaggi necessari per calzare l'albero a mio piacimento. Qui è possibile consultare i file per modificare i riferimenti al file e così via. Buttati fuori! :)

Al termine, il file viene spostato e il registro è intatto. Ti senti come un pirata ninja.

Anche; La dir mkdir è necessaria solo se si sposta il file in una nuova cartella, ovviamente. L' if eviterà la creazione di questa cartella prima nella cronologia di quanto esista il tuo file.


57
Come ossessivo amante dei log, non ci proverei. Ai file non era stato assegnato il nome in quei momenti, quindi la storia riflette una situazione inesistente. Chissà quali test potrebbero rompersi in passato! Il rischio di infrangere le versioni precedenti non vale praticamente la pena.
Vincent,

7
@Vincent Hai perfettamente ragione, e ho cercato di essere il più chiaro possibile sull'improbabilità che questa soluzione fosse appropriata. Penso anche che stiamo parlando di due significati della parola "storia" in questo caso, apprezzo entrambi.
Øystein Steimler

6
Trovo che ci siano situazioni in cui si potrebbe aver bisogno di questo. Supponiamo di aver sviluppato qualcosa nel mio ramo personale, che ora voglio unire a monte. Ma scopro che il nome del file non è appropriato, quindi lo cambio per tutto il mio ramo personale. In questo modo posso mantenere una cronologia corretta e avere il nome corretto dall'inizio.
user2291758

3
@ user2291758 questo è il mio caso d'uso. Questi comandi git più potenti sono pericolosi ma ciò non significa che non abbiano casi d'uso molto convincenti se sai cosa stai facendo!
philix,

1
se possibile, l'utilizzo di --index-filterfor renames sarà molto più veloce in quanto l'albero non dovrà essere estratto e ripristinato ad ogni commit. --index-filteragisce direttamente su ciascun indice di commit.
Thomas Guyot-Sionnest,

87

No.

La risposta breve è NO . Non è possibile rinominare un file in Git e ricordare la cronologia. Ed è un dolore.

Si dice che git log --follow--find-copies-harderfunzionerà, ma non funziona per me, anche se non ci sono modifiche al contenuto del file e le mosse sono state fatte git mv.

(Inizialmente ho usato Eclipse per rinominare e aggiornare i pacchetti in un'unica operazione, il che potrebbe aver confuso Git. Ma questa è una cosa molto comune da fare. --followSembra funzionare solo se mvviene eseguita una e quindi una commite mvnon è troppo lontana.)

Linus afferma che dovresti comprendere tutti i contenuti di un progetto software in modo olistico, senza dover tenere traccia dei singoli file. Beh, purtroppo, il mio piccolo cervello non può farlo.

È davvero fastidioso che così tante persone abbiano ripetutamente insensato l'affermazione che Git tiene traccia automaticamente delle mosse. Hanno perso tempo. Git non fa nulla del genere. In base alla progettazione (!) Git non tiene traccia delle mosse.

La mia soluzione è quella di rinominare i file nella loro posizione originale. Modificare il software per adattarlo al controllo del codice sorgente. Con Git sembra che tu abbia bisogno di "git" giusto la prima volta.

Sfortunatamente, questo rompe Eclipse, che sembra usare --follow. git log --followa volte non mostra la cronologia completa dei file con storie di ridenominazione complicate, anche se lo git logfa. (Non so perché.)

(Ci sono alcuni hack troppo intelligenti che tornano indietro e raccomandano il vecchio lavoro, ma sono piuttosto spaventosi. Vedi GitHub-Gist: emiller / git-mv-with-history .)


2
Credo che tu abbia ragione. Stavo solo cercando di usare php-cs-fixer per riformattare l'origine del mio progetto Laravel 5, ma insiste per cambiare la capitalizzazione delle clausole dello spazio dei nomi in modo che corrisponda al valore minuscolo della cartella dell'app. Ma gli spazi dei nomi (o i caricamenti automatici del compositore) funzionano solo con CamelCase. Devo modificare le maiuscole della cartella in App ma questo fa perdere le mie modifiche. Questo è l'esempio più banale, ma mostra come l'euristico git non sia in grado di seguire nemmeno il più semplice dei cambi di nome (--follow e --find-copy-harder dovrebbero essere la regola, non l'eccezione).
Zack Morris,

6
git -1, sovversione +1
Cosmin

È ancora vero? Questo è un motivo in più per me per rimanere con tfs per ora, mantenere la cronologia di un file spostato / rinominato è un must in un grande progetto.
Cesar,

@Cesar Se per "ricordare la storia", intende "seguire i nomi durante la visualizzazione del registro" (che è l'unica cosa utile di cui dovremmo preoccuparci), allora questo non è mai stato vero! Git non "registra" i nomi, ma gli strumenti possono facilmente rilevarli e presentarci con i nomi e le mosse. Se "non funziona" per qualcuno, lui / lei dovrebbe cambiare gli strumenti che sta usando. Ci sono molte meravigliose GUI Git che hanno questa capacità.
Mohammad Dehghan,

La risposta breve è Sì. La versione corrente di Git supporta anche "git log --follow". e sono d'accordo con @MohammadDehghan
insung

43
git log --follow [file]

ti mostrerà la cronologia attraverso i nomi.


29
Sembra che ciò richieda il commit solo della ridenominazione prima di iniziare a modificare il file. Se sposti il ​​file (nella shell) e poi lo cambi, tutte le scommesse sono disattivate.
yoyo

22
@yoyo: questo perché git non tiene traccia dei nomi, li rileva. A git mvfondamentalmente fa a git rm && git add. Ci sono opzioni come -M90/ --find-renames=90per considerare un file da rinominare quando è identico al 90%.
vdboor,

22

Lo voglio:

git mv {old} {new}
git add -u {new}

3
Il -u non sembra fare nulla per me, si suppone che aggiorni la cronologia?
Jeremy,

1
Forse vuoi invece il comportamento -A? Ancora una volta, vedi qui: git-scm.com/docs/git-add
James M. Greene,

1
Aggiunge i file, tuttavia non aggiorna la cronologia in modo che "git log file name" mostri la cronologia completa. Mostra la cronologia completa solo se si utilizza ancora l'opzione --follow.
Jeremy,

3
Ho fatto un refactor complicato che ha spostato una directory include (usando mv, non git mv) e poi ho cambiato molti percorsi #include all'interno dei file rinominati. git non è riuscito a trovare abbastanza somiglianza per tracciare la storia. Ma git add -u era proprio quello di cui avevo bisogno. Lo stato git ora indica "rinominato" dove prima mostrava "cancellato" e "nuovo file".
AndyJost,

1
Ci sono molte domande su SO che affrontano lo scopo di git add -u. I documenti di Git tendono ad essere inutili e sono l'ultimo posto in cui vorrei cercare. Ecco un post che mostra git add -uin azione: stackoverflow.com/a/2117202 .
nobar,

17

Vorrei rinominare / spostare una sottostruttura di progetto in Git spostandola da

/project/xyz

per

/ Components / xyz

Se uso una pianura git mv project components, allora tutta la cronologia di commit per il xyzprogetto viene persa.

No (8 anni dopo, Git 2.19, Q3 2018), perché Git rileverà la ridenominazione della directory e questo è ora meglio documentato.

Vedi commit b00bf1c , commit 1634688 , commit 0661e49 , commit 4d34dff , commit 983f464 , commit c840e1a , commit 9929430 (27 giu 2018) e commit d4e8062 , commit 5dacd4a (25 giu 2018) di Elijah Newren ( newren) .
(Unita da Junio ​​C Hamano - gitster- in commit 0ce5a69 , 24 lug 2018)

Questo è ora spiegato in Documentation/technical/directory-rename-detection.txt:

Esempio:

Quando tutti x/a, x/be si x/csono spostati su z/a, z/be z/c, è probabile che l' x/daggiunta nel frattempo voglia anche passare a z/dsuggerendo che l'intera directory ' x' si è spostata su ' z'.

Ma sono molti altri casi, come:

un lato della cronologia rinomina x -> ze l'altro rinomina alcuni file x/e, causando la necessità che l'unione esegua una ridenominazione transitiva.

Per semplificare il rilevamento della ridenominazione di directory, queste regole sono applicate da Git:

un paio di regole di base limitano quando si applica il rilevamento della ridenominazione di directory:

  1. Se una determinata directory esiste ancora su entrambi i lati di un'unione, non consideriamo che sia stata rinominata.
  2. Se un sottoinsieme di file da rinominare presenta un file o una directory (o si frappone), "disattiva" la ridenominazione della directory per quei percorsi secondari specifici e segnala all'utente il conflitto .
  3. Se l'altro lato della cronologia ha rinominato una directory in un percorso che il tuo lato della cronologia ha rinominato, ignora quel particolare nome dall'altro lato della cronologia per qualsiasi ridenominazione di directory implicita (ma avvisa l'utente).

Puoi vedere molti test in t/t6043-merge-rename-directories.sh, che sottolineano anche che:

  • a) Se le ridenominazioni dividono una directory in due o più altre, la directory con il maggior numero di rinominazioni "vince".
  • b) Evitare il rilevamento della ridenominazione di directory per un percorso, se tale percorso è l'origine di una ridenominazione su entrambi i lati di un'unione.
  • c) Applicare rinominazioni di directory implicite alle directory solo se l'altro lato della cronologia è quello che sta rinominando.

15

Obbiettivo

  • Usa (ispirato a Smar , preso in prestito da Exherbo )git am
  • Aggiungi cronologia commit dei file copiati / spostati
  • Da una directory all'altra
  • O da un repository all'altro

Limitazione

  • Tag e rami non vengono mantenuti
  • La cronologia viene tagliata con il nome del file di percorso (ridenominazione directory)

Sommario

  1. Estrarre la cronologia in formato e-mail utilizzando
    git log --pretty=email -p --reverse --full-index --binary
  2. Riorganizza l'albero dei file e aggiorna i nomi dei file
  3. Aggiungi nuova cronologia utilizzando
    cat extracted-history | git am --committer-date-is-author-date

1. Estrarre la cronologia in formato e-mail

Esempio: la storia di estratto file3, file4efile5

my_repo
├── dirA
│   ├── file1
│   └── file2
├── dirB            ^
│   ├── subdir      | To be moved
│   │   ├── file3   | with history
│   │   └── file4   | 
│   └── file5       v
└── dirC
    ├── file6
    └── file7

Imposta / pulisci la destinazione

export historydir=/tmp/mail/dir       # Absolute path
rm -rf "$historydir"    # Caution when cleaning the folder

Estrai la cronologia di ogni file in formato e-mail

cd my_repo/dirB
find -name .git -prune -o -type d -o -exec bash -c 'mkdir -p "$historydir/${0%/*}" && git log --pretty=email -p --stat --reverse --full-index --binary -- "$0" > "$historydir/$0"' {} ';'

Purtroppo l'opzione --followo --find-copies-hardernon può essere combinata con --reverse. Questo è il motivo per cui la cronologia viene tagliata quando il file viene rinominato (o quando viene rinominata una directory padre).

Cronologia temporanea in formato e-mail:

/tmp/mail/dir
    ├── subdir
    │   ├── file3
    │   └── file4
    └── file5

Dan Bonachea suggerisce di invertire i loop del comando di generazione del log git in questo primo passo: anziché eseguire git log una volta per file, eseguirlo esattamente una volta con un elenco di file sulla riga di comando e generare un singolo registro unificato. In questo modo i commit che modificano più file rimangono un singolo commit nel risultato e tutti i nuovi commit mantengono il loro ordine relativo originale. Si noti che ciò richiede anche modifiche nel secondo passaggio di seguito quando si riscrivono i nomi dei file nel registro (ora unificato).


2. Riorganizzare l'albero dei file e aggiornare i nomi dei file

Supponiamo di voler spostare questi tre file in questo altro repository (può essere lo stesso repository).

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB              # New tree
│   ├── dirB1         # from subdir
│   │   ├── file33    # from file3
│   │   └── file44    # from file4
│   └── dirB2         # new dir
│        └── file5    # from file5
└── dirH
    └── file77

Quindi riorganizza i tuoi file:

cd /tmp/mail/dir
mkdir -p dirB/dirB1
mv subdir/file3 dirB/dirB1/file33
mv subdir/file4 dirB/dirB1/file44
mkdir -p dirB/dirB2
mv file5 dirB/dirB2

La tua cronologia temporanea è ora:

/tmp/mail/dir
    └── dirB
        ├── dirB1
        │   ├── file33
        │   └── file44
        └── dirB2
             └── file5

Cambia anche i nomi dei file nella cronologia:

cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'

3. Applica nuova cronologia

L'altro repository è:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
└── dirH
    └── file77

Applica commit da file cronologici temporanei:

cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am --committer-date-is-author-date

--committer-date-is-author-dateconserva i timestamp di commit originali ( commento di Dan Bonachea ).

L'altro repository è ora:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB
│   ├── dirB1
│   │   ├── file33
│   │   └── file44
│   └── dirB2
│        └── file5
└── dirH
    └── file77

Utilizzare git statusper visualizzare la quantità di commit pronti per essere inviati :-)


Trucco extra: controlla i file rinominati / spostati nel tuo repository

Per elencare i file che sono stati rinominati:

find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'

Altre personalizzazioni: è possibile completare il comando git logutilizzando le opzioni --find-copies-hardero --reverse. Puoi anche rimuovere le prime due colonne usando cut -f3-e grepping il modello completo '{. * =>. *}'.

find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'

4
ATTENZIONE: questa tecnica suddivide i commit che cambiano 2 o più file in commit frammentati separati, e inoltre mescola il loro ordine ordinando il nome del file (quindi i frammenti di un commit originale non appaiono adiacenti nella cronologia lineare). La cronologia risultante è quindi "corretta" solo su base file per file. Se si sposta più di un file, NESSUNO dei nuovi commit nella cronologia risultante rappresenta un'istantanea coerente dei file spostati che siano mai esistiti nella cronologia del repository originale.
Dan Bonachea,

2
Ciao @DanBonachea. Grazie per il tuo feedback interessante. Ho migrato con successo alcuni repository contenenti diversi file usando questa tecnica (anche con file rinominati e file spostati tra le directory). Cosa suggerisci di cambiare in questa risposta. Pensi che dovremmo aggiungere un banner di ATTENZIONE nella parte superiore di questa risposta che spiega i limiti di questa tecnica? Saluti
olibre

2
Ho adattato questa tecnica per evitare il problema invertendo i loop del comando di generazione del log git nel passaggio 1. Vale a dire. anziché eseguire git log una volta per file, eseguirlo esattamente una volta con un elenco di file sulla riga di comando e generare un singolo registro unificato. In questo modo i commit che modificano 2 o più file rimangono un singolo commit nel risultato e tutti i nuovi commit mantengono il loro ordine relativo originale. Si noti che ciò richiede anche modifiche al passaggio 2 quando si riscrivono i nomi dei file nel registro (ora unificato). Ho anche usato git am --committer-date-is-author-date per preservare i timestamp di commit originali.
Dan Bonachea,

1
Grazie per la tua sperimentazione e condivisione. Ho aggiornato un po 'la risposta per gli altri lettori. Tuttavia, ho impiegato del tempo per testare la tua elaborazione. Non esitate a modificare questa risposta se si desidera fornire esempi di righe di comando. Saluti;)
olibre

4

Ho seguito questo processo in più passaggi per spostare il codice nella directory principale e conservare la cronologia.

Passaggio 0: creato un ramo "cronologia" da "master" per la custodia

Passaggio 1: utilizzato lo strumento git-filter-repo per riscrivere la cronologia. Questo comando di seguito ha spostato la cartella 'FolderwithContentOfInterest' a un livello superiore e ha modificato la cronologia di commit pertinente

git filter-repo --path-rename ParentFolder/FolderwithContentOfInterest/:FolderwithContentOfInterest/ --force

Passaggio 2: A questo punto il repository GitHub ha perso il percorso del repository remoto. Aggiunto riferimento remoto

git remote add origin git@github.com:MyCompany/MyRepo.git

Passaggio 3: estrarre informazioni sul repository

git pull

Passaggio 4: collegare il ramo perso locale con il ramo di origine

git branch --set-upstream-to=origin/history history

Passaggio 5: conflitto di unione degli indirizzi per la struttura delle cartelle, se richiesto

Passaggio 6: spingere !!

git push

Nota: la cronologia modificata e la cartella spostata sembrano essere già state salvate. enter code here

Fatto. Il codice si sposta nella directory principale / desiderata mantenendo intatta la cronologia!


2

Mentre il nucleo di Git, l'idraulico Git non tiene traccia dei nomi, la cronologia che visualizzi con il registro Git "porcellana" può rilevarli se vuoi.

Per un dato git loguso l'opzione -M:

git log -p -M

Con una versione corrente di Git.

Questo funziona anche per altri comandi git diff.

Ci sono opzioni per rendere i confronti più o meno rigorosi. Se si rinomina un file senza apportare modifiche significative al file allo stesso tempo, sarà più facile per Git log e gli amici rilevare la ridenominazione. Per questo motivo alcune persone rinominano i file in un commit e li cambiano in un altro.

C'è un costo nell'uso della CPU ogni volta che chiedi a Git di scoprire dove sono stati rinominati i file, quindi se lo usi o meno e quando dipende da te.

Se desideri avere sempre la cronologia segnalata con il rilevamento della ridenominazione in un determinato repository, puoi utilizzare:

git config diff.renames 1

I file che si spostano da una directory all'altra vengono rilevati. Ecco un esempio:

commit c3ee8dfb01e357eba1ab18003be1490a46325992
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:20:19 2017 -0500

    test rename again

diff --git a/yyy/power.py b/zzz/power.py
similarity index 100%
rename from yyy/power.py
rename to zzz/power.py

commit ae181377154eca800832087500c258a20c95d1c3
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:19:17 2017 -0500

    rename test

diff --git a/power.py b/yyy/power.py
similarity index 100%
rename from power.py
rename to yyy/power.py

Si noti che questo funziona ogni volta che si utilizza diff, non solo con git log. Per esempio:

$ git diff HEAD c3ee8df
diff --git a/power.py b/zzz/power.py
similarity index 100%
rename from power.py
rename to zzz/power.py

Come prova ho apportato una piccola modifica a un file in un ramo di funzionalità e l'ho eseguito il commit, quindi nel ramo master ho rinominato il file, eseguito il commit, quindi ho apportato una piccola modifica in un'altra parte del file e l'ho eseguito. Quando sono andato al ramo delle funzioni e unito dal master, l'unione ha rinominato il file e unito le modifiche. Ecco l'output dall'unione:

 $ git merge -v master
 Auto-merging single
 Merge made by the 'recursive' strategy.
  one => single | 4 ++++
  1 file changed, 4 insertions(+)
  rename one => single (67%)

Il risultato è stato una directory di lavoro con il file rinominato e apportate entrambe le modifiche al testo. Quindi è possibile che Git faccia la cosa giusta nonostante non rintracci esplicitamente i nomi.

Questa è una risposta tardiva a una vecchia domanda, quindi le altre risposte potrebbero essere state corrette per la versione Git al momento.


1

Innanzitutto creare un commit autonomo con solo una ridenominazione.

Quindi eventuali modifiche al contenuto del file inserite nel commit separato.


1

Per rinominare una directory o un file (non so molto su casi complessi, quindi potrebbero esserci alcuni avvertimenti):

git filter-repo --path-rename OLD_NAME:NEW_NAME

Per rinominare una directory nei file che la menzionano (è possibile utilizzare i callback, ma non so come):

git filter-repo --replace-text expressions.txt

expressions.txtè un file pieno di righe come literal:OLD_NAME==>NEW_NAME(è possibile usare RE di Python con regex:o glob con glob:).

Per rinominare una directory nei messaggi di commit:

git-filter-repo --message-callback 'return message.replace(b"OLD_NAME", b"NEW_NAME")'

Sono supportate anche le espressioni regolari di Python, ma devono essere scritte manualmente in Python.

Se il repository è originale, senza telecomando, dovrai aggiungere --forceper forzare una riscrittura. (Potresti voler creare un backup del tuo repository prima di farlo.)

Se non si desidera conservare i riferimenti (verranno visualizzati nella cronologia delle filiali della GUI di Git), sarà necessario aggiungere --replace-refs delete-no-add.


0

Basta spostare il file e lo stage con:

git add .

Prima di eseguire il commit è possibile verificare lo stato:

git status

Questo mostrerà:

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    old-folder/file.txt -> new-folder/file.txt

Ho provato con Git versione 2.26.1.

Estratto dalla pagina di aiuto di GitHub .


-3

Faccio spostare i file e poi faccio

git add -A

che ha messo nell'area di saturazione tutti i file cancellati / nuovi. Qui git si rende conto che il file viene spostato.

git commit -m "my message"
git push

Non so perché ma questo funziona per me.


Il trucco qui è che non devi cambiare una singola lettera, anche se cambi qualcosa e premi Ctrl + Z, la cronologia verrà spezzata. Quindi, in quel caso, se scrivi qualcosa, ripristina il file e spostalo di nuovo e fai un singolo add-> commit per esso.
Xelian il
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.