我如何在过去做一个Git提交?

时间:2010-10-09 02:28:34

标签: git version-control repository git-commit

我正在将所有内容转换为Git供我个人使用,我发现存储库中已有一些旧版本的文件。如何根据文件的“修改日期”以正确的顺序将其提交到历史记录中,以便我有准确的文件历史记录?

我被告知这样的事情会起作用:

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

12 个答案:

答案 0 :(得分:175)

你给出的建议是有缺陷的。无条件地在--env-filter中设置GIT_AUTHOR_DATE会重写每次提交的日期。此外,在--index-filter内使用 git commit 是不常见的。

你在这里处理多个独立的问题。

指定“现在”以外的日期

每个提交都有两个日期:作者日期和提交者日期。您可以通过环境变量GIT_AUTHOR_DATE和GIT_COMMITTER_DATE为写入新提交的任何命令提供值来覆盖每个值。请参阅“Date Formats” in 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”的一部分,之后命名该选项;请参阅“Options” in git-filter-branch(1)和基础“plumbing”命令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

只要您可以将提交命名为新提交的父级,上述操作就会起作用。如果您确实希望通过新的根提交(无父母)添加新文件,那么您需要一些不同的东西:

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),但有other ways of doing the same thing适用于较旧版本的Git。

将文件插入多个参考历史记录

如果您的存储库更复杂(即它有多个ref(分支,标签等)),那么您可能需要使用 git filter-branch 在使用 git filter-branch 之前,您应该制作整个存储库的备份副本。整个工作树的简单 tar 存档(包括.git目录)就足够了。 git filter-branch 会生成备份引用,但通过删除.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-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

您还可以安排在新的根提交中首次添加文件:通过 git rebase 部分中的“孤儿”方法创建新的根提交(在{{1中捕获它) }}),使用无条件new_commit--index-filter --parent-filter

答案 1 :(得分:103)

您可以照常创建提交,但在提交时,请将环境变量GIT_AUTHOR_DATEGIT_COMMITTER_DATE设置为适当的日期时间。

当然,这将在您的分支的尖端(即,在当前HEAD提交之前)进行提交。如果你想在回购中再推回它,你必须有点花哨。假设你有这段历史:

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

答案 2 :(得分:75)

我知道这个问题已经过时了,但这对我来说真的有用了:

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

答案 3 :(得分:31)

在我的情况下,随着时间的推移,我将 myfile 的一堆版本保存为myfile_bak,myfile_old,myfile_2010,backups / myfile等。我想使用修改日期将myfile的历史记录放在git中。所以将最旧的重命名为myfile,git add myfile,然后重命名为git commit --date=(modification date from ls -l) myfile,将下一个最旧的重命名为myfile,将另一个git提交重命名为--date,重复...

要稍微自动化,可以使用shell-foo来获取文件的修改时间。我从ls -lcut开始,但stat(1)更直接

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

答案 4 :(得分:16)

就我而言,在使用--date选项时,我的git进程崩溃了。可能是我做了一件可怕的事。结果出现了一些index.lock文件。所以我手动删除了.git文件夹中的.lock文件并执行了,因为所有修改过的文件都要在传递的日期提交,这次就可以了。谢谢所有答案。

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

答案 5 :(得分:15)

以下是我过去在fooN=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"

答案 6 :(得分:14)

这是一个老问题,但我最近偶然发现了它。

git commit --date='2021-01-01 12:12:00' -m "message" 工作正常并在 GitHub 上进行了验证。

答案 7 :(得分:3)

您可以随时更改计算机上的日期,进行提交,然后更改日期并推送。

答案 8 :(得分:2)

要进行类似于过去的提交,必须同时设置WidgetFoo.ElementBetterWidget

struct S<T> { typealias U = T }

typealias TA = S<Int>

let x: TA.T // 'T' is not a member type of 'TA' (aka 'S<Int>')
let y: TA.U

其中GIT_AUTHOR_DATE可以是确切日期,例如GIT_COMMITTER_DATE,也可以是相对日期,例如GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '...'

要在git日志中查看两个日期,请使用:

date -d'...'

答案 9 :(得分:1)

或者仅使用fake-git-history为特定数据范围生成它。

答案 10 :(得分:0)

预步骤。

  • 将所有数据从远程拉取到本地存储库。

  • 我们正在使用 --amend 和 --date 开关。

具体命令如下:

$ git commit --amend --date="YYYY-MM-DD HH:MM:SS"

答案 11 :(得分:0)

  1. git --date 仅更改 GIT_AUTHOR_DATE,但许多 git 应用程序,例如 GitHub 显示 GIT_COMMITTER_DATE。确保也更改 GIT_COMMITTER_DATE
  2. git 不知道默认 UNIX 日期输出中的时区。确保以兼容格式(例如 ISO8601)格式化日期时间格式。

OS X 中的完整示例(将 GIT_COMMITTER_DATEGIT_AUTHOR_DATE 都更改为 4 小时前):

x=$(date -v -4H +%Y-%m-%dT%H:%M:%S%z); export GIT_COMMITTER_DATE=$x; git commit --amend --date $x