4

这是 gitk 目前在我们的一个项目中的样子:

https://dl.dropbox.com/u/2582508/gitk.png

显然,据我们所知,这发生在使用远程分支完成单个“git merge”之后 - 我们不确定为什么或发生了什么。知道这里发生了什么吗?

更重要的是,修复它的最佳方法是什么?这些合并提交是空的,但是在执行“git rebase -i”时,合并提交通常似乎不会出现。

最重要的是,我不想让历史与其他克隆不兼容,即他们应该仍然能够拉/推/合并它。这甚至可能吗?

4

1 回答 1

3

这是有人使用git pull(或,等效地,git fetchgit merge)更新他们的项目的结果。想象一下,您的存储库如下所示:

o---o---o [起源/主人]
         \
          A---B---C [大师]

也就是说,您已经完成了 commits AB并且C在原始仓库中的内容之上。

与此同时,其他人进行更改并将其推送到共享存储库。如果您随后运行git fetch您的存储库,则如下所示:

o---o---o---D---E---F [起源/主人]
         \
          A---B---C [大师]

现在,如果你运行git merge(请记住:git pull后面git fetch跟着git merge)。你会有这个:

o---o---o---D---E---F [起源/主人]
         \ \
          A---B---C---G [大师]

假设一切顺利,G可能只是一个“愚蠢的”合并提交;从技术上讲,状态G是不同的FC因此必须以不同的方式考虑。

现在,如果你推动这个改变,你会得到这个:

o---o---o---D---E---F
         \ \
          A---B---C---G [起源/主人]

如果你继续开发,你会得到这个:

o---o---o---D---E---F
         \ \
          A---B---C---G [起源/主人]
                       \
                        H---I---J [大师]

现在,如果您继续这样做(并且如果很多人继续这样做),您最终会得到一棵像您图片中的树一样的树。这不是“错误的”,但很多人不喜欢它,因为它使开发历史非常难以遵循。

解决这个问题的方法是教人们rebase。变基将(如您所述)远程无用的合并提交并为您提供更清晰的历史记录。在上面的例子中,你最终会得到一个线性的发展历史。这更容易遵循。但是,您需要知道,在 rebase 之后,您需要重新构建和重新测试您的代码......仅仅因为代码容易合并并不意味着结果是正确的。

如果您使用中央存储库来共享官方开发线,您可以实现一个 pre-receive 钩子来检测这些自动(“愚蠢”/“无用”)合并提交并拒绝推送 - 强制用户要么变基. 实际上,您希望钩子查找默认的合并提交消息......所以,如果您确实想保留合并提交(有时这是有道理的),您至少必须编写一个智能提交消息。

这是一个示例钩子。我去掉了一堆额外的东西,所以我没有去测试它。

#!/bin/bash

# 这个脚本基于 Gnome 的 pre-receive-check-policy 钩子。
# 这个脚本*仅*检查无关的合并提交。

# 在一些消息中使用
服务器=git.wherever.com

GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)

in_import() {
    测试 -e "$GIT_DIR/待定"
}

强迫(){
    测试 -n "$GNOME_GIT_FORCE"
}

check_commit() {
    提交=$1

    主题="$(git log $commit -1 --pretty=format:%s)"
    if expr "$subject" : ".*Merge branch.*of.*\(git\|ssh\):" > /dev/null 2>&1; 然后
          如果 !in_import && !强迫; 然后
                猫 &2
---
提交:

EOF
        git log $commit -1 >&2
        猫 &2

看起来它是通过键入没有 --rebase 的 'git pull' 生成的
当您进行本地更改时的选项。现在运行 'git pull --rebase'
将解决问题。然后请再次尝试“git push”。请参见:

  http://live.gnome.org/Git/Help/ExtraMergeCommits
---
EOF
        1号出口
          菲
    菲
}

check_ref_update() {
    旧版本=$1
    新版本=$2
    参考名=$3

    更改类型=更新
    if expr $oldrev : "^0\+$" > /dev/null 2>&1; 然后
    更改类型=创建
    菲

    if expr $newrev : "^0\+$" > /dev/null 2>&1; 然后
          如果 [ x$change_type = xcreate ] ; 然后
             # 删除无效的引用,允许
                返回 0
          菲
          更改类型=删除
    菲

    案例 $refname 在
     裁判/头/ *)
        # 分支更新
        分支名称=${refname#refs/heads/}

        范围=
        # 对于此分支更新引入的新提交,我们希望
        # 运行一些检查以发现常见错误。
        #
        # 这里的表达式和 post-receive-notify-cia 中的一样;我们采取
        # repo 中的所有分支,如“^/ref/heads/branchname”,其他
       # 比我们实际提交的分支,并排除提交
       # 已经在提交列表中的那些分支上
       # $oldrev 和 $newrev。

        如果 [ -n "$range" ] ; 然后
        对于合并在 $(git rev-parse --symbolic-full-name --not --branches | \
                    egrep -v "^\^$refname$" | \
            git rev-list --reverse --stdin "$range"); 做
            check_commit $合并
        完毕
        菲
        ;;
    经社理事会

    返回 0
}

如果 [ $# = 3 ] ; 然后
    check_ref_update $@
别的
    同时读取 oldrev newrev refname;做
    check_ref_update $oldrev $newrev $refname
    完毕
菲

出口 0
于 2010-02-18T19:52:07.140 回答