Як можна змінити часову позначку старого комітету в Git?


746

Відповіді на тему: Як змінити існуючі, незапущені коміти? опишіть спосіб внесення змін до попередніх повідомлень про фіксацію, які ще не були висунуті за течією. Нові повідомлення успадковують часові позначки оригіналів. Це здається логічним, але чи є також спосіб встановити час?



34
git commit --amend --reset-author
Ерік М. Шпренгель

Відповіді:


535

Використовуйте git filter-branchз фільтром env, який встановлює GIT_AUTHOR_DATEта GIT_COMMITTER_DATEдля конкретного хешу комітету, який ви хочете виправити.

Це призведе до недійсності цього та всіх майбутніх хешей.

Приклад:

Якщо ви хочете змінити дати вчинення 119f9ecf58069b265ab22f1f97d2b648faf932e0, ви можете зробити це приблизно так:

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'

4
Дивіться "ДАТИ ФОРМАТИ" kernel.org/pub/software/scm/git/docs/git-commit.html
Дастін

8
Це знайшло правильне значення, але лише встановлення цих змінних насправді не вплинуло на дату старого введення.
IQAndreas

36
Що ви маєте на увазі під "Це знецінить це та всі майбутні хеши".
EpicDavi

16
EpicDavi: Це означає, що вам доведеться змусити натиснути на будь-який віддалений сховище, і кожен, хто витягнув команду чи будь-які майбутні зобов’язання, повинен буде скинути і витягнути, або видалити і клонувати з нуля. Наскільки я знаю, немає жодного методу, який би обійшов це.
EriF89

4
Як і примітка для початківців, короткий хеш не працює в операторі if, використовуйте довгий SHA-1
40детективи

780

Ви можете зробити інтерактивну базу даних і вибрати редагування для комісії, дату якої ви хочете змінити. Коли процес ребазування припиняється, наприклад, для внесення змін до комісії, яку ви вводите, наприклад:

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

Після цього ви продовжуєте інтерактивну базу даних.

ОНОВЛЕННЯ (у відповідь на коментар studgeek): щоб змінити дату здійснення замість дати автора:

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

Рядки вище задають змінну середовища GIT_COMMITTER_DATE, яка використовується при внесенні змін.

Все перевірено в Git Bash.


22
@nschum --date = "" та --data "без дати тексту" - це все однаково, беручи дату зараз.
Пол Пладійс

12
версія git 1.7.7.1 за допомогою --date = "зараз" дає фатальний: недійсний формат дати: зараз
Арагорн

4
Коли здійснювати чиї дати ви хочете зміни є самою останньою фіксації, ви не повинні робити те rebase, що ви можете просто зробитиgit commit --amend
однойменному

7
Замість експорту GIT_COMMITTER_DATE = "" спробуйте зняти GIT_COMMITTER_DATE.
Марк Е. Хааз

2
Я використовую --no-edit, щоб можна було використовувати в автоматизованих сценаріях! + var fixedDate = strftime(new Date(), "%c"); + var result = shelljs.exec("git commit --amend --date=\"" + fixedDate + "\" --no-edit");
Марчелло де Продаж

392

Кращий спосіб впоратися з усіма цими пропозиціями в одній команді - це

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

Це встановить останнє зобов’язання та дату автора "прямо зараз".


22
Це чудово підходить для редагування конкретних комісій під час інтерактивної бази даних.
friederbluemle

2
Ви можете додати псевдонім до оболонки і для нього
kaleissin

14
Здається, що Git не знає формат дати, тому, щоб бути абсолютно правильним, вам доведеться зробити щось подібне:LANG= GIT_COMMITTER_DATE="`date`" git commit --amend --date "`date`"
Michał Góral

Я роблю це, коли перезаписую і розминаю гілку, тож вона створює єдиний комітет із оновленою часовою позначкою.
Люк Ересман

12
ви також можете просто зробити --date "now". Git> = 2 буде інтерпретувати це.
вісбукі

189

Просто роби git commit --amend --reset-author --no-edit. Для старих комісій ви можете зробити інтерактивну базу даних і вибрати editкоманду, дату якої потрібно змінити.

git rebase -i <ref>

Потім внесіть зміни до комісії --reset-authorта --no-editзмініть дату автора на поточну дату:

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

Нарешті продовжте інтерактивну базу даних:

git rebase --continue

5
хороший дзвінок у використанні --reset-author, він новий у git 1.6.6 (ref gitlog.wordpress.com/2010/01/13/git-1-6-6 )
Тім

1
Це чудово працює, щоб Github показав зобов’язання скасованого PR в правильному порядку, оскільки вони впорядковують їх за часовою міткою і без цього фокусу, часові позначки можуть бути однаковими.
Натан Лонг

4
Примітка --reset-authorбуде скинутий як Автор, так і Дата автора до цього часу.
wisbucky

чи змінить це одночасно "ДАТА КОМІТЕРА"?
luochen1990

134

Я написав для цього сценарій та пакет Homebrew. Супер простий в установці, ви можете знайти його на PotatoLabs/git-redateсторінці GitHub .

