Как мне сделать git commit в прошлом?

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

Мне сказали что-то вроде этого будет работать:

git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all  

7 ответов


советы вам были даны ущербна. Безоговорочно установка 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-branch (1) и основная команда "сантехника"git-commit-tree (1).

вставка файла в один ref история

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

в следующих командах используйте имя объекта (хэш SHA-1) фиксация вместо "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

вышеизложенное работает до тех пор, пока вы можете назвать фиксацию, которая должна быть родительской для вашей новой фиксации. Если вы действительно хотите, чтобы ваш новый файл добавляйтесь через новый root 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.

вставка файла в мульти -ref история

если ваш репозиторий более сложный (т. е. он имеет более одного ref (ветви, теги и т. д.)), то вам, вероятно, нужно будет использовать git фильтр-ветвь. перед использованием git filter-branch, вы должны сделать резервную копию всего репозитория. простой деготь архив всего вашего рабочего дерева (включая .git directory) достаточно. git filter-branch делает резервные копии ссылок, но часто легче восстановить из не совсем правильной фильтрации, просто удалив ваш .git каталог и восстановление его из резервной копии.

Примечание: в приведенных ниже примерах используется команда нижнего уровня git update-index --add вместо git add. Вы могли бы использовать в Git добавить, но сначала вам нужно скопировать файл из некоторого внешнего местоположения в ожидаемый путь (--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-branch и добавить --parent-filter к 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

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


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

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

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 как myfile_bak, myfile_old, myfile_2010, резервные копии / myfile и т.д. Я хотел поместить историю myfile в git, используя даты их модификации. Поэтому переименуйте самый старый в myfile,git add myfile, потом git commit --date=(modification date from ls -l) myfile, переименуйте следующий старейший в myfile, другой git commit с --date, повторите...

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

git commit --date="`stat -c %y myfile`" myfile

в моем случае, при использовании опции --date, мой процесс git разбился. Может, я сделал что-то ужасное. И в результате какой-то коэффициент.появился файл блокировки. Поэтому я вручную удалил .заблокировать файлы .папка git и выполняется, для всех измененных файлов, которые будут переданы в прошедшие даты, и на этот раз это сработало. Спасибо за все ответы здесь.

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

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

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

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

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

обновление: --date также принимает такие выражения, как --date "3 days ago" или даже --date "yesterday". Таким образом, мы можем свести его к одной строке команда:

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

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