Jak zrobić commit Git w przeszłości?

Konwertuję wszystko na Gita na własny użytek i znalazłem kilka starych wersji pliku już w repozytorium. Jak dodać go do historii w odpowiedniej kolejności zgodnie z "datą modyfikacji" pliku, aby mieć dokładną historię pliku?

Powiedziano mi, że coś takiego zadziała:

git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all  
Author: Dom, 2010-10-09

7 answers

Twoja rada jest błędna. Bezwarunkowo ustawienie GIT_AUTHOR_DATE w --env-filter zmieniłoby datę każdego commita. Ponadto, nietypowe byłoby użycie git commit wewnątrz --index-filter.

Masz tu do czynienia z wieloma, niezależnymi problemami.

Określanie dat innych niż"teraz"

Każdy commit ma dwie daty: datę autora i datę zatwierdzenia. Możesz nadpisać każdą z nich, dostarczając wartości za pomocą zmiennych środowiskowych GIT_AUTHOR_DATE i GIT_COMMITTER_DATE dla każdego polecenia, które pisze nowy commit. Zobacz "formaty daty" w git-commit (1) lub poniżej:

Git internal format = <unix timestamp> <time zone offset>, e.g.  1112926393 +0200
RFC 2822            = e.g. Thu, 07 Apr 2005 22:13:13 +0200
ISO 8601            = e.g. 2005-04-07T22:13:13

Jedynym poleceniem, które pisze nowy commit podczas normalnego użytkowania jest git commit. Posiada również opcję --date, która pozwala bezpośrednio określić datę autora. Twoje przewidywane użycie zawiera git filter-branch --env-filter również używa zmiennych środowiskowych wymienionych powyżej (są one częścią "env", po którym opcja jest nazwana; zobacz "opcje" w git-filter-branch(1) oraz podstawowe polecenie "plumbing" git-commit-tree(1).

Wstawianie pliku do pojedynczego ref Historia

Jeśli Twoje repozytorium jest bardzo proste (tzn. masz tylko jedną gałąź, bez znaczników), to prawdopodobnie możesz użyć git rebase do wykonania tej pracy.

W poniższych poleceniach użyj nazwy obiektu (SHA-1 hash) zatwierdzania zamiast "A". Nie zapomnij użyć jednej z metod "nadpisania daty" podczas uruchamiania git commit.

---A---B---C---o---o---o   master

git checkout master
git checkout A~0
git add path/to/file
git commit --date='whenever'
git tag ,new-commit -m'delete me later'
git checkout -
git rebase --onto ,new-commit A
git tag -d ,new-commit

---A---N                      (was ",new-commit", but we delete the tag)
        \
         B'---C'---o---o---o   master

Jeśli chcesz zaktualizować a, aby zawierał nowy plik (zamiast tworzyć nowy commit, w którym został dodany), użyj git commit --amend zamiast git commit. Wynik wyglądałby tak:

---A'---B'---C'---o---o---o   master

Powyższe działanie działa tak długo, jak długo możesz nazwać commit, który powinien być rodzicem twojego nowego commita. Jeśli chcesz, aby nowy plik został dodany przez nowy commit główny( bez rodziców), potrzebujesz czegoś nieco innego: {]}

B---C---o---o---o   master

git checkout master
git checkout --orphan new-root
git rm -rf .
git add path/to/file
GIT_AUTHOR_DATE='whenever' git commit
git checkout -
git rebase --root --onto new-root
git branch -d new-root

N                       (was new-root, but we deleted it)
 \
  B'---C'---o---o---o   master

git checkout --orphan jest stosunkowo nowy (Git 1.7.2), ale istnieją inne sposoby robienia tego samego , które działają na starszych wersjach Gita.

Wstawianie pliku do Multi-ref Historia

Jeśli Twoje repozytorium jest bardziej złożone (tzn. ma więcej niż jeden ref (gałęzie, znaczniki itp.)), wtedy prawdopodobnie będziesz musiał użyć git filter-branch. przed użyciem git filter-branch , należy wykonać kopię zapasową całego repozytorium.a simple tar archiwum całego drzewa roboczego (w tymGit directory) jest wystarczający. git filter-branch robi kopie zapasowe refs, ale często łatwiej jest odzyskać kopię z nie do końca odpowiedniego filtrowania, usuwając katalog .git i przywracając go z kopii zapasowej.

Uwaga: poniższe przykłady używają polecenia niższego poziomu git update-index --add zamiast git add. Możesz użyć git add, ale najpierw musisz skopiować plik z jakiejś zewnętrznej lokalizacji do oczekiwanej ścieżki (--index-filter uruchamia jego polecenie w tymczasowym GIT_WORK_TREE, które jest puste).

Jeśli chcesz, aby Twój nowy plik był dodawany do każdego istniejącego commita, możesz to zrobić:

new_file=$(git hash-object -w path/to/file)
git filter-branch \
  --index-filter \
    'git update-index --add --cacheinfo 100644 '"$new_file"' path/to/file' \
  --tag-name-filter cat \
  -- --all
git reset --hard

Nie widzę powodu, aby zmieniać daty istniejących commitów za pomocą --env-filter 'GIT_AUTHOR_DATE=…'. Gdybyś go użył, zmieniłbyś datę każdego commita.

