Git:更改提交者信息

时间:2017-09-14 10:33:00

标签: git bash

我使用此脚本修改提交:

rm -rf repo

echo "clonning $1"
git clone $1 repo

cd repo
git checkout dev

echo "setting remote origin to $2"
git remote set-url origin $2

array=( 'email1@gmail.com' 'email2@gmail.com' )
for OLD_EMAIL in "${array[@]}"
do
  echo $OLD_EMAIL
  git filter-branch -f --env-filter '
  CORRECT_NAME="New name"
  CORRECT_EMAIL="new@email.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 -- --tags
done
echo "Authors list:"
git log --format='%cE' | sort -u
echo -n "Push to destination (y/n)? "
read answer
if echo "$answer" | grep -iq "^y" ;then
    git push
else
    echo Aborted
fi

cd ../

它从第一个回购中提取数据,修改提交者信息并推送到第二个回购。

如果有人直接提交第二个回购,问题就出现了。如何将这些更改应用于第一个回购?

2 个答案:

答案 0 :(得分:6)

如果我正确理解您的问题(阅读评论后),您的回购目前看起来像这样:

Initial State

第一个回购(广告)中的提交已被修改以创建备用提交(a' -d'),这些提交被推入第二个回购,然后添加了其他提交,(例如)。 / p>

重新编辑您的历史记录

因为您在两个回购邮件中的身份信息之间没有1:1的关系,因此尝试修改' -d'使用filter-branch以恢复原始历史记录,而理论上可能,将需要一种能够肯定地识别原始提交的方法'没有确定提交(其哈希)所需的一条信息。

提交基本上由几条信息组成:

  1. 树的哈希
  2. 提交的父级的哈希值
  3. 作者的身份信息
  4. 创作的时间戳
  5. 提交者的身份信息
  6. 提交的时间戳
  7. 提交消息
  8. 所有信息的大小
  9. 所有这些都经过哈希处理,以便为您的提交创建唯一标识符。改变了2,3,5和8之后,我们留下了树,这个树不一定是唯一的,时间戳不一定是唯一的,而提交消息也不一定是唯一的。

    你可以通过比较树和其中一个时间戳来获得一个不错的匹配,所以让我们为那个场景编写一些伪代码。

    # create a variable to hold the information from teh current commit
    pseudoidentifier=$TREE + $AUTHOR_TIMESTAMP
    
    # go to the first repo
    cd /path/to/firstrepo
    
    # output the log | grep to search | sed to remove everything after delimeter
    oldhash=`git log --format="{hash}~{tree}{authortimestamp}" | grep pseudoidenfier | sed "s/~.+$//"`
    
    # get the new identity using a custom formatted show command
    newidentity=`git show -q --format="{formatted identity}" $oldhash`
    
    # parse out the name and email, probably with sed
    CORRECT_NAME=`sed 's/pattern//' $newidentity`
    CORRECT_EMAIL=`sed 's/pattern//' $newidentity`
    
    # go to the second repo
    cd /path/to/secondrepo
    
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
    

    不幸的是,写入速度慢,测试困难且耗时。可能需要多次重新运行整个事物。因为你的最终目标是重新统一代码。还有其他一些选项可能会减少头痛并且速度更快。特别是如果你确实需要保持第二个回复,身份更新完好无损。

    替代方法

    如果没有共同的历史记录,您仍然可以使用更多手动方式将两者同步。在这种情况下,我建议使用以下三种方法。

    一点前期工作

    在开始之前,我们可以检查d和d'确实完全相同。我们可以使用git show命令来执行此操作:

    $ git show -q --format="%T" d
    a017285da45ec06fc744815f33a2e22627f4a799
    $ git show -q --format="%T" d'
    a017285da45ec06fc744815f33a2e22627f4a799
    

    此命令将输出提交指向的树对象,如果两个树匹配,则您将处理相同的代码。完全可能在没有匹配代码库的情况下执行以下过程,但您可能必须解决该情况下的冲突。这一步真的只是告诉你两者将如何轻松融合在一起。

    Cherry-Pick方法

    如果您最初修改提交的repo完好无损,则可以将两者中的分支提取到一个repo中,并尝试使用cherry-pick复制提交。

    git checkout <branch at d>
    git cherry-pick d'...g
    

    (注意语法是3个点)这将在(但不包括)d&#39;之后应用每次提交的更改。直到并包括g到d。创建新提交e&#39; -g&#39;。

    History after cherry-pick

    补丁方法

    如果您没有简单的方法将更改从两个分支转换为单个仓库,您可以为第二个仓库中的提交创建一系列补丁并将其应用到第一个仓库。

    在第二个回购

    git checkout <branch of g>
    git format-patch --output-directory <dir> d'...g
    

    (同样,语法是3个点)这将在(并且不包括)d&#39;之后输出每个提交的一系列补丁文件。直至并包括g。然后将这些文件复制到第一个存储库中可以获取这些文件的位置。

    在第一个回购

    git checkout <branch of d>
    git am /path/to/patches/*
    

    你最终会在樱桃采摘方法的同一个地方结束。

    History after patch

    创建嫁接

    如果存在很多冲突并且您不需要保留身份更改信息,您也可以使用git replace执行移植。

    git replace --graft e d
    

    这将创建一个提交e的副本,其中d作为父项,并添加一个表示使用e&#39;每当它试图访问e时提交。有效地使d成为两者的共同祖先,并允许您执行传统的合并(h)。

    enter image description here

    然后是什么?

    在没有共同历史记录的同时保留两个repos将始终导致这样的问题,并且随着两者缓慢分歧(例如,当你解决冲突时)它们会变得更糟。随着时间的推移,这两种方法都需要越来越多的资源来维护这两个回购。

    我建议一旦两个repos同步,选择其中一个并从那时起专门使用那个。如果您需要两个遥控器,只需将该回购推送给它们。然后,您可以轻松地使用许多经过验证的真实工作流程来维护两个回购。

    如果这不是一个选项,我建议一丝不苟地检查两个回购头的树木,以验证它们是否经常一点一点地相同。

答案 1 :(得分:0)

你有两种选择来完成这项工作:

  1. 如果您信任这些用户,可以让他们更改他们的电子邮件(只有这个git repo或所有回购,为所有回购添加--global
  2. git config user.email email@server.com
    
    1. 如果您想通过预提交git钩子强制执行它,您将添加到第二个存储库并让它们全部拉出新的更新。 有关详情,请访问herehere