Konwertuję wszystko na Git na własny użytek i znalazłem kilka starych wersji pliku już w repozytorium. Jak zapisać historię w prawidłowej kolejności zgodnie z „datą modyfikacji” pliku, aby mieć dokładną historię pliku?
Powiedziano mi, że coś takiego działa:
git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all
git
version-control
repository
git-commit
nieznany
źródło
źródło
git commit --date="xxx day ago" -m "yyy"
do tego celu, jeśli ktoś się zastanawia.Odpowiedzi:
Porada, którą otrzymałeś, jest wadliwa. Bezwarunkowe ustawienie GIT_AUTHOR_DATE w
--env-filter
spowoduje przepisanie daty każdego zatwierdzenia. Poza tym użycie git commit w środku byłoby niezwykłe--index-filter
.Masz tutaj do czynienia z wieloma niezależnymi problemami.
Określanie dat innych niż „teraz”
Każde zatwierdzenie ma dwie daty: datę autora i datę osoby zatwierdzającej. Możesz zastąpić każdą z nich, podając wartości za pomocą zmiennych środowiskowych GIT_AUTHOR_DATE i GIT_COMMITTER_DATE dla każdego polecenia, które zapisuje nowe zatwierdzenie. Zobacz „Formaty daty” w git-commit (1) lub poniżej:
Jedynym poleceniem, które zapisuje nowe zatwierdzenie podczas normalnego użytkowania, jest polecenie git . Posiada również
--date
opcję, która pozwala bezpośrednio określić datę autora. Twoje przewidywane użycie obejmujegit filter-branch --env-filter
również wykorzystanie wyżej wymienionych zmiennych środowiskowych (są one częścią „env”, po której nazwa jest nazwana; patrz „Opcje” w git-filter-branch (1) i leżące u jej podstaw polecenie „hydrauliczne” git-commit -drzewo (1) .Wstawianie pliku do historii pojedynczego odwołania
Jeśli twoje repozytorium jest bardzo proste (tzn. Masz tylko jedną gałąź, bez tagów), prawdopodobnie możesz użyć git rebase do wykonania tej pracy.
W poniższych poleceniach użyj nazwy obiektu (skrót SHA-1) zatwierdzenia zamiast „A”. Nie zapomnij użyć jednej z metod „przesłonięcia daty” podczas uruchamiania git commit .
Jeśli chcesz zaktualizować A, aby zawierał nowy plik (zamiast tworzenia nowego zatwierdzenia w miejscu, w którym został dodany), użyj
git commit --amend
zamiastgit commit
. Wynik wyglądałby następująco:Powyższe działa tak długo, jak można nazwać zatwierdzenie, które powinno być rodzicem nowego zatwierdzenia. Jeśli naprawdę chcesz, aby nowy plik został dodany za pomocą nowego zatwierdzenia głównego (bez rodziców), potrzebujesz czegoś innego:
git checkout --orphan
jest stosunkowo nowy (Git 1.7.2), ale istnieją inne sposoby robienia tego samego, co działa na starszych wersjach Gita.Wstawianie pliku do historii wielu referencji
Jeśli twoje repozytorium jest bardziej złożone (tzn. Ma więcej niż jeden odnośnik (gałęzie, tagi itp.)), Prawdopodobnie będziesz musiał użyć git filter-branch . Przed użyciem git filter-branch powinieneś wykonać kopię zapasową całego repozytorium. Wystarczy proste archiwum tar całego działającego drzewa (w tym katalogu .git). git filter-branch wykonuje kopie zapasowe kopii zapasowej, ale często łatwiej jest odzyskać dane po niezupełnie właściwym filtrowaniu, po prostu usuwając
.git
katalog i przywracając go z kopii zapasowej.Uwaga: Poniższe przykłady używają polecenia niższego poziomu
git update-index --add
zamiastgit add
. Możesz użyć git add , ale najpierw musisz skopiować plik z jakiejś lokalizacji zewnętrznej do oczekiwanej ścieżki (--index-filter
uruchamia polecenie w tymczasowym drzewie GIT_WORK_TREE, które jest puste).Jeśli chcesz, aby nowy plik był dodawany do każdego istniejącego zatwierdzenia, możesz to zrobić:
Naprawdę nie widzę powodu, by zmieniać daty istniejących zatwierdzeń
--env-filter 'GIT_AUTHOR_DATE=…'
. Gdybyś go użył, uczyniłbyś to warunkowym, aby przepisał datę każdego zatwierdzenia.Jeśli chcesz, aby nowy plik pojawiał się tylko w zatwierdzeniach po pewnym istniejącym zatwierdzeniu („A”), możesz to zrobić:
Jeśli chcesz, aby plik został dodany za pomocą nowego zatwierdzenia, które ma być wstawione w środku twojej historii, musisz wygenerować nowy zatwierdzenie przed użyciem git filter-branch i dodać
--parent-filter
do git filter-branch :Możesz również zaaranżować, aby plik był dodawany po raz pierwszy w nowym głównym zatwierdzeniu: utwórz nowy główny zatwierdzenie za pomocą metody „osieroconej” z sekcji git rebase (przechwyć
new_commit
), użyj bezwarunkowego--index-filter
i--parent-filter
podobnego"sed -e \"s/^$/-p $new_commit/\""
.źródło
--index-filter
zastosowanie do zwróconych zatwierdzeńgit rev-list
? W tej chwili widzę filtr indeksu zastosowany do podzestawu rev-list. Doceń każdy wgląd.-- --all
do przetwarzania wszystkich zatwierdzeń dostępnych z dowolnego ref. Ostatni przykład pokazuje, jak zmienić tylko niektóre zatwierdzenia (wystarczy przetestować GIT_COMMIT pod kątem tego, co chcesz). Aby zmienić tylko określoną listę zatwierdzeń, możesz zapisać listę przed filtrowaniem (np.git rev-list … >/tmp/commits_to_rewrite
), A następnie przetestować członkostwo w filtrze (npif grep -qF "$GIT_COMMIT" /tmp/commits_to_rewrite; then git update-index …
.). Co dokładnie próbujesz osiągnąć? Możesz zacząć nowe pytanie, jeśli jest zbyt wiele do wyjaśnienia w komentarzach.import-directories.perl
Gitcontrib/
(lubimport-tars.perl
, lubimport-zips.py
…), aby utworzyć nowe repozytorium Git z twoich migawek (nawet z „Stare” znaczniki czasu). Wrebase
/filter-branch
techniki w mojej odpowiedzi są potrzebne tylko jeśli chcesz wstawić plik, który został „left out” historii istniejącego składowiska.Możesz utworzyć zatwierdzenie jak zwykle, ale kiedy zatwierdzasz, ustaw zmienne środowiskowe
GIT_AUTHOR_DATE
iGIT_COMMITTER_DATE
odpowiednie czasy danych.Oczywiście spowoduje to zatwierdzenie na końcu gałęzi (tj. Przed bieżącym zatwierdzeniem HEAD). Jeśli chcesz odsunąć go z powrotem w repozytorium, musisz się trochę rozkoszować. Powiedzmy, że masz tę historię:
I chcesz, aby twoje nowe zatwierdzenie (oznaczone jako „X”) pojawiło się na drugim miejscu :
Najłatwiejszym sposobem jest rozgałęzienie od pierwszego zatwierdzenia, dodanie nowego zatwierdzenia, a następnie zmiana bazy wszystkich innych zatwierdzeń na nowym. Tak jak:
źródło
GIT_AUTHOR_DATE='Fri Jul 26 19:32:10 2013 -0400' GIT_COMMITTER_DATE='Fri Jul 26 19:32:10 2013 -0400' git commit
2013-07-26T19:32:10
: kernel.org/pub/software/scm/git/docs/…THE_TIME='2019-03-30T8:20:00 -0500' GIT_AUTHOR_DATE=$THE_TIME GIT_COMMITTER_DATE=$THE_TIME git commit -m 'commit message here'
Wiem, że to pytanie jest dość stare, ale to właśnie dla mnie zadziałało:
źródło
--date
obsługuje także format daty względnej czytelny dla człowieka.git --date
zmodyfikuje tylko $ GIT_AUTHOR_DATE ... więc w zależności od okoliczności zobaczysz aktualną datę dołączoną do zatwierdzenia ($ GIT_COMMITTER_DATE)git show <commit-hash> --format=fuller
. Tam zobaczyszAuthorDate
datę, którą podałeś, aleCommitDate
rzeczywistą datę zatwierdzenia.W moim przypadku w czasie I uratował kilka wersji myfile jak myfile_bak, myfile_old, myfile_2010, tworzenie kopii zapasowych / myfile itp chciałem umieścić historię myfile w git przy użyciu ich daty modyfikacji. Więc zmień nazwę najstarszego na myfile,
git add myfile
a następniegit commit --date=(modification date from ls -l) myfile
zmień nazwę następnego najstarszego na myfile, kolejne polecenie git z opcją --data, powtórz ...Aby to nieco zautomatyzować, możesz użyć shell-foo, aby uzyskać czas modyfikacji pliku. Zacząłem od
ls -l
icut
, ale stat (1) jest bardziej bezpośredniźródło
--date
„Zastąp datę autora użytą w zatwierdzeniu”.git log
Data wydaje się być datą autora,git log --pretty=fuller
pokazuje zarówno datę ważności, jak i datę zatwierdzenia.git commit
Opcja--date
będzie modyfikować tylkoGIT_AUTHOR_DATE
nieGIT_COMMITTER_DATE
. Jak wyjaśnia Pro Git Book : „Autorem jest osoba, która pierwotnie napisała dzieło, a osoba odpowiedzialna to osoba, która jako ostatnia zastosowała dzieło”. W kontekście datGIT_AUTHOR_DATE
jest to data, w której plik został zmieniony, aGIT_COMMITTER_DATE
data, w której został zatwierdzony. Ważne jest, aby pamiętać, że domyślniegit log
wyświetla daty autora jako „Data”, ale następnie używa dat zatwierdzania do filtrowania, gdy podano--since
opcję.stat -c %y
w macOS (i innych wariantach BSD) jeststat -f %m
.Oto co mogę użyć, aby dokonać zmian na
foo
doN=1
dni w przeszłości:Jeśli chcesz, aby zobowiązać się do jeszcze starszej daty, powiedzmy 3 dni z powrotem, wystarczy zmienić
date
argumentudate -v-3d
.Jest to bardzo przydatne, gdy na przykład zapomnisz coś popełnić.
AKTUALIZACJA :
--date
akceptuje również wyrażenia takie jak--date "3 days ago"
lub nawet--date "yesterday"
. Możemy więc zredukować to do jednego wiersza polecenia:źródło
git --date
zmodyfikuje tylko $ GIT_AUTHOR_DATE ... więc w zależności od okoliczności zobaczysz aktualną datę dołączoną do zatwierdzenia ($ GIT_COMMITTER_DATE)git commit --amend --date="$(stat -c %y fileToCopyMTimeFrom)"
git commit --amend --date="$(date -R -d '2020-06-15 16:31')"
W moim przypadku podczas korzystania z opcji --date mój proces git się zawiesił. Być może zrobiłem coś strasznego. W rezultacie pojawił się plik index.lock. Więc ręcznie usunąłem pliki .lock z folderu .git i wykonałem, aby wszystkie zmodyfikowane pliki zostały zatwierdzone w minionych terminach i tym razem zadziałało. Dzięki za wszystkie odpowiedzi tutaj.
źródło
git commit --date
. Również twój przykładowy komunikat zatwierdzenia powinien zostać zmieniony, aby zniechęcić słabe wiadomości jednowierszowe, takie jak te @JstRoRRgit --date
zmodyfikuje tylko $ GIT_AUTHOR_DATE ... więc w zależności od okoliczności zobaczysz aktualną datę dołączoną do zatwierdzenia ($ GIT_COMMITTER_DATE)Aby dokonać zatwierdzenia, które wygląda tak, jakby było zrobione w przeszłości, musisz ustawić oba
GIT_AUTHOR_DATE
iGIT_COMMITTER_DATE
:gdzie
date -d'...'
może być dokładna data jak2019-01-01 12:00:00
lub względna jak5 months ago 24 days ago
.Aby zobaczyć obie daty w dzienniku git, użyj:
Działa to również w przypadku zatwierdzeń scalania:
źródło
Zawsze możesz zmienić datę na komputerze, dokonać zatwierdzenia, a następnie zmienić datę z powrotem i przesłać.
źródło
Lub po prostu użyj fałszywej historii git, aby wygenerować ją dla określonego zakresu danych.
źródło