4

これは現在、私たちのプロジェクトの 1 つで gitk がどのように見えるかです:

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

これは、リモート ブランチで単一の「git マージ」が実行された後に発生したようです。理由や何が起こっているのかはわかりません。ここで何が起こったのか分かりますか?

さらに重要なことは、それを修正するための最良の方法は何ですか? これらのマージ コミットは空ですが、「git rebase -i」を実行すると、通常、マージ コミットは表示されないようです。

最も重要なことは、履歴を他のクローンと互換性がないようにしないことです。つまり、履歴をプル/プッシュ/マージできるようにする必要があります。それは可能ですか?

4

1 に答える 1

3

git pullこれは、誰かが(または、同等に、git fetchおよび)を使用してプロジェクトを更新した結果ですgit merge。リポジトリが次のようになっていると想像してください。

o --- o ---o[オリジン/マスター]
         \
          A --- B ---C[マスター]

つまり、元のリポジトリにあったものに加えて、コミットを実行ABましCた。

その間に、他の誰かが変更を加えて共有リポジトリにプッシュします。次にリポジトリを実行git fetchすると、次のようになります。

o --- o --- o --- D --- E ---F[オリジン/マスター]
         \
          A --- B ---C[マスター]

ここで、実行するとgit merge(覚えておいてください:の後には)git pullgit 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[マスター]

さて、これを続ければ(そして多くの人がこれを続ければ)、あなたはあなたの写真のような木になってしまうでしょう。これは「間違っている」わけではありませんが、開発履歴を追跡するのが非常に難しいため、多くの人がそれを嫌います。

この問題の解決策は、人々にリベースするように教えることです。リベースすると、(ご指摘のとおり)役に立たないマージコミットがリモートになり、はるかにクリーンな履歴が得られます。上記の場合、線形の開発履歴になります。それをフォローするのははるかに簡単です。ただし、リベースした後、コードを再構築して再テストする必要があることを知っておく必要があります...コードが簡単にマージされたからといって、結果が正しいとは限りません。

中央リポジトリを使用して公式の開発ラインを共有している場合は、これらの自動(「愚かな」/「役に立たない」)マージコミットを検出してプッシュを拒否する事前受信フックを実装できます。 。実際には、フックでデフォルトのマージコミットメッセージを検索する必要があります...したがって、本当にマージコミットを維持したい場合は(場合によってはそれが理にかなっています)、少なくともインテリジェントなコミットメッセージを作成する必要があります。

これがフックの例です。私は余分なものをたくさん取り除いたので、それをテストすることができませんでした。

#!/ bin / bash

#このスクリプトは、Gnomeのpre-receive-check-policyフックに基づいています。
#このスクリプトは、無関係なマージコミットを*のみ*チェックします。

#一部のメッセージで使用
server = git.wherever.com

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

in_import(){
    test -e "$ GIT_DIR /pending"
}

force(){
    test -n "$ GNOME_GIT_FORCE"
}

check_commit(){
    commit = $ 1

    subject = "$(git log $ commit -1 --pretty = format:%s)"
    if expr "$ subject":"。*Mergebranch。*of。*\(git \ | ssh \):"> / dev / null 2>&1; それから
          もしも !in_import &&!強制; それから
                猫&2
---
コミット:

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

--rebaseなしで「gitpull」と入力して作成されたようです
ローカルで変更した場合のオプション。'gitpull--rebase'を実行しています
問題を修正します。次に、「gitpush」をもう一度試してください。参照してください:

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

check_ref_update(){
    oldrev = $ 1
    newrev = $ 2
    refname = $ 3

    change_type = update
    if expr $ oldrev: "^ 0 \ + $"> / dev / null 2>&1; それから
    change_type = create
    fi

    if expr $ newrev: "^ 0 \ + $"> / dev / null 2>&1; それから
          if [x $ change_type = xcreate]; それから
             #無効な参照を削除し、許可する
                0を返す
          fi
          change_type = delete
    fi

    ケース$refnamein
     refs / heads / *)
        #ブランチの更新
        branchname = $ {refname#refs / heads /}

        range =
        #このブランチアップデートで導入された新しいコミットについては、
        #よくある間違いを見つけるためにいくつかのチェックを実行します。
        #
        #ここでの表現はpost-receive-notify-ciaと同じです。私たちは取る
        #リポジトリ内のすべてのブランチ、「^ / ref / heads / branchname」、その他
       #実際にコミットしているブランチよりも、コミットを除外する
       #間のコミットのリストからそれらのブランチにすでにあります
       #$oldrevと$newrev。

        if [-n "$ range"]; それから
        $(git rev-parse --symbolic-full-name --not --branches|\にマージされた場合
                    egrep -v "^ \ ^ $ refname $" | \
            git rev-list --reverse --stdin "$ range"); 行う
            check_commit $ merged
        終わり
        fi
        ;;
    esac

    0を返す
}

if [$#= 3]; それから
    check_ref_update $ @
そうしないと
    oldrevnewrevrefnameを読みながら; 行う
    check_ref_update $ oldrev $ newrev $ refname
    終わり
fi

出口0
于 2010-02-18T19:52:07.140 に答える