Jeśli chcesz, aby nowy plik pojawiał się tylko w zatwierdzeniu po jakimś istniejącym zatwierdzeniu ("A"), możesz to zrobić to:

file_path=path/to/file
before_commit=$(git rev-parse --verify A)
file_blob=$(git hash-object -w "$file_path")
git filter-branch \
  --index-filter '

    if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$before_commit"') &&
       test -n "$x"; then
         git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
    fi

  ' \
  --tag-name-filter cat \
  -- --all
git reset --hard

Jeśli chcesz, aby plik został dodany przez nowy commit, który ma zostać wstawiony do środka twojej historii, musisz wygenerować nowy commit przed użyciem git filter-branch i dodać --parent-filter do git filter-branch :

file_path=path/to/file
before_commit=$(git rev-parse --verify A)

git checkout master
git checkout "$before_commit"
git add "$file_path"
git commit --date='whenever'
new_commit=$(git rev-parse --verify HEAD)
file_blob=$(git rev-parse --verify HEAD:"$file_path")
git checkout -

git filter-branch \
  --parent-filter "sed -e s/$before_commit/$new_commit/g" \
  --index-filter '

    if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$new_commit"') &&
       test -n "$x"; then
         git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
    fi

  ' \
  --tag-name-filter cat \
  -- --all
git reset --hard

Możesz również zaaranżować, aby plik został dodany jako pierwszy w nowym commicie root: utwórz nowy commit root za pomocą metody" orphan " z sekcji Git rebase (przechwyć go w new_commit), użyj bezwarunkowa --index-filter, a --parent-filter Jak "sed -e \"s/^$/-p $new_commit/\"".

 164
Author: Chris Johnsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-18 18:24:18

Możesz utworzyć commit jak zwykle, ale po zatwierdzeniu Ustaw zmienne środowiskowe GIT_AUTHOR_DATE i GIT_COMMITTER_DATE na odpowiednie okresy.

Oczywiście spowoduje to, że commit pojawi się na końcu twojej gałęzi (tj. przed aktualnym commitem głównym). Jeśli chcesz przesunąć go dalej w repo, musisz się trochę wykwintnie. Powiedzmy, że masz tę historię:

o--o--o--o--o

I chcesz, aby nowy commit (oznaczony jako "X") pojawił się second :

o--X--o--o--o--o

Najprostszy sposób będzie branch z pierwszego commita, Dodaj nowy commit, a następnie zmień wszystkie inne commity na nowe. Tak:

$ git checkout -b new_commit $desired_parent_of_new_commit
$ git add new_file
$ GIT_AUTHOR_DATE='your date' GIT_COMMITTER_DATE='your date' git commit -m 'new (old) files'
$ git checkout master
$ git rebase new_commit
$ git branch -d new_commit
 95
Author: mipadi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-09 15:16:12

Wiem, że to pytanie jest dość stare, ale to właśnie na mnie zadziałało:

git commit --date="10 day ago" -m "Your commit message" 
 51
Author: Hyder B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-09 19:31:48

W moim przypadku z czasem zapisałem kilka wersji myfile jako myfile_bak, myfile_old, myfile_2010, backups/myfile itp. Chciałem umieścić historię myfile w git używając ich dat modyfikacji. Więc zmień nazwę najstarszego na myfile, git add myfile, następnie git commit --date=(modification date from ls -l) myfile, Zmień nazwę następnego najstarszego na myfile, kolejny commit z --date, repeat...

Aby to nieco zautomatyzować, możesz użyć shell-foo, aby uzyskać czas modyfikacji pliku. Zacząłem od ls -l i cut, ale stat (1) jest bardziej bezpośrednie

git commit --date="`stat -c %y myfile`" myfile
 30
Author: skierpage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-14 19:20:38

W moim przypadku, podczas używania opcji --date, mój proces git uległ awarii. Może zrobiłem coś strasznego. I w rezultacie jakiś indeks.pojawił się plik blokady. Więc ręcznie usunięte .Zablokuj pliki z .git folder i wykonane, dla wszystkich zmodyfikowanych plików, które mają być committed w mijanych datach i to działało tym razem. Thanx za wszystkie odpowiedzi tutaj.

git commit --date="`date --date='2 day ago'`" -am "update"
 15
Author: JstRoRR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-30 11:03:45

Oto, czego używam do zatwierdzania zmian w foo na N=1 dni w przeszłości:

git add foo
git commit -m "Update foo"
git commit --amend --date="$(date -v-1d)"

Jeśli chcesz zobowiązać się do jeszcze starszej daty, powiedzmy 3 dni wstecz, po prostu zmień argument date: date -v-3d.

To naprawdę przydatne, gdy zapomnisz coś wczoraj popełnić, na przykład.

Aktualizacja: --date akceptuje również wyrażenia typu --date "3 days ago" lub nawet --date "yesterday". Możemy więc zredukować ją do jednej komendy liniowej:

git add foo ; git commit --date "yesterday" -m "Update"
 10
Author: Vilson Vieira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-28 13:43:38

Zawsze możesz zmienić datę na swoim komputerze, wprowadzić commit, następnie zmienić datę wstecz i wcisnąć.

 3
Author: Nik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-27 10:31:52