2015-06-20 8 views
5

Ich versuche Squash viele Commits in einem einzigen, das Problem ist, dass ich tun muss, dass von Autor (Name oder E-Mail).Git Squash nach Autor - Alle Autor Commit in einem einzigen Commit

Der Fall:

Lets sagen, ich habe einen Zweig namens Feature-a, in diesem Zweig Ich habe viele Commits für viele Autoren. Wie kann ich alle Commits nach Autor (zum Beispiel E-Mail) in einen einzigen Commit zerquetschen? Ich möchte, dass alle Autor Commits in Master zusammengeführt werden können.

Irgendwelche Hilfe hier?

Vielen Dank im Voraus

+0

Das klingt, als könnte es zu viel unnötiger Anstrengung führen. Das heißt, wenn Commits eines bestimmten Autors nicht konsekutiv sind, dann wird das Quetschen von ihnen viel manuellen Eingriff erfordern. Es wäre besser, wenn Ihre vielen Autoren jeweils in einer eigenen Branche arbeiten. – larsks

Antwort

1

Be careful rewriting history

Das Ende führen Sie könnte möglich sein möchten, wenn Sie Zweige für jeden Autor zu erstellen, cherry-pick die Festschreibungen von jedem Autor in den rechten Zweig, Squash dann diese Änderungen. Ich denke jedoch nicht, dass das funktionieren wird, wenn diese Commits sinnvoll voneinander abhängen.

Wenn Sie eine Reihe von Commits:

  Author1    Author2    Author1 
version1 ---commit---> version2 ---commit---> version3 ---commit--->... 

Wenn Sie die Änderungen von Author2 zu extrahieren, um zu versuchen waren, und wendet sie auf version1 gibt es eine gute Chance, es wird keinen Sinn machen (Beispiel: , wenn Autor2 den von Autor1 erstellten Code ändert.

1

Mit Kenkron ‚s caveats im Auge, könnten Sie ein tun:

SORTED_GIT_LOGS=$(git log --pretty="format:%an %H" master..feature_a | sort -g | cut -d' ' -f2); \ 
IFS=$(echo -en "\n\b"); for LOG in $SORTED_GIT_LOGS; do \ 
    git cherry-pick $LOG; \ 
done | less 

Die git log --pretty="format:%an %H" master..feature_a | sort -g die Protokolle der feature_a Commits sortieren würde (nicht diejenigen von master wegen der master..feature_a Syntax)

Sie müssten immer noch eine interaktive Rebase machen, um die Commits (jetzt vom Autor bestellt) unter master zu quetschen.

+0

Beispiel für interaktive Rebase: http://denniskubes.com/2012/08/22/honey-i-squashed-the-commits/ – VonC

+0

Wenn vom Autor getan, könnte ein 'git reset' auch funktionieren: http: // makandracards .com/makandra/527-squash-mehrere-git-commits-in-one-commit – VonC

1

Ich musste eine ähnliche Neuschreibung in einem unnötig großen Repository durchführen, während der Repo offline war. Der Ansatz, den ich nahm, war automatisierte "interaktive" Rebase unter Verwendung GIT_SEQUENCE_EDITOR, die in this answer von @ James-Foucar & @pfalcon abgedeckt ist.

Damit dies gut funktioniert, habe ich zuerst die Merges aus dem neu geschriebenen Abschnitt des Verlaufs entfernt. Für meinen eigenen Fall wurde dies mit einer Menge von git rebase --onto gemacht, die ausführlich in anderen Fragen zu StackOverflow behandelt wird.

Ich habe eine small script generate-similiar-commit-squashes.sh die pick & squash Befehle zu erzeugen, so dass aufeinanderfolgende ähnliche Festschreibungen gestaucht würde. Ich habe Autor-date-and-shortlog verwendet, um ähnliche Commits zu finden, aber Sie brauchen nur den Autor (mein Gist hat einen Kommentar darüber, wie man ihn nur für den Autor anpassen kann).

$ generate-similiar-commit-squashes.sh > /tmp/git-rebase-todo-list 

Die Ausgabe sieht aus wie

... 
pick aaff1c556004539a54a7a33ce2fb859af0c4238c [email protected] 
squash aa190ea2323ece42f1cd212041bf61b94d751d5c [email protected] 
pick aab8c98981a8d824d2bc0d5278d59bc1a22cc7b0 [email protected]_config.yml 

Das Repository auch von voll war selbst kehrt mit dem gleichen Stil ‚Update xyz‘ Nachrichten begehen. Wenn sie zerquetscht wurden, führten sie zu leeren Commits.

Die Commits, die ich zusammengeführt habe, hatten identische Commit-Nachrichten. git rebase -i bietet eine überarbeitete Commit-Nachricht mit allen komprimierten Commit-Nachrichten, die sich wiederholt haben. Um das zu beheben, habe ich ein kleines Perl-Skript von this answer verwendet, um doppelte Zeilen von der Commit-Nachricht zu entfernen, die von git rebase angeboten wird. Es ist besser in einer Datei, da es in einer Shell-Variable verwendet wird.

$ echo 'print if ! $x{$_}++' > /tmp/strip-seen-lines.pl 

Jetzt für den letzten Schritt:

$ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' \ 
    GIT_SEQUENCE_EDITOR='cat /tmp/git-rebase-todo-list >' \ 
    git rebase --keep-empty -i $(git rev-list --max-parents=0 HEAD) 

Trotz --keep-empty mit beschwerte git ein paar Mal durch diesen Prozess über leere Commits. Es würde mich mit einem unvollständigen git rebase auf die Konsole werfen. Um die leere Commit- und Resume-Verarbeitung zu überspringen, wurden die folgenden zwei Befehle benötigt (in meinem Fall eher häufig).

$ git reset HEAD^ 
$ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' git rebase --continue 

Wieder trotz --keep-empty, fand ich, dass ich had no empty commits in der letzten git Geschichte, so über die Resets sie alle entfernt worden. Ich nehme an, dass etwas mit meinem Git, Version 2.14.1, nicht stimmt. Die Verarbeitung von ~ 10000 Commits wie diese dauerte etwas mehr als 10 Minuten auf einem beschissenen Laptop.

+0

Interessanter Ansatz, vollständiger als meine Antwort. +1. Ich bin mir aber nicht sicher, ob dein "- keep-empty" Problem auftritt. – VonC

+0

Wenn Sie nicht möchten, dass der Verlauf überschrieben wird, wenn Sie nicht möchten, dass sich der Rewriter als Committer für jeden Commit einschreibt, müssen Sie das Neuschreiben wahrscheinlich durch Zurücksetzen des Commiters beenden. Die einfachste Methode ist [setting committer = author] (https://stackoverflow.com/a/32944640/5037965), aber ein ausgefeilterer Ansatz wird benötigt, wenn die ursprünglichen Committer-Informationen tatsächlich wichtig sind und beibehalten werden müssen. –

+0

Ich habe zu https://gist.github.com/jayvdb/9b41677f00065dbd94cc02446fc5ba34 ein Skript 'generate-multiple-new-file-squashes.sh' hinzugefügt, um Commits zusammenzufassen, die nur aus aufeinanderfolgenden Adds bestehen (dh der Committer verwendet den GitHub/GitLab/BitBucket Web UI "Datei hochladen") –