2010-11-09 9 views
24

Eine Weile zurück I asked our developers to use rebase instead of merge before pushing. Durch das Entfernen trivialer Zusammenführungen wird das Commit-Diagramm viel einfacher nachvollzogen (zB gitk, git log).Block Push der trivialen Verschmelzung zu Git-Server

Manchmal Leute immer noch versehentlich triviale Zusammenführungen, dann drücken. Hat jemand Tipps oder Tricks zum Schreiben eines serverseitigen Hooks, der triviale Zusammenführungen blockiert?

Mit "trivial merge" meine ich eine Zusammenführung ohne Konflikte. Here's an example und here's a better explanation of a trivial merge in git.

Update Mi 10 November 01:26:41 UTC 2010: tolle Kommentare, alle! Vielen Dank.

  • Beachten Sie Folgendes: alles, was ich wirklich Leute bin gefragt ist, dies zu tun:
    • wenn git pull --ff-only ausfällt, tun git pull --rebase statt git pull
  • git.git hat nur ein oder zwei Committer, oder? Theoretisch sollte es einfach sein, dem Commit-Diagramm zu folgen, aber es sieht ziemlich unordentlich aus.

aktualisiert Do 11. November 23.49.35 UTC 2010:

aktualisieren Mi 15. Dezember 18.34.52 UTC 2010:

  • adymitruk ist in der Nähe! Nur ein Fall ist noch ungelöst: Nicht-triviale Zusammenführungen müssen noch funktionieren.
  • Eine ziemlich vollständige test suite ist verfügbar, überprüfen Sie es.
  • Ich bat um Hilfe bei einem (der?) git mailing list.
+0

Wie definieren Sie "trivial merge?" Wie können Sie zwischen trivialen Zusammenführungen und nicht trivialen Zusammenführungen unterscheiden? – cdhowie

+0

Ich habe das hinzugefügt, beginnend mit * By "trivial merge" ... * –

+2

Es gibt viele Argumente gegen Rebasing statt Merge. Persönlich würde ich es hassen, gezwungen zu werden. Sag einfach;) –

Antwort

8

Ich stieß auf dieses Stück Code, während ich versuchte, eine Lösung zu finden. Es tut nicht genau, was Sie wollen, aber es sollte ez sein, zusätzliche Verzweigungsnamen in der if-Anweisung hinzuzufügen.

Funktioniert für mich, so weit. es zwingt Pull-Rebase für den gleichen Zweig und lässt regelmäßige Zusammenführungen mit anderen Zweigen durch.

Alle Credits gehen an den ursprünglichen Autor.

#!/bin/bash 
# 
# This git update hook will refuse unnecessary merge commits caused by pulling 
# from being pushed to a shared repository. These commits make following the 
# history of a project difficult and are always avoidable with rebasing. 
# 
# by Scott Kyle (appden) 
# modified by Olivier Refalo (orefalo) 

refname="$1" 
oldrev="$2" 
newrev="$3" 

# if this is not run as a hook, you may have messed up 
if [ -z "$GIT_DIR" -o -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then 
    echo "Usage: GIT_DIR=<path> $0 <ref> <oldrev> <newrev>" >&2 
    exit 1 
fi 

# if the new revision is all 0's then it's a commit to delete a ref 
zero="0000000000000000000000000000000000000000" 
# also check if the new revision is not a commit or is not a fast forward 
# detect branch deletion, branch creation... and more 
if [ "${refname#refs/heads/}" = "master" ] || [ "$newrev" = "$zero" ] || [ "$oldrev" = "$zero" ] || [ $(git cat-file -t $newrev) != "co 
mmit" ] || [ $(git merge-base $oldrev $newrev) != "$oldrev" ]; then 
    exit 0 
fi 

# loop through merges in the push only following first parents 
for merge in $(git rev-list --first-parent --merges $oldrev..$newrev --); do 
    # lazily create the revision list of this branch prior to the push 
    [ -z "$revlist" ] && revlist=$(git rev-list $oldrev) 
    # check if the second parent of the merge is already in this branch 
    if grep -q $(git rev-parse $merge^2) <<< "$revlist"; then 
     cat >&2 <<-EOF 
      *** PUSH REJECTED *** 
      *** TRIVIAL merge detected on local branch ${refname#refs/heads/} 
      *** To fix: git rebase origin/${refname#refs/heads/} 
      *** 
      *** Next time use: git pull --rebase 
      *** 
      *** Permanent fix: git config [--global] branch.autosetuprebase always 
      *** Then for existing branches: git config branch.<name>.rebase true 
     EOF 
     exit 1 
    fi 
done 

echo -Info- Clean history successfully preserved! 
exit 0 
+1

Dies blockiert auch nichttriviale Zusammenführungen. Siehe https://gist.github.com/737842. Ich habe diesen Code zu diesem Gist hinzugefügt, geben Sie einfach "make" ein, um Tests auszuführen. –

+0

Bei der Bereitstellung auf dem Server (Update-Hook) zwingt es Benutzer in 'Pull - Rebase'. Eine reguläre Zusammenführung von einem anderen Zweig funktioniert gut, aber aus dem gleichen Zweig wird bei einer trivialen Zusammenführung fehlschlagen –

+0

Ah, ich verstehe. Tut mir leid, ich hätte deine Beschreibung genauer lesen sollen. Als ich diese Frage vor einem Jahr gestellt habe, war ich auf der Suche nach etwas, das eine nichttriviale Zusammenführung von Herkunft/Master zu Master ermöglichen würde, so dass die Leute immer noch Merges machen könnten. In meinem alten Job (bei Mifos) stieß ich auf mehrere Integrationen, bei denen das Rebasieren schwierig war, aber das Zusammenführen war einfach. Jetzt, da ich mit der Rebase vertrauter bin, würde ich wahrscheinlich das Update-Skript verwenden, das Sie vorgestellt haben. Schließen wir das Buch zu diesem Thema. Du gewinnst! –

5

Dieses Update Haken wird überprüfen, ob Sie bestimmte Zweige drängen werden (es erlaubt trivial verschmilzt in wip, Thema und anderen Branchen).

Dies ist nicht störend für den Rest der Eltern bei Octopus-Zusammenführungen, da es nur den zweiten Elternteil referenziert, der bei jedem Merge-Commit gedrückt wird. Bitte zögern Sie nicht, das Skript zu aktualisieren.

UPDATE: Reservierte Zweige müssen auf der Fernbedienung vorhanden sein.

#!/bin/bash 
refname="$1" 
oldrev="$2" 
newrev="$3" 
branches="refs/heads/hotfixes refs/heads/dev refs/heads/qa refs/heads/master" 
cont="no" 
for branch in $branches ; do 
    if [[ $refname == $branch ]] ; then 
    cont="yes" 
    fi 
done 
if [[ $cont == "no" ]] ; then 
    exit 0 
fi 
echo "inspecting branch $refname for trivial merges" >&2 
hashes="$(git log --format=%H --merges $oldrev..$newrev)" 
for hash in $hashes ; do 
    echo "checking merge commit $hash" >&2 
    cont="no" 
    for branch in $branches ; do 
    if [[ $refname == $branch ]] ; then 
     continue 
    fi 
    # if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == "0" ]] ; then 
    if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == " 0" ]] ; then 
     cont="yes" 
    fi 
    done 
    if [[ $cont == "no" ]] ; then 
    echo "No trivial merges allowed. Please rebase and push again." >&2 
    exit 1 
    fi 
done 
exit 0 
+0

Danke! Ich gebe das eine Chance und markiere die akzeptierte Antwort, wenn ich es zum Laufen bringen kann. –

+0

@adymitruk - Sie sollten '&&' anstelle von 'AND' verwenden. Es würde auch von einigen Zeilenumbrüchen innerhalb der '[[' 'und']] 'profitieren. – bstpierre

+0

Einverstanden .. das war mehr Pseudo-Code. Bitte schlagen Sie einen Ersatz für die if-Bedingung vor und ich werde die Antwort bearbeiten. –