Вопрос

Я преобразую все в GIT для своего личного использования, и я нашел несколько старых версий файла, уже в репозитории. Как я могу посвятить его истории в правильном порядке в соответствии с «модифицированной датой» файла, чтобы у меня была точная история файла?

Мне сказали, что что -то подобное сработает:

git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all  
Это было полезно?

Решение

Совет, которым вам дали, недостаточно. Безоговорочно установка Git_author_date в --env-filter Перепишите дату каждого коммита. Кроме того, было бы необычно использовать git commit внутри --index-filter.

Вы имеете дело с несколькими независимыми проблемами здесь.

Указание дат, кроме «сейчас»

Каждый коммит имеет два дата: дата автора и дата коммиттера. Вы можете переопределить каждый, поставляя значения через переменные среды git_author_date и git_committer_date для любой команды, которая записывает новый коммит. Видеть «Форматы даты» в git-commit (1) или ниже:

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

Единственная команда, которая пишет новый коммит во время нормального использования, git commit. Анкет У него также есть --date Вариант, который позволяет вам напрямую указать дату автора. Ваше ожидаемое использование включает в себя git filter-branch --env-filter Также используются переменные среды, упомянутые выше (они являются частью «Env», после чего назван опция; см. «Варианты» в Git-Filter-Tranch (1) и основная команда "сантехника" Git-Cond-Tree (1).

Вставка файла в один рефери История

Если ваш репозиторий очень прост (т.е. у вас есть только одна ветвь, без тегов), то вы, вероятно, можете использовать git rebase сделать работу.

В следующих командах используйте имя объекта (HASH SHA-1) Commit вместо «A». Не забудьте использовать один из методов «переопределения даты» при запуске 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

Если вы хотели обновить A, чтобы включить новый файл (вместо того, чтобы создать новый коммит, где он был добавлен), затем используйте git commit --amend вместо git commit. Анкет Результат будет выглядеть так:

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

Вышесказанное работает так долго, как вы можете назвать фиксацию, который должен быть родителем вашего нового фиксации. Если вы действительно хотите, чтобы ваш новый файл был добавлен через новый CORT Commit (без родителей), то вам нужно что-то немного другое:

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 относительно новый (GIT 1.7.2), но есть другие способы сделать то же самое Это работает на более старых версиях Git.

Вставить файл в мульти-рефери История

Если ваш репозиторий более сложный (т.е. у него более одного реф (филиалы, тегов и т. Д.), то вам, вероятно, потребуется использовать GIT Filter-Tranch. Перед использованием GIT Filter-Tranch, вы должны сделать резервную копию всего вашего репозитория. Просто смол Архив всего вашего рабочего дерева (включая каталог .git) достаточно. GIT Filter-Tranch делает Backup Refs, но часто легче оправиться от не совсем правой фильтрации, просто удаляя .git Справочник и восстановление его из резервной копии.

Примечание. Приведенные ниже примеры используют команду нижнего уровня git update-index --add вместо git add. Анкет Вы могли бы использовать git add, но сначала вам нужно скопировать файл из какого -то внешнего местоположения на ожидаемый путь (--index-filter Запускает свою команду во временном git_work_tree, который пуст).

Если вы хотите, чтобы ваш новый файл был добавлен в каждый существующий коммит, то вы можете сделать это:

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

Я не вижу никаких причин, чтобы изменить даты существующих коммитов с --env-filter 'GIT_AUTHOR_DATE=…'. Анкет Если бы вы использовали его, вы бы сделали это условным, чтобы это переписывало дату для каждого коммита.

Если вы хотите, чтобы ваш новый файл появился только в коммитах после некоторого существующего коммита («A»), то вы можете сделать это:

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

Если вы хотите, чтобы файл был добавлен через новый коммит, который должен быть вставлен в середину своей истории, вам нужно будет генерировать новый коммит до использования GIT Filter-Tranch и добавить --parent-filter к GIT Filter-Tranch:

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

Вы также можете организовать, чтобы файл был впервые добавлен в новом корневом фиксации: создайте свой новый корневой коммит через метод «сирота» из git rebase раздел (захватить его в new_commit), используйте безусловный --index-filter, и а --parent-filter нравится "sed -e \"s/^$/-p $new_commit/\"".

Другие советы

Вы можете создать коммит как обычно, но когда вы совершаете, установите переменные среды GIT_AUTHOR_DATE и GIT_COMMITTER_DATE к соответствующим датам.

Конечно, это сделает коммит на кончике вашей отрасли (т. Е. Перед текущей головой Commit). Если вы хотите подтолкнуть его на дальше в репо, вы должны получить немного фантазии. Допустим, у вас есть эта история:

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

И вы хотите, чтобы ваш новый коммит (помеченный как «X») появился второй:

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

Самый простой способ - это перейти из первого коммита, добавить свой новый коммит, а затем переиграть все остальные коммиты поверх нового. Вот так:

$ 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

Я знаю, что этот вопрос довольно старый, но это то, что на самом деле сработало для меня:

git commit --date="10 day ago" -m "Your commit message" 

В моем случае со временем я спасил кучу версий мой файл Как myfile_bak, myfile_old, myfile_2010, резервные копии / myfile и т. Д. Я хотел поставить историю myfile в Git, используя свои даты модификации. Так переименуйте самые старые до MyFile, git add myfile, потом git commit --date=(modification date from ls -l) myfile, Переименовать следующий старый в MyFile, еще один коммит GIT -Date, повторить ...

Чтобы несколько автоматизировать, вы можете использовать Shell-Foo, чтобы получить время модификации файла. Я начал с ls -l и cut, но стат (1) более прямой

git commit --date="`stat -c %y мой файл`" мой файл

Ниже приведено то, что я использую для получения изменений на foo к N=1 Дни в прошлом:

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

Если вы хотите посвятить себя еще более старому свиданию, скажем, 3 дня назад, просто измените date Аргумент: date -v-3d.

Например, это действительно полезно, когда вы забываете что -то совершить вчера.

ОБНОВИТЬ: --date также принимает выражения, как --date "3 days ago" или даже --date "yesterday". Анкет Таким образом, мы можем уменьшить его до одной строки команды:

git add foo ; git commit --date "yesterday" -m "Update"

В моем случае, используя вариант -дат, мой процесс GIT разбился. Может быть, я сделал что -то ужасное. И в результате появился какой -то файл index.lock. Таким образом, я вручную удалил файлы .lock из .GIT папки и выполненные, для всех измененных файлов, которые должны быть совершены в пропущенные даты, и на этот раз это работало. Спасибо за все ответы здесь.

git commit --date="`date --date='2 day ago'`" -am "update"

Вы всегда можете изменить дату на своем компьютере, сделать коммит, затем изменить дату назад и нажмите.

Чтобы сделать коммит, который выглядит так, как это было сделано в прошлом, вы должны установить оба GIT_AUTHOR_DATE и GIT_COMMITTER_DATE:

GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '...'

куда date -d'...' может быть точной датой, как 2019-01-01 12:00:00 или относительно как 5 months ago 24 days ago.

Чтобы увидеть обе даты в журнале GIT:

git log --pretty=fuller

Или просто используйте командную строку Toolhttps: //github.com/artiebits/fake-git-ishistory, чтобы создать его для конкретного диапазона данных

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top