给您的建议是有缺陷的。在中无条件设置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)中的“ Options”和基础的“ plumbing”命令git-commit) -tree(1)。
将文件插入单个引用历史记录
如果您的存储库非常简单(即,您只有一个分支,没有标签),则可以使用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提交(没有父项)添加新文件,那么您需要一些不同的东西:
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-branch。在使用git filter-branch之前,您应该制作整个存储库的备份副本。整个工作树(包括.git目录)的简单tar存档就足够了。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的变基节(捕获它new_commit
),使用无条件的--index-filter
,和--parent-filter
喜欢"sed -e \"s/^$/-p $new_commit/\""
。