git – 在每次提交中更改邮件地址

参见英文答案 >
How to change the author and committer name and e-mail of multiple commits in Git?                                    32个

我使用错误的邮件地址使用源树做了几次提交(未推送).

为了纠正这个错误,我做了一些研究,发现这个脚本用一个好的邮件来编辑提交.
问题是,当我第一次从git中提取项目时,已有来自多个用户的200多个提交.

当我使用脚本时,它正确地恢复了我的邮件地址,但其他人被销毁了:

ex : a.my@mail.com became a.my@5030863e-2e11-0d4c-b7c1-a084646f5798

你知道我怎么能解决这个问题吗?

#!/bin/sh

git filter-branch -f --env-filter '

OLD_EMAIL="a.bbbb@5030863e-2e11-0d4c-b7c1-a084646f5798"
CORRECT_NAME="a.bbbb"
CORRECT_EMAIL="a.bbbb@mail.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

编辑1:

我在其他邮件地址上使用过该脚本

它纠正了以前的所有内容但是sourcetree告诉我主人是248up / 248down:

我怎么能得到这种状态?

EDIT2:

正如我所建议的那样

git branch -f master origin/master

它纠正了回购的状态(248up / 248down消失了)

但是我仍然有2倍的sourcetree历史,在紫色我们可以看到最后一次提交在遥远的回购(我修改了错误的邮件),从蓝色部分开始有正确的历史记录,最后我的本地提交(开发)分支和功能与良好的邮件):

最佳答案 由于你只有一些提交要做,而不是整个历史,我会手工使用git rebase -i -p和git commit –amend –author“a.jard< a.jard@mail. COM>”中.

It’s covered in this answer这不是公认的答案,但有两倍的选票.

至于为什么你得到你的脚本的结果,这是由于git的性质和rebase如何工作. rebase不会重写历史,也不能. git中的提交是不可变的.提交的ID与提交本身的内容相关联,包括日期,日志消息,作者和提交者等元数据. rebase写下新的历史.

这个难题的另一个关键是提交的ID是使用其父项的ID计算的.如果不更改子项,则无法更改父项.这使得git push和pull非常有效,如果我告诉你我已经提交ABC123并且如果你有提交ABC123我们都知道我们有相同的历史.

例如,假设您有一个包含五个提交的简单存储库.主人和起源/主人都指向E.

A - B - C - D - E [master] [origin/master]

B的电子邮件地址错误. A,C,D和E都很好.您运行filter-branch命令.它会看A,看看没有变化,不管它.它将查看B,更改提交者,并编写一个以A作为父项的新提交.我们称之为B1.

A - B - C - D - E [master] [origin/master]
 \
  B1

现在它看着C.没有什么可以改变,但它需要它的父亲B1.由于ID包含父ID,因此必须进行新的提交.

A - B - C - D - E [master] [origin/master]
 \
  B1 - C1

和D和E一样

A - B - C - D - E [master] [origin/master]
 \
  B1 - C1 - D1 - E1

完成,filter-branch将[master]移动到E1.

A - B - C - D - E [origin/master]
 \
  B1 - C1 - D1 - E1 [master]

这就是为什么在过去更改一个提交会导致其后的所有内容发生分歧.

因为该脚本的作者没有指示您限制git-filter-branch应该过滤哪些修订版,所以它完成了当前分支的整个历史记录.

幸运的是,您可以通过将master移回origin / master来撤消此操作.有几种方法可以做到这一点. git branch -f master origin / master是最简单的.

更新这涵盖了您的新问题,其中您的开发分支悬挂在已过滤的分支上.让我们从头开始.你有这种情况……

A - B - C - D - E [master] [origin/master]

你运行了git author-rewrite并完成了这个.

A - B - C - D - E [origin/master]
 \
  B1 - C1 - D1 - E1 [master]

您分离了master并开始进行新的提交.

A - B - C - D - E [origin/master]
 \
  B1 - C1 - D1 - E1 [master] - F - G - H [devel]

你运行了git branch -f master origin / master来撤消你的过滤器. git中的分支只是指向提交的标签,因此只移动了主标签.您的devel分支仍然悬挂在过滤的提交上.

A - B - C - D - E [origin/master] [master]
 \
  B1 - C1 - D1 - E1 - F - G - H [devel]

现在你需要得到devel和F,G和H挂掉主人.第一项业务是将devel转移到掌握.如果我们这样做,将很难再找到F,G和H.你可以写下ID,或者你可以用标签取出一些保险. git tag tmp devel.

A - B - C - D - E [origin/master] [master]
 \
  B1 - C1 - D1 - E1 - F - G - H [devel] <tmp>

现在使用git branch -f devel master将devel移动到master. tmp标记可以访问筛选的分支.

A - B - C - D - E [origin/master] [master] [devel]
 \
  B1 - C1 - D1 - E1 - F - G - H <tmp>

现在你可以使用git cherry-pick将每个单独的更改复制到devel.提交的内容不会改变,但是父母是,所以必须复制它们.

git checkout devel
git cherry-pick F^..tmp

为了解释F ^ ..tmp部分,我们想要从H到FF的所有内容.H说要包括H的父,但是排除F的父,那只是H和G.因为我们想在列表中包含F,我们使用F ^来排除F的父母.

你结束了这个.

A - B - C - D - E [origin/master] [master] - F1 - G1 - H1 [devel]
 \
  B1 - C1 - D1 - E1 - F - G - H <tmp>

一旦你检查好了,用git tag -d tmp删除tmp标签.

A - B - C - D - E [origin/master] [master] - F1 - G1 - H1 [devel]

不要担心,如果你搞砸了提交仍然存在几周,然后才会收集垃圾.

现在,您可以使用上面提到的rebase技术检查devel并修复您的提交.你会结束这件事.

A - B - C - D - E [origin/master] [master]
 \
  B2 - C2 - D2 - E2 - F2 - G2 - H2 [devel]

使用git branch -f master E2手动将master移动到E2.

A - B - C - D - E [origin/master]
 \
  B2 - C2 - D2 - E2 [master] - F2 - G2 - H2 [devel]

你仍然会分歧.仍然需要强制推动您的更改,其他所有人都必须强制推动.那部分是无法避免的.在推动历史后改变历史总是很混乱.

还有很多其他方法可以实现这一切.使用git filter-branch的一个优点是它将为您移动所有标记和分支.对于像你这样的小变化,对于新用户,我更喜欢小步骤.更容易理解发生了什么.

点赞