Синтаксис:

git redate -c 3

Вам просто потрібно запустити, git redateі ви зможете відредагувати всі дати in vim останніх 5 комітетів (також є -cопція, скільки комісій ви хочете повернути назад, вона просто за замовчуванням до 5). Повідомте мене, якщо у вас є якісь запитання, коментарі чи пропозиції!

введіть тут опис зображення


2
Чудові речі, навіть якщо мені довелося використовувати vim, а не нано
howdoyouturnthison

Дякуємо @Edmund за чудовий сценарій. Не вдалося побачити дату редагування in vi після того, як я запустив git redate -c. Я бачу лише% cI | XXXXXXXXXXXXXXXX | Початкова комісія. Чи можете ви допомогти? Спасибі
Кіем Нгуен

@KiemNguyen, ви можете спробувати просто git redate (без -c)?
bigpotato

4
повністю згодні з Міною і @howdoyouturnthison тут, чому б вам не зробити його редактором агностиком через змінну середовища EDITOR? (також я на Linux, а не на Mac ...)
ympostor

3
Дякую @Edmund! На всякий випадок у сценарію виникає проблема з обробкою значення за замовчуванням для COMMITS. Якщо його не встановлено, наступний код застосовує фільтри лише для (я думаю / знайденого) останнього комітету. "git filter-branch -f --env-filter" $ ENVFILTER "HEAD ~ $ COMMITS..HEAD> / dev / null"
Григорій Ентін

101

Кожне зобов’язання пов’язане з двома датами, датою вступника та датою автора. Ви можете переглянути ці дати за допомогою:

git log --format=fuller

Якщо ви хочете змінити дату автора та дату завершення останніх 6 комісій, ви можете просто скористатися інтерактивною базою даних:

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

Для всіх комісій, де ви хочете змінити дату, замініть pickна edit(або просто e), а потім збережіть і вийдіть із редактора.

Тепер ви можете внести зміни до кожної комісії, вказавши дату автора та дату введення документа у форматі ISO-8601:

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

Перша дата - дата вчинення, друга - дата автора.

Потім перейдіть до наступного комітету з:

git rebase --continue

Повторіть процес, поки ви не внесете зміни до всіх своїх зобов'язань. Перевірте свій прогрес за допомогою git status.


1
Я слідував за цим і опинився на "відірваній голові"!
Simon H

1
@Simon H Я знову перевірив свою відповідь, і вона працює добре. Вам слід було набрати щось інше, або ви вже були в відстороненій голові. Якщо ви хочете повернутися з відірваної голови, зробіть це git checkout name-of-current-branch.
Ортомала Локні

3
Це найкраща і найпростіша відповідь. Невеликий рада: використовувати --no-edit в git commit --amend --no-edit --date=2017-10-08T09:51:07тримати старе повідомлення коммітов.
Маріуш Павельський

2
Ви також можете оновити, GIT_COMMITTER_DATE як описано тут, eddmann.com/posts/…
smihael

2
@smihael Дякую за посилання. Я включив вашу відповідь у свою відповідь.
Ортомала Локні


44

Грунтуючись на theosp «s відповіді , я написав скрипт git-cdc(для зміни дати прийняття) , що я поклав в моємуPATH .

Ім'я важливе: в git-xxxбудь-якій точці вашого PATHвведення можна вводити:

git xxx
# here
git cdc ... 

