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

时间:2014-12-29 17:02:17

标签: git bash email atlassian-sourcetree git-flow

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

为了纠正这个错误,我做了一些研究,发现这个脚本用好的邮件编辑提交。 问题是,当我第一次从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

EDIT1:

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

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

enter image description here

我怎么能获得这种状态?

EDIT2:

正如我所建议的

git branch -f master origin/master

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

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

enter image description here

1 个答案:

答案 0 :(得分:2)

由于您只有一些提交要做,而不是整个历史记录,我会使用git rebase -i -pgit 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我们都知道我们有相同的历史。

例如,假设您有一个包含五个提交的简单存储库。 master和origin / master都指向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最简单。

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

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>

现在将devel移动到使用git branch -f 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到F的所有内容。F..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的一个优点是它会为您移动所有标记和分支。对于像你这样的小变化,对于新用户,我更喜欢小步骤。它更容易理解发生了什么。