这个问题可能看起来很奇怪,但是在重写超过100次提交后我遇到了同步git历史记录的问题。
在我重写的机器上,一个简单的git fetch
同步了一切。
在另一台mac机器上,git sync
没有帮助,但在随机删除本地.git/
日志和引用文件然后发出git pull
后,历史记录得到了刷新。
但是,无论我在Windows机器上做什么,我都无法刷新项目历史记录。试了一下:
git reset --hard HEAD
& git fetch
git fetch --all
git pull
每次在Windows机器上,我都会获得与不同作者相同的提交的重复条目(我更改了作者字段)。
我使用本教程跟踪了大量的历史记录重写:
https://help.github.com/articles/changing-author-info/
Open Terminal.
Create a fresh, bare clone of your repository:
git clone --bare https://github.com/user/repo.git
cd repo.git
Copy and paste the script, replacing the following variables based on the information you gathered:
OLD_EMAIL
CORRECT_NAME
CORRECT_EMAIL
#!/bin/sh
git filter-branch --env-filter '
OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
view rawgit-author-rewrite.sh hosted with ❤ by GitHub
Press Enter to run the script.
Review the new Git history for errors.
Push the corrected history to GitHub:
git push --force --tags origin 'refs/heads/*'
Clean up the temporary clone:
cd ..
rm -rf repo.git
有没有人经历过大规模的git历史重写?如果是,其他团队成员刷新他们的git历史的步骤是什么?
答案 0 :(得分:4)
理解这里的问题的关键(或关键)是,在Git:
当你"重写历史记录"时,你没有 - 你可以不改变任何现有的提交。相反,您复制每个现有提交。 git filter-branch
做的是复制您请求的所有提交,最早的" (最祖先的)到#34;最新的" (最少祖先/最尖端)订单,按原样应用过滤器:
最后,这对于真正大规模的重写意味着你实际上有两个不同的存储库并排放置:旧的,旧的提交,新的,新的提交。在过滤过程结束时,git filter-branch
会将名称更改为指向新副本。
如果你有一个只有三次提交的小型存储库 - 让我们调用它们A
到C
- 和一个master
分支,并且所有三个提交都需要进行一些更改(s),你会有这个:
A--B--C [was the original master]
A'-B'-C' <-- master
新提交实际上是 new 提交。仍然使用旧提交的任何人仍然使用旧提交。他们必须停止使用这些提交并开始使用新的提交。
在某些情况下,您使用git filter-branch
指定的过滤器在原始提交中根本不会更改任何内容。在这种情况下 - 如果filter-branch
写入的 new 提交与原始提交一点一点地相同,那么,新提交实际上与旧提交相同承诺。如果我们查看同一个三提交原始存储库,但选择仅修改第二个B
提交的内容或元数据的过滤器,我们会改为:
A--B--C
\
B'-C' <-- master
作为最终结果。
请注意,即使过滤未更改任何有关原始C
的信息,也会发生。这是因为原始B
的某些内容已被更改,导致新的和不同的提交B'
。因此,当git filter-branch
复制C
时,它必须进行一次更改:副本C'
的父级是新B'
而不是原B
。
也就是说,git filter-branch
将A
复制到新的提交,但根本没有任何更改(甚至没有任何父信息),因此新的提交结果是重新使用原A
。然后它将B
复制到新的提交,并进行了更改,因此新提交现在为B'
。然后,它复制C
而不进行更改,将父级更改为B'
,并编写新的提交C'
。
如果您的过滤器仅对C
进行了更改,则git filter-branch
命令会将A
复制到自身,将B
复制到自身,将C
复制到C'
{1}},给予:
A--B--C
\
C' <-- master
一般来说,the easiest way for people to deal with a really massive upstream origin
rewrite is for them to discard their existing repositories entirely。也就是说,我们期望共享不超过一些原始提交:在大量重写的某个早期点,我们更改提交A
或其附近的提交,以便每次后续提交都必须被复制到新的提交。因此,创建 new 克隆可能并不比更新现有克隆更昂贵。它肯定更容易!
严格来说,这不是必要。作为&#34;下游&#34;对于消费者,我们可以运行git fetch
并获取所有新的提交及其更新的分支名称,以及可能更新的标记(在这里要特别小心,因为标签在默认情况下不会更新)。但由于我们有我们自己的分支名称,指向原始提交而不是新复制的提交,我们现在必须使每个我们的分支名称引用新的 - 复制提交,也许复制我们拥有的上游没有的提交(因此也没有复制)。
换句话说,我们可以,对于我们的每个分支,运行:
git checkout <branch>
git reset --hard origin/<branch>
使我们的 branch
名称作为其提示提交,与origin/branch
命名的提交相同。 (请记住,git fetch
强制更新所有我们的 origin/branch
名称,以匹配 branch
指向的{{{ 1}}。)
这相当于删除我们的每个分支并使用origin
重新创建它们。换句话说,它不会继续推进任何我们的提交,重写git checkout
的任何人都没有复制(因为他们不能,因为他们没有他们)。要继续我们的提交,我们必须做同样的事情deal with an upstream rebase。内置的fork-point代码是否会为你正确地执行 - 如果你的Git至少为2.0,那么它通常是针对一个单独的问题(并且已经在其他地方得到了回答)。 请注意,您必须为您希望继续提交的每个分支执行此操作。
答案 1 :(得分:0)
在第二台计算机上,首先运行git fetch
,而不是git pull
。然后,对于其历史记录被重写的每个分支,您需要执行git reset --hard HEAD
。请注意,此命令仅适用于当前分支。因此,如果历史重写影响了多个分支,则需要签出并重置每个分支。