Цей сценарій є bash, навіть у Windows (оскільки Git буде називати його зі свого середовища 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"

З цим ви можете вводити:

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

Це призведе до скидання автором / датою здійснення комісії перед HEAD ( @~) до вказаної дати.

git cdc @~ "2 days ago"

Це призведе до скидання автором / датою здійснення комісії перед HEAD ( @~) до тієї ж години, але 2 дні тому.


Ілля Семенов у коментарях згадує :

Для OS X ви також можете встановити GNU coreutils( brew install coreutils), додати його до PATH( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") та використовувати 2 days agoсинтаксис.


1
Для мене це працювало лише з цитуванням дати та часу в одній цитаті: git cdc @~ "2014-07-04 20:32:45інакше вона не визнає час і, отже, отримає час 00:00:00 (це стає третім аргументом).
peschü

3
Для OS X ви також можете встановити GNU coreutils ( brew install coreutils), додати його до PATH ( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"), а потім використовувати синтаксис "2 дні тому".
Ілля Семенов

1
@IlyaSemenov Цікаво. Я включив ваш коментар у відповідь для більшої наочності.
VonC

Я намагаюся використовувати ваш перший приклад, але я продовжую отримувати "фатальний: недійсний формат дати:". Який формат дати очікує Mac OS X?
usbsnowcrash

@usbsnowcrash не впевнений на mac. Чи працює другий приклад " 2 days ago"?
VonC

25

Як редагувати декілька дат фіксації

Інші відповіді не дуже зручні для редагування кількох дат фіксації. Я повернувся до цього питання через кілька років, щоб поділитися технікою.

Щоб змінити дати останніх 4 зобов’язань:

git rebase -i HEAD~4

Відредагуйте базу даних наступним чином, вставляючи execрядки, щоб змінити дати за потребою:

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"

Гарне використання --amend/ --dateваріанту. Простіше, ніж моя власна відповідь, використовуючи змінні середовища. Отримано.
VonC

Чи можна використовувати параметр поточної дати / часу?
приймає

Це GIT_AUTHOR_DATEлише оновлення .
Blaise

Re. 'Чи можливо використовувати поточну дату / час як параметр?': "Зараз" розуміється як дійсна дата, тому рядки для виконання вище станутьexec git commit --amend --no-edit --date "now"
Ендрю Річардс

20

якщо це попереднє останнє введення.

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

якщо ви вже натиснете на оргін і можете змусити використовувати:

git push --force 

якщо ви не можете примусити натиснути, і якщо він натиснений, ви не можете змінити фіксацію! .


18

Ось зручний псевдонім, який змінює і час, і авторський час останнього введення, на час, прийнятий date --date:

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

Використання: git cd <date_arg>

Приклади:

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

Редагувати: Ось більш автоматизована версія, яка перевіряє, чи є індекс чистим (без невмілих змін) і повторно використовує останнє повідомлення про фіксацію або не вдається інакше (нерозумно):

[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

Я створив цей пакет npm, щоб змінити дату старих комітів.

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

Використання зразка:

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

Вам буде запропоновано вибрати команду, яку ви хочете змінити, а потім ввести нову дату.

Якщо ви хочете змінити комісію за допомогою конкретного хеша, запустіть це git-change-date --hash=[hash]


Я просто хотів сказати, що це чудово і працює прекрасно. Дякую, ти врятував мені багато часу!
paranza

17

Наступна функція bash змінить час будь-якого введення в поточну гілку.

Будьте обережні, щоб не використовувати їх, якщо ви вже натиснули команду або використовуєте команду в іншій гілці.

# 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
У вас є помилка: if [[ -z "$commit" ]]->if [[ -z "$date_timestamp" ]]
blueFast

Приємно! Я рекомендую встановити GIT_COMMITTER_DATE=в кінці методу, щоб запобігти будь-яким подальшим ручним зобов’язанням щодо збереження зазначеної дати.
петля

@loopkin, GIT_COMMITTER_DATE встановлено лише для команди "git commit", тому не потрібно очищати її після цього
nimrodm

@nimrodm, я тільки тестував ще раз, і ти прав. Дякуємо, що вказали на це.
петля

12

Щоб змінити дату автора та дату здійснення:

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

10

Якщо ви хочете отримати точну дату чергового вчинення (скажімо, ви перезавантажили редагування комісії і хочете, щоб у ньому була дата початкової попередньої версії):

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

Це виправляє дату присвоєння HEAD рівно датою вчинення a383243 (додайте більше цифр, якщо є двозначності). Він також з’явиться вікно редактора, щоб ви могли редагувати повідомлення про фіксацію.

Це для дати автора, яка, як правило, вам важлива - дивіться інші відповіді щодо дати вчинення.


7

Якщо ви хочете виконати прийняту відповідь ( https://stackoverflow.com/a/454750/72809 ) у стандартному командному рядку Windows, вам потрібна наступна команда:

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"

Примітки:

  • Можливо, можна розділити команду на кілька рядків (Windows підтримує розділення рядків за допомогою символу carret ^), але мені це не вдалося.
  • Ви можете писати дати ISO, економлячи багато часу на пошук правильного дня тижня та загальних розчарувань щодо порядку елементів.
  • Якщо ви хочете, щоб дата автора та виконавця була однаковою, ви можете просто вказати на раніше встановлену змінну.

Величезне спасибі в блозі Коліна Свінгена . Хоча його код не працював для мене, він допоміг мені знайти правильне рішення.


7

Якщо комісія ще не натиснута, я можу використовувати щось подібне:

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

після цього git bash відкриє редактор із уже застосованою датою, тому вам потрібно просто зберегти його, ввівши в командному режимі VI редактор ": wq", і ви можете натиснути його


2
Просто додавши до приємної відповіді: якщо ви не хочете редагувати повідомлення про фіксацію (якщо ви просто хочете змінити дату виконання зобов’язань), скористайтеся --no-editопцією.
Антоніо Вініцій Менез Медей

Крім того, якщо комісія вже була натиснута, ви все одно можете натиснути змінену комітку за допомогою git push -f(примусове оновлення). Однак це може мати побічні ефекти. (особливо якщо багато людей мають місцевих клонів сховища)
Антоніо Вініцій Менез Медей


2

Вже є багато чудових відповідей, але коли я хочу змінити дату для кількох комісій за один день або за один місяць, я не знаходжу належної відповіді. Тож я створюю новий сценарій для цього з поясненнями, сподіваюся, що це комусь допоможе:

#!/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

Дата буде змінена:

AuthorDate: Wed Sep 13 13:39:41 2017 +0800
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.