Change mail address in each commit

This question already has an answer here:

  • Change the author and committer name and e-mail of multiple commits in Git 29 answers

  • Since you only have a few commits to do, rather than the whole history, I would do it by hand using git rebase -i -p and git commit --amend --author "a.jard <a.jard@mail.com>" .

    It's covered in this answer which is not the accepted answer, but has double the votes.

    As to why you're getting the result you are with your script, it's due to the nature of git and how rebase works. rebase does not rewrite history, it can't. Commits in git are immutable. The ID of a commit is tied to the content of the commit itself including the meta data like the date, log message, author and committer. rebase writes new history.

    The other key to the puzzle is the ID of a commit is calculated using the ID of its parents. You cannot change the parent without also changing the children. This makes git push and pull very efficient, if I tell you I have commit ABC123 and if you have commit ABC123 we both know we have the same history.

    For example, let's say you have a simple repository with five commits like this. master and origin/master both point at E.

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

    B has the wrong email address. A, C, D and E are all fine. You run your filter-branch command. It will look at A, see there is no change, and leave it alone. It will look at B, change the committer, and write a new commit with A as the parent. Let's call it B1.

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

    Now it looks at C. There's nothing to change, but it needs its parent to B1. Because the ID includes the parent's ID, it must make a new commit.

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

    And the same thing with D and E.

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

    Done, filter-branch moves [master] to E1.

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

    And that is why changing one commit in the past will cause everything after it to diverge.

    Because the author of that script didn't instruct you to limit which revisions git-filter-branch should filter, it did the whole history of the current branch.

    Fortunately, you can undo this by moving master back to origin/master. There's several ways to do this. git branch -f master origin/master is simplest.

    UPDATE This covers your new problem where your development branch is left hanging off the filtered branch. Let's start from the beginning. You had a situation like this...

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

    You ran git author-rewrite and wound up with this.

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

    You branched off master and started making new commits.

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

    You ran git branch -f master origin/master to undo your filter. Branches in git are just labels pointing at commits, so only the master label was moved. Your devel branch is still hanging off the filtered commits.

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

    Now you need to get devel and F, G and H hanging off master. First order of business is to move devel to master. If we do that it will be difficult to find F, G and H again. You could just write down the IDs, or you can take out some insurance with a tag. git tag tmp devel .

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

    Now move devel to master with git branch -f devel master . The tmp tag keeps the filtered branch accessible.

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

    Now you can use git cherry-pick to copy each individual change to devel. The content of the commit won't change, but the parents are, so they must be copied.

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

    To explain the F^..tmp part, we want everything from H to F. F..H says to include the parents of H, but exclude the parents of F, that's only H and G. Since we want to include F in the list, we use F^ to exclude the parents of F.

    You wind up with this.

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

    Once you've checked it's ok, delete the tmp tag with git tag -d tmp .

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

    Don't worry, if you messed up the commits will still be there for weeks before they are garbage collected.

    Now you can check out devel and fix your commits using the rebase technique mentioned above. You'll wind up with this.

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

    Manually move master to E2 with git branch -f master E2 .

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

    You will still have diverged. Pushing your changes will still need to be forced, and everyone else will have to force pull. That part cannot be avoided. Changing history after it's been pushed is always messy.

    There are many other ways to accomplish all this. One of the advantages of using git filter-branch is it will move all tags and branches changed along the way for you. For small changes such as yours, and for new users, I prefer doing it in small steps. It's easier to understand what's going on.

    链接地址: http://www.djcxy.com/p/28492.html

    上一篇: 更改所有提交的提交元数据

    下一篇: 在每次提交中更改邮件地址