Jak zmienić znacznik czasu starego zatwierdzenia w Git?


746

Odpowiedzi na pytanie, jak zmodyfikować istniejące, niepoprawne zatwierdzenia? opisz sposób zmiany poprzednich komunikatów zatwierdzenia, które nie zostały jeszcze przekazane w górę. Nowe wiadomości dziedziczą znaczniki czasu oryginalnych zatwierdzeń. Wydaje się to logiczne, ale czy istnieje sposób na ponowne ustawienie czasów?



34
git commit --amend --reset-author
Erick M. Sprengel

Odpowiedzi:


535

Używaj git filter-branchz ustawionym filtrem env GIT_AUTHOR_DATEi GIT_COMMITTER_DATEdla określonego skrótu zatwierdzenia, który chcesz naprawić.

Spowoduje to unieważnienie tego i wszystkich przyszłych skrótów.

Przykład:

Jeśli chcesz zmienić daty zatwierdzenia 119f9ecf58069b265ab22f1f97d2b648faf932e0, możesz to zrobić za pomocą czegoś takiego:

git filter-branch --env-filter \
    'if [ $GIT_COMMIT = 119f9ecf58069b265ab22f1f97d2b648faf932e0 ]
     then
         export GIT_AUTHOR_DATE="Fri Jan 2 21:38:53 2009 -0800"
         export GIT_COMMITTER_DATE="Sat May 19 01:01:01 2007 -0700"
     fi'


8
Że znalazł właściwą wartość, ale po prostu ustawienie te zmienne faktycznie nie wydaje się wpływać na datę stary popełnić.
IQAndreas

36
Co rozumiesz przez „To unieważni to i wszystkie przyszłe hasze”.
EpicDavi

16
EpicDavi: Oznacza to, że będziesz musiał wymusić wypychanie do dowolnego zdalnego repozytorium, a każdy, kto wyciągnął zatwierdzenie lub jakiekolwiek przyszłe zatwierdzenia, będzie musiał zresetować i wyciągnąć lub usunąć i sklonować od zera. O ile mi wiadomo, nie ma metody, która obejdzie ten problem.
EriF89

4
Uwaga dla początkujących: krótki skrót nie działa w instrukcji if, użyj długiego SHA-1
40detectives

780

Możesz zrobić interaktywny rebase i wybrać edycję zatwierdzenia, którego datę chcesz zmienić. Gdy proces rebase zostanie zatrzymany w celu zmiany zatwierdzenia, które wpiszesz, na przykład:

git commit --amend --date="Wed Feb 16 14:00 2011 +0100"

Następnie kontynuujesz interaktywny rebase.

AKTUALIZACJA (w odpowiedzi na komentarz studgeek): aby zmienić datę zatwierdzenia zamiast daty autora:

GIT_COMMITTER_DATE="Wed Feb 16 14:00 2011 +0100" git commit --amend

Powyższe wiersze ustawiają zmienną środowiskową GIT_COMMITTER_DATE, która jest używana do zmiany zatwierdzenia.

Wszystko jest testowane w Git Bash.


22
@nschum --date = "" i --data "non-date-text" wszystkie dają to samo, biorąc pod uwagę datę teraz.
Paul Pladijs,

12
w wersji git 1.7.7.1 przy użyciu --date = "now" podaje fatal: nieprawidłowy format daty: teraz
Aragorn

4
Gdy data popełnienia którego chcesz zmienić to najnowszy popełnić, nie trzeba robić to rebase, można po prostu zrobićgit commit --amend
tytułowej

7
Zamiast eksportować GIT_COMMITTER_DATE = "", spróbuj cofnąć ustawienie GIT_COMMITTER_DATE.
Mark E. Haase

2
Używam --no-edit, abyś mógł korzystać z automatycznych skryptów! + var fixedDate = strftime(new Date(), "%c"); + var result = shelljs.exec("git commit --amend --date=\"" + fixedDate + "\" --no-edit");
Marcello de Sales

392

Lepszym sposobem obsługi wszystkich tych sugestii za pomocą jednego polecenia jest

LC_ALL=C GIT_COMMITTER_DATE="$(date)" git commit --amend --no-edit --date "$(date)"

Spowoduje to ustawienie daty ostatniego zatwierdzenia i autora na „teraz”.


22
Działa to świetnie, edytując określone zatwierdzenia podczas interaktywnej bazy.
friederbluemle

2
Możesz także dodać alias do powłoki
kaleissin

14
Wygląda na to, że Git nie rozpoznaje formatu daty w języku, więc aby być całkowicie poprawnym, musisz zrobić coś takiego:LANG= GIT_COMMITTER_DATE="`date`" git commit --amend --date "`date`"
Michał Góral

Robię to, gdy zmieniam bazę i zgniatam gałąź, więc tworzy ona jedno zatwierdzenie ze zaktualizowanym znacznikiem czasu.
Luke Ehresman,

12
możesz też po prostu zrobić --date "now". Git> = 2 to zinterpretuje.
wisbucky,

189

Po prostu zrób git commit --amend --reset-author --no-edit. W przypadku starszych zatwierdzeń możesz wykonać interaktywną editzmianę bazy i wybrać zatwierdzenie, którego datę chcesz zmodyfikować.

git rebase -i <ref>

Następnie zmień zatwierdzenie za pomocą --reset-authori, --no-editaby zmienić datę autora na bieżącą:

git commit --amend --reset-author --no-edit

Wreszcie kontynuuj z interaktywnym rebase:

git rebase --continue

5
dobre wezwanie do używania --reset-author, jest nowy w git 1.6.6 (ref gitlog.wordpress.com/2010/01/13/git-1-6-6 )
Tim Abell

1
Działa to dobrze, aby Github pokazywał zatwierdzenia PR opartego na rebased we właściwej kolejności, ponieważ porządkują je według znacznika czasu i bez tej sztuczki znaczniki czasu mogą być takie same.
Nathan Long,

4
notatka --reset-authorzresetuje teraz zarówno autora, jak i datę autora.
wisbucky

czy to jednocześnie zmieni „DATĘ ZOBOWIĄZANIA”?
luochen1990

134

Napisałem do tego skrypt i pakiet Homebrew. Bardzo łatwy w instalacji, można go znaleźć na PotatoLabs/git-redatestronie GitHub .

Składnia:

git redate -c 3

Musisz tylko uruchomić git redatei będziesz mógł edytować wszystkie daty w vim z ostatnich 5 zatwierdzeń (istnieje również -copcja określająca, ile zatwierdzeń chcesz cofnąć, domyślnie jest to 5). Daj mi znać, jeśli masz jakieś pytania, komentarze lub sugestie!

wprowadź opis zdjęcia tutaj


2
Świetne rzeczy, mimo że musiałem używać vima zamiast nano
howdoyouturnthison

Dzięki @Edmund za świetny skrypt. Nie mogłem zobaczyć daty edycji w vi po uruchomieniu git redate -c. Widzę tylko% cI | XXXXXXXXXXXXXXXX | Wstępne zatwierdzenie. Czy mógłbyś mi pomóc? Dzięki
Kiem Nguyen,

@KiemNguyen czy mógłbyś spróbować po prostu zmienić nazwę (bez -c)?
bigpotato

4
całkowicie zgadzam się z Miną i @howdoyouturnthison tutaj, dlaczego nie sprawisz, by edytor był agnostyczny poprzez zmienną środowiskową EDITOR? (też jestem na Linuksie, nie Mac ...)
Olympostor

3
Dzięki @Edmund! Na wszelki wypadek skrypt ma problem z obsługą domyślnej wartości dla COMMITS. Jeśli nie jest ustawiony, poniższy kod stosuje filtry tylko do (chyba / znalazłem) ostatniego zatwierdzenia. "git filter-branch -f --env-filter" $ ENVFILTER "HEAD ~ $ COMMITS..HEAD> / dev / null"
Grigory Entin

101

Każde zatwierdzenie jest powiązane z dwiema datami: datą osoby odpowiedzialnej i datą autora. Możesz zobaczyć te daty za pomocą:

git log --format=fuller

Jeśli chcesz zmienić datę autora i datę zatwierdzenia ostatnich 6 zatwierdzeń, możesz po prostu użyć interaktywnej bazy danych:

git rebase -i HEAD~6

.

pick c95a4b7 Modification 1
pick 1bc0b44 Modification 2
pick de19ad3 Modification 3
pick c110e7e Modification 4
pick 342256c Modification 5
pick 5108205 Modification 6

# Rebase eadedca..5108205 onto eadedca (6 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

W przypadku wszystkich zatwierdzeń, w których chcesz zmienić datę, zamień pickna edit(lub po prostu e), a następnie zapisz i zamknij edytor.

Możesz teraz zmienić każde zatwierdzenie, określając datę autora i datę zatwierdzającego w formacie ISO-8601:

GIT_COMMITTER_DATE="2017-10-08T09:51:07" git commit --amend --date="2017-10-08T09:51:07"

Pierwsza data to data zatwierdzenia, druga to data autora.

Następnie przejdź do następnego zatwierdzenia za pomocą:

git rebase --continue

Powtarzaj ten proces, dopóki nie zmienisz wszystkich swoich zobowiązań. Sprawdź swoje postępy za pomocą git status.


1
Poszedłem za tym i skończyłem na „oderwanej głowie”!
Simon H

1
@ Simon H Ponownie przetestowałem moją odpowiedź i działa dobrze. Powinieneś był napisać coś innego lub już byłeś zdystansowany. Jeśli chcesz wrócić z odłączonej głowy, zrób to git checkout name-of-current-branch.
Ortomala Lokni,

3
To najlepsza i najłatwiejsza odpowiedź. Mała wskazówka: użyj --no-edit w, git commit --amend --no-edit --date=2017-10-08T09:51:07aby zachować stary komunikat zatwierdzenia.
Mariusz Pawelski

2
Możesz także chcieć zaktualizować GIT_COMMITTER_DATE zgodnie z opisem tutaj eddmann.com/posts/…
smihael

2
@smihael Dzięki za link. Uwzględniłem twoją sugestię w mojej odpowiedzi.
Ortomala Lokni


44

Opierając się na theosp „s odpowiedź , napisałem skrypt o nazwie git-cdc(na bieżąco zmian commit), że umieścić w moim PATH.

Nazwa jest ważna: w git-xxxdowolnym miejscu PATHmożesz wpisać:

git xxx
# here
git cdc ... 

Ten skrypt jest bash, nawet w systemie Windows (ponieważ Git będzie go wywoływał ze środowiska msys )

#!/bin/bash
# commit
# date YYYY-mm-dd HH:MM:SS

commit="$1" datecal="$2"
temp_branch="temp-rebasing-branch"
current_branch="$(git rev-parse --abbrev-ref HEAD)"

date_timestamp=$(date -d "$datecal" +%s)
date_r=$(date -R -d "$datecal")

if [[ -z "$commit" ]]; then
    exit 0
fi

git checkout -b "$temp_branch" "$commit"
GIT_COMMITTER_DATE="$date_timestamp" GIT_AUTHOR_DATE="$date_timestamp" git commit --amend --no-edit --date "$date_r"
git checkout "$current_branch"
git rebase  --autostash --committer-date-is-author-date "$commit" --onto "$temp_branch"
git branch -d "$temp_branch"

Dzięki temu możesz wpisać:

git cdc @~ "2014-07-04 20:32:45"

Spowoduje to zresetowanie daty autora / zatwierdzenia zatwierdzenia przed HEAD ( @~) do określonej daty.

git cdc @~ "2 days ago"

Spowoduje to zresetowanie daty autora / zatwierdzenia przed HEAD ( @~) na tę samą godzinę, ale 2 dni temu.


Ilya Semenov wspomina w komentarzach :

W systemie OS X możesz także zainstalować GNU coreutils( brew install coreutils), dodać go do PATH( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"), a następnie użyć 2 days agoskładni „ ”.


1
Dla mnie to działało tylko z podaniem daty i godziny w jednym cytacie: w git cdc @~ "2014-07-04 20:32:45przeciwnym razie nie rozpoznałby godziny i dlatego uzyskałby czas 00:00:00 (staje się trzecim argumentem).
peschü

3
W systemie OS X możesz także zainstalować GNU coreutils ( brew install coreutils), dodać go do PATH ( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"), a następnie użyć składni „2 dni temu”.
Ilya Semenov,

1
@IlyaSemenov Interesujące. W odpowiedzi umieściłem twój komentarz dla większej widoczności.
VonC

Próbuję użyć Twojego pierwszego przykładu, ale ciągle pojawia się komunikat „Fatal: Nieprawidłowy format daty:”. Jakiego formatu daty oczekuje Mac OS X?
usbsnowcrash

@usbsnowcrash nie jestem pewien na Macu. Czy drugi przykład „ 2 days ago” działa?
VCC,

25

Jak edytować wiele dat zatwierdzenia

Inne odpowiedzi nie są zbyt wygodne w przypadku edycji kilku dat zatwierdzenia. Wróciłem do tego pytania po kilku latach, aby podzielić się techniką.

Aby zmienić daty ostatnich 4 zatwierdzeń:

git rebase -i HEAD~4

Zmodyfikuj bazę w następujący sposób, wstawiając execwiersze, aby odpowiednio zmodyfikować daty:

pick 4ca564e Do something
exec git commit --amend --no-edit --date "1 Oct 2019 12:00:00 PDT"
pick 1670583 Add another thing
exec git commit --amend --no-edit --date "2 Oct 2019 12:00:00 PDT"
pick b54021c Add some tests
exec git commit --amend --no-edit --date "3 Oct 2019 12:00:00 PDT"
pick e8f6653 Fix the broken thing
exec git commit --amend --no-edit --date "4 Oct 2019 12:00:00 PDT"

Ładne użycie opcji --amend/ --date. Prostsze niż moja odpowiedź przy użyciu zmiennych środowiskowych. Pozytywne.
VonC

Czy można użyć bieżącej daty / godziny jako parametru?
potwierdza

To GIT_AUTHOR_DATEtylko aktualizacje .
Blaise

Re. „Czy można użyć bieżącej daty / godziny jako parametru?”: „Teraz” jest rozumiane jako poprawna data, więc powyższe wiersze wykonawcze stałyby sięexec git commit --amend --no-edit --date "now"
Andrew Richards

20

jeśli jest to poprzednie ostatnie zatwierdzenie.

git rebase  -i HEAD~2
git commit --amend --date=now

jeśli już naciskasz na początek i możesz wymusić użycie:

git push --force 

jeśli nie możesz wymusić wypychania i jeśli jest on popychany, nie możesz zmienić zatwierdzenia! .


18

Oto wygodny alias, który zmienia czasy zatwierdzenia i autora ostatniego zatwierdzenia na czas zaakceptowany przez date --date:

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && GIT_COMMITTER_DATE=\"$d\" \
            git commit --amend --date \"$d\""

Stosowanie: git cd <date_arg>

Przykłady:

git cd now  # update the last commit time to current time
git cd '1 hour ago'  # set time to 1 hour ago

Edycja: Oto bardziej zautomatyzowana wersja, która sprawdza, czy indeks jest czysty (bez niezatwierdzonych zmian) i ponownie wykorzystuje ostatni komunikat zatwierdzenia lub w przeciwnym razie zawiedzie (niezawodny):

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && \
        git diff-index --cached --quiet HEAD --ignore-submodules -- && \
        GIT_COMMITTER_DATE=\"$d\" git commit --amend -C HEAD --date \"$d\"" \
        || echo >&2 "error: date change failed: index not clean!"

17

Utworzyłem ten pakiet npm, aby zmienić datę starych zatwierdzeń.

https://github.com/bitriddler/git-change-date

Przykładowe użycie:

npm install -g git-change-date
cd [your-directory]
git-change-date

Zostaniesz poproszony o wybranie zatwierdzenia, które chcesz zmodyfikować, a następnie o wprowadzenie nowej daty.

Jeśli chcesz zmienić zatwierdzenie przez określony skrót, uruchom to git-change-date --hash=[hash]


Chciałem tylko powiedzieć, że to jest świetne i pięknie działało. Dziękuję, zaoszczędziłeś mi dużo czasu!
paranza

17

Poniższa funkcja bash zmieni czas każdego zatwierdzenia w bieżącym oddziale.

Uważaj, aby nie używać, jeśli już wypchnąłeś zatwierdzenie lub korzystasz z zatwierdzenia w innej gałęzi.

# rewrite_commit_date(commit, date_timestamp)
#
# !! Commit has to be on the current branch, and only on the current branch !!
# 
# Usage example:
#
# 1. Set commit 0c935403 date to now:
#
#   rewrite_commit_date 0c935403
#
# 2. Set commit 0c935403 date to 1402221655:
#
#   rewrite_commit_date 0c935403 1402221655
#
rewrite_commit_date () {
    local commit="$1" date_timestamp="$2"
    local date temp_branch="temp-rebasing-branch"
    local current_branch="$(git rev-parse --abbrev-ref HEAD)"

    if [[ -z "$date_timestamp" ]]; then
        date="$(date -R)"
    else
        date="$(date -R --date "@$date_timestamp")"
    fi

    git checkout -b "$temp_branch" "$commit"
    GIT_COMMITTER_DATE="$date" git commit --amend --date "$date"
    git checkout "$current_branch"
    git rebase "$commit" --onto "$temp_branch"
    git branch -d "$temp_branch"
}

1
Masz tam błąd: if [[ -z "$commit" ]]->if [[ -z "$date_timestamp" ]]
blueFast

Miły! Poleciłbym ustawienie GIT_COMMITTER_DATE=na końcu metody, aby zapobiec dalszym ręcznym zatwierdzeniom w celu zachowania określonej daty.
loopkin

@loopkin, GIT_COMMITTER_DATE jest ustawiony tylko dla polecenia „git commit”, więc nie trzeba go później
usuwać

@nimrodm, właśnie testowałem ponownie i masz rację. Dzięki za zwrócenie na to uwagi.
loopkin

12

Aby zmienić zarówno datę autora, jak i datę zatwierdzenia:

GIT_COMMITTER_DATE="Wed Sep 23 9:40 2015 +0200" git commit --amend --date "Wed Sep 23 9:40 2015 +0200"

10

Jeśli chcesz uzyskać dokładną datę kolejnego zatwierdzenia (powiedz, że dokonałeś edycji bazy zmian w bazie danych i chcesz, aby miała datę oryginalnej wersji sprzed bazy):

git commit --amend --date="$(git show -s --format=%ai a383243)"

To poprawia datę zatwierdzenia HEAD, która jest dokładnie datą zatwierdzenia a383243 (dołącz więcej cyfr, jeśli występują niejednoznaczności). Pojawi się także okno edytora, abyś mógł edytować komunikat zatwierdzenia.

To jest data autora, na której zwykle Ci zależy - zobacz inne odpowiedzi dotyczące daty osoby odpowiedzialnej.


7

Jeśli chcesz wykonać zaakceptowaną odpowiedź ( https://stackoverflow.com/a/454750/72809 ) w standardowym wierszu poleceń systemu Windows, potrzebujesz następującego polecenia:

git filter-branch -f --env-filter "if [ $GIT_COMMIT = 578e6a450ff5318981367fe1f6f2390ce60ee045 ]; then export GIT_AUTHOR_DATE='2009-10-16T16:00+03:00'; export GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; fi"

Uwagi:

  • Może być możliwe podzielenie polecenia na wiele linii (Windows obsługuje dzielenie linii za pomocą symbolu carret ^), ale mi się nie udało.
  • Możesz pisać daty ISO, oszczędzając dużo czasu na znajdowaniu odpowiedniego dnia tygodnia i ogólnej frustracji związanej z kolejnością elementów.
  • Jeśli chcesz, aby data autora i autora była taka sama, możesz po prostu odwołać się do poprzednio ustawionej zmiennej.

Bardzo dziękuję na blogu Colina Svingena . Mimo że jego kod nie działał dla mnie, pomógł mi znaleźć właściwe rozwiązanie.


7

Jeśli zatwierdzenie nie zostało jeszcze wypchnięte, mogę użyć czegoś takiego:

git commit --amend --date=" Wed Mar 25 10:05:44 2020 +0300"

po tym git bash otwiera edytor z już zastosowaną datą, więc musisz go tylko zapisać, wpisując w trybie komend VI edytora „: wq” i możesz go wcisnąć


2
Wystarczy dodać do ładnej odpowiedzi: jeśli nie chcesz edytować wiadomości zatwierdzenia (jeśli chcesz tylko zmienić datę zatwierdzenia), skorzystaj z --no-editopcji.
Antonio Vinicius Menezes Medei

Ponadto, jeśli zatwierdzenie zostało już wypchnięte, nadal możesz wcisnąć zmienione zatwierdzenie za pomocą git push -f(wymuszonej aktualizacji). Może to jednak mieć skutki uboczne. (szczególnie jeśli wiele osób ma lokalne klony repozytorium)
Antonio Vinicius Menezes Medei


2

Jest już wiele świetnych odpowiedzi, ale kiedy chcę zmienić datę wielu zatwierdzeń w ciągu jednego dnia lub miesiąca, nie znajduję właściwej odpowiedzi. Tworzę więc nowy skrypt z wyjaśnieniem, mam nadzieję, że pomoże to komuś:

#!/bin/bash

# change GIT_AUTHOR_DATE for commit at Thu Sep 14 13:39:41 2017 +0800
# you can change the data_match to change all commits at any date, one day or one month
# you can also do the same for GIT_COMMITTER_DATE

git filter-branch --force --env-filter '

date_match="^Thu, 14 Sep 2017 13+"              

# GIT_AUTHOR_DATE will be @1505367581 +0800, Git internal format 
author_data=$GIT_AUTHOR_DATE;                   
author_data=${author_data#@}                  
author_data=${author_data% +0800}                # author_data is 1505367581     

oneday=$((24*60*60))

# author_data_str will be "Thu, 14 Sep 2017 13:39:41 +0800", RFC2822 format
author_data_str=`date -R -d @$author_data`      

if [[ $author_data_str =~ $date_match ]];
then
    # remove one day from author_data
    new_data_sec=$(($author_data-$oneday))
    # change to git internal format based on new_data_sec
    new_data="@$new_data_sec +0800"             
    export GIT_AUTHOR_DATE="$new_data"
fi
' --tag-name-filter cat -- --branches --tags

Data zostanie zmieniona:

AuthorDate: Wed Sep 13 13:39:41 2017 +0800
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.