Really flatten a git merge

Jest kilka pytań o "spłaszczenie merge" w StackOverflow, a odpowiedź zwykle brzmi "Git rebase". Te odpowiedzi choć brakuje jednego kluczowego punktu-kolejność commitów.

Załóżmy, że istnieje gałąź A z commitami z 1 czerwca i 1 sierpnia oraz gałąź B z commitem z 1 lipca (UPDATE w celu przywrócenia bazy opisanej poniżej: gałęzie są w pełni niezależne i nie mają wspólnego przodka, na przykład pochodzą z 2 różnych repozytoriów). Podczas łączenia B W A, będzie następująca historia (na git log):

Merged branch 'B'
Aug 1
Jul 1
Jun 1

Teraz szukam sposobu na uzyskanie tego samego wyniku, ale bez commitów scalających(a więc z bazową historią liniową w tej kolejności, i tak, to oznacza ponowne rodzicielstwo commitów). Git rebase nie pomaga tutaj, ponieważ z nim, otrzymasz następujące historie:

Jul 1
Aug 1
Jun 1

Lub

Aug 1
Jun 1
Jul 1

Innymi słowy, Git rebase zawsze układa jedną gałąź na drugiej, podczas gdy ja szukam rozwiązania, które przeplata commity posortowane według daty zatwierdzenia autora.

Najwyraźniej, w prostych przypadkach, potrzebny układ można osiągnąć poprzez ręczne postprocesowanie git rebase za pomocą git rebase-i, ale to nie jest praktyczne dla dużych historii, więc szukałbym zautomatyzowanych poleceń / skryptów.

Usecase? Jeśli A i B reprezentują różne części tego samego projektu, które zdarzały się być w różnych repozytoriach i nadszedł czas, aby to naprawić, łącząc je ze sobą, to naturalne jest, aby liniowa historia rozwijała się w rzeczywista kolejność rozwoju.

Author: John Vandenberg, 2012-09-04

4 answers

Po pewnym namyśle, wymyśliłem jak zrobić Jak uruchomić git rebase -- interactive w sposób nieinteraktywny?, który również zapewnia całkowicie Skryptowe rozwiązanie tego pytania.

1. przenoszenie 2 gałęzi z różnych repozytoriów do jednego repozytorium (git remote add + git fetch)

2. Rebase (nieinteraktywnie) jedna gałąź na drugiej (kolejność ma znaczenie, rozważ pierwszy commit z której gałęzi chcesz mieć jako pierwszy commit oddział skonsolidowany).

3. przygotuj następujący skrypt (rebase-reoder-by-date):

#!/bin/sh
awk '
/^pick/ {
            printf "%s %s ", $1, $2;
            system("echo -n `git show --format='%ai' -s " $2 "`");
            for (i = 3; i <= NF; i++) printf " %s", $i; printf "\n";
        }
' $1 | sort -k3 > $1.tmp
mv $1.tmp $1

4. Run: GIT_SEQUENCE_EDITOR=./rebase-reoder-by-date git rebase -i <initial commit>

Zastrzeżenie: Wszystkie te operacje powinny mieć miejsce na kopiach oryginalnych repozytoriów, przejrzyj/sprawdź / przetestuj połączoną gałąź, aby upewnić się, że jest to, czego oczekujesz i Zawiera to, czego oczekujesz, trzymaj kopie zapasowe pod ręką.

 12
Author: pfalcon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:06:46

Jaki jest problem z pozostawieniem osobnego rozwoju w osobnych liniach do czasu ich połączenia? Jeśli byli oddzieleni, to byli oddzieleni.

Istnieje wiele sposobów, aby wyświetlić historię w porządku chronologicznym bez hakowania historii, jak próbujesz. Próbowałeś git log --pretty --date-order?

 2
Author: Infiltrator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-05 05:30:26

[zobacz moją inną odpowiedź na całkowicie zautomatyzowane rozwiązanie. Zostawiłbym to jako przykład ścieżki, która doprowadziła do ostatecznego rozwiązania, na wypadek, gdyby ktoś stanął przed podobnym nie tak oczywistym zadaniem.]

Ok, to nie jest prawdziwa odpowiedź na pytanie (w pełni Skryptowe, zautomatyzowane rozwiązanie), ale myślenie i przykład jak (interaktywne rebase oparte) przetwarzanie może być zautomatyzowane.

Cóż, po pierwsze, dla ostatecznego rozwiązania git filter-branch --parent-filter wygląda dokładnie to, co jest potrzebne. Poza tym, że mój git-fu nie pozwala mi pisać, 1 -, 2-lub 3-liner, a podejście do pisania samodzielnego skryptu do parsowania wszystkich wersji nie jest fajne i bardziej wymagające niż rebase-i.

Więc, rebase-i może być użyty efektywnie, jeśli daty autora commit były widoczne. Moją pierwszą myślą było tymczasowe łatanie komunikatów commit, aby zacząć od daty autora używając git filter-branch --msg-filter, Uruchamianie rebase-i, a następnie rozpakowywanie wiadomości z powrotem.

Druga myśl brzmiała: po co się męczyć, lepiej łatać listę zmian rebase jako używany przez rebase-i. tak więc proces będzie:

  1. Jak zwykle łącz gałęzie A i B z różnych repo do jednego repo.
  2. Rebase (nieinteraktywnie) jedna gałąź na drugiej. Zastanów się, która gałąź musi zostać przeniesiona do której, aby mieć pierwotne prawo zatwierdzenia (którego nie można łatwo przepisać za pomocą rebase).
  3. Start git rebase -i
  4. w innej konsoli przejdź do $REPO/.git / rebase-merge/
  5. Run: awk '/^pick/ {printf "%s %s ", $1, $2; system("echo -n git show --format='%ai' -s " $2 ""); for (I = 3; i git-rebase-todo.nowy; mv git-rebase-todo.nowy git-rebase-todo
  6. to wydaje się właściwe miejsce/sposób na zmianę kolejności commitów: sort -k3 git-rebase-todo >git-rebase-todo.new; mv git-rebase-todo.new git-rebase-todo
  7. przełącz się na oryginalną konsolę i przeładuj plik git-rebase-todo w edytorze, a następnie zakończ edytor.
Voila! W rzeczywistości, to może być całkowicie Skryptowe jeśli {[2] } może działać w trybie "nie-interaktywnym", zgłosiłem Jak uruchomić Git rebase --interactive w sposób nie-interaktywny?Za to.
 1
Author: pfalcon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:06:46

Właściwie, jeśli dobrze rozumiem, możesz to łatwo osiągnąć za pomocą git-stitch-repo .

 0
Author: weynhamz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-03 17:14:47