Jak wybrać zakres commitów i połączyć się z inną gałęzią?

Mam następujący układ repozytorium:

  • master branch (produkcja)
  • integracja
  • Praca

To, co chcę osiągnąć, to wybrać zakres commitów z działającej gałęzi i połączyć je z gałęzią integracyjną. Jestem całkiem nowy w git i nie mogę dowiedzieć się, jak dokładnie to zrobić (cherry zbieranie zakresów commit w jednej operacji, a nie Łączenie) bez brudzenia repozytorium. Jakieś wskazówki lub przemyślenia na ten temat? Dzięki!

7 answers

Jeśli chodzi o zakres commitów, cherry-picking jest nie było praktyczne.

Jak wspomniano poniżej przez Keitha Kim, Git 1.7.2 + wprowadził możliwość cherry-pick zakresu commitów (ale nadal musisz być świadomy konsekwencji cherry-pickingu dla przyszłej merge )

Git cherry-pick " nauczył się wybierać zakres commitów
(np. " cherry-pick A..B "i" cherry-pick --stdin"), podobnie "git revert"; nie obsługują one jednak ładniejsze sterowanie sekwencyjne "rebase [-i] " ma.

Damian komentarze i ostrzega:

W formularzu" cherry-pick A..B", A powinny być starsze niż B.
jeśli są w złej kolejności, polecenie po cichu zawiedzie .

Jeśli chcesz wybrać zakres B przez D (włącznie) , to B^..D.
Patrz " Git create branch from range of previous commits?" jako ilustracja.

Jak Jubobs wspomina w komentarzach :

Zakłada to, że B nie jest commitem root; w przeciwnym razie pojawi się błąd" unknown revision".

Uwaga: od wersji Git 2.9.x / 2.10 (Q3 2016), możesz wybrać zakres commitów bezpośrednio na orphan branch( pusta Głowica): zobacz " jak zmienić istniejącą gałąź w git ".


Oryginalna odpowiedź (styczeń 2010)

A rebase --onto byłoby lepiej, gdzie ty powtórz podany zakres commit na górze swojej gałęzi integracji, jak to opisał Charles Bailey tutaj .
aby zobaczyć praktyczny przykład git rebase --onto, poszukaj "oto jak przeszczepić gałąź tematyczną opartą na jednej gałęzi do drugiej" na stronie podręcznika git rebase, aby zobaczyć praktyczny przykład git rebase --onto)

Jeśli Twoja bieżąca gałąź jest integracją:

# Checkout a new temporary branch at the current location
git checkout -b tmp

# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range

# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration

To odtworzy wszystko pomiędzy:

  • po rodzicu first_SHA-1_of_working_branch_range (stąd ~1): pierwszy commit you chcesz odtworzyć
  • do "integration "(co wskazuje na ostatni commit, który chcesz odtworzyć, z gałęzi working)

Do "tmp "(co wskazuje na to, gdzie integration wskazywało wcześniej)

Jeśli wystąpi jakikolwiek konflikt, gdy jeden z tych commitów zostanie powtórzony:

  • albo Rozwiąż i uruchom "git rebase --continue".
  • lub pomiń tę łatkę, a zamiast tego Uruchom "git rebase --skip"
  • lub anulować wszystko za pomocą "git rebase --abort "(i umieścić z powrotem gałąź integration na tmp oddział)

Po tym rebase --onto, integration zostanie zwrócony przy ostatnim commicie gałęzi integracyjnej (czyli gałęzi" tmp " + wszystkie powtórzone commity)

Z cherry-picking lub rebase --onto, nie zapominaj, że ma to konsekwencje dla kolejnych połączeń, jak opisano tutaj .


Czystym rozwiązaniem "cherry-pick" jest omawiane tutaj i obejmowałoby coś w rodzaju:

Jeśli chcesz użyć patcha to " Git format-patch|Git am" a "git cherry" to twoje opcje.
Obecnie git cherry-pick akceptuje tylko jeden commit, ale jeśli chcesz wybrać zakres B przez D, to będzie to B^..D w git lingo, więc

git rev-list --reverse --topo-order B^..D | while read rev 
do 
  git cherry-pick $rev || break 
done 

Ale w każdym razie, kiedy musisz "odtworzyć" zakres commitów, słowo "replay" powinno skłonić cię do użycia funkcji" rebase " W Git.

 659
Author: VonC,
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
2018-04-28 06:44:24

Od wersji git v1.7. 2 cherry pick może akceptować zakres commitów:

git cherry-pick nauczył się wybierać zakres commitów (np. cherry-pick A..B i cherry-pick --stdin), podobnie jak git revert; te nie wspierają jednak ładniejszej kontroli sekwencjonowania rebase [-i].

 119
Author: Keith Kim,
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
2014-09-22 22:22:29

Jesteś pewien, że nie chcesz połączyć gałęzi? Jeśli działająca gałąź ma kilka ostatnich zmian, których nie chcesz, możesz po prostu utworzyć nową gałąź z nagłówkiem w miejscu, w którym chcesz.

Teraz, jeśli naprawdę chcesz wybrać zakres commitów, z jakiegokolwiek powodu, eleganckim sposobem na to jest po prostu wyciągnięcie patchsetu i zastosowanie go do nowej gałęzi integracji: {]}

git format-patch A..B
git checkout integration
git am *.patch

To jest zasadniczo to, co i tak robi git-rebase, ale bez potrzeby grania w gry. Możesz dodać --3way do git-am, jeśli chcesz się połączyć. Upewnij się, że nie ma innych*.łataj pliki już w katalogu, w którym to robisz, jeśli postępujesz zgodnie z instrukcjami dosłownie...

 24
Author: djs,
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
2010-01-04 09:32:52

Załóżmy, że masz 2 gałęzie,

"branchA": zawiera commity, które chcesz skopiować (z "commitA" do "commitB"

"branchB": gałąź, z której chcesz przenieść commity z "branchA"

1)

 git checkout <branchA>

2) get the IDs of "commitA" and "commit"

3)

git checkout <branchB>

4)

git cherry-pick <commitA>^..<commitB>

5) Jeśli masz konflikt, rozwiąż go i wpisz

git cherry-pick --continue

Aby kontynuować proces wyboru wiśni.

 9
Author: KostasA,
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-08-01 14:29:48

Zawinąłem Kod VonC do krótkiego skryptu bash, git-multi-cherry-pick, dla łatwego działania:

#!/bin/bash

if [ -z $1 ]; then
    echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
    echo "";
    echo "Usage:  $0 start^..end";
    echo "";
    exit 1;
fi

git rev-list --reverse --topo-order $1 | while read rev 
do 
  git cherry-pick $rev || break 
done 

Obecnie używam tego, gdy odbudowuję historię projektu, który miał zarówno kod 3rd-party, jak i modyfikacje mieszane razem w tym samym bagażniku svn. Teraz dzielę core 3rd party code, 3rd party modules i customizations na ich własne gałęzie git dla lepszego zrozumienia dostosowań w przyszłości. git-cherry-pick jest pomocny w tej sytuacji, ponieważ mam dwa drzewa w tym samym repozytorium, ale bez wspólnego przodka.

 6
Author: Adam Franco,
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 11:33:32

Wszystkie powyższe opcje monitują o rozwiązanie konfliktów scalania. Jeśli łączysz zmiany wprowadzone dla zespołu, trudno jest rozwiązać konflikty scalania ze strony programistów i kontynuować. Jednak "Git merge" zrobi scalenie w jednym ujęciu, ale nie możesz przekazać zakresu poprawek jako argumentu. musimy użyć poleceń "git diff" i "GIT apply"aby wykonać zakres scalania obrotów. Zauważyłem, że "git apply" nie powiedzie się, jeśli plik patch ma diff dla zbyt wielu plików, więc musimy Utwórz łatkę na plik, a następnie zastosuj. Zauważ, że skrypt nie będzie w stanie usunąć plików usuniętych w gałęzi source. Jest to rzadki przypadek, można ręcznie usunąć takie pliki z gałęzi docelowej. Status zakończenia "git apply" nie jest zerowy, jeśli nie jest w stanie zastosować poprawki, jednak jeśli użyjesz opcji-3way, powróci ona do 3 way merge i nie musisz się martwić o tę awarię.

Poniżej znajduje się skrypt.

enter code here



  #!/bin/bash

    # This script will merge the diff between two git revisions to checked out branch
    # Make sure to cd to git source area and checkout the target branch
    # Make sure that checked out branch is clean run "git reset --hard HEAD"


    START=$1
    END=$2

    echo Start version: $START
    echo End version: $END

    mkdir -p ~/temp
    echo > /tmp/status
    #get files
    git --no-pager  diff  --name-only ${START}..${END} > ~/temp/files
    echo > ~/temp/error.log
    # merge every file
    for file in `cat  ~/temp/files`
    do
      git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff
      if [ $? -ne 0 ]
      then
#      Diff usually fail if the file got deleted 
        echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log
        echo Skipping the merge: git diff command failed for $file
        echo "STATUS: FAILED $file" >>  /tmp/status
        echo "STATUS: FAILED $file"
    # skip the merge for this file and continue the merge for others
        rm -f ~/temp/git-diff
        continue
      fi

      git apply  --ignore-space-change --ignore-whitespace  --3way --allow-binary-replacement ~/temp/git-diff

      if [ $? -ne 0 ]
       then
#  apply failed, but it will fall back to 3-way merge, you can ignore this failure
         echo "git apply command filed for $file"
       fi
       echo
       STATUS=`git status -s $file`


       if [ ! "$STATUS" ]
       then
#   status is null if the merged diffs are already present in the target file
         echo "STATUS:NOT_MERGED $file"
         echo "STATUS: NOT_MERGED $file$"  >>  /tmp/status
       else
#     3 way merge is successful
         echo STATUS: $STATUS
         echo "STATUS: $STATUS"  >>  /tmp/status
       fi
    done

    echo GIT merge failed for below listed files

    cat ~/temp/error.log

    echo "Git merge status per file is available in /tmp/status"
 2
Author: Yoganand Bijapur,
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
2016-09-07 09:08:39

Inną opcją może być scalenie z naszą strategią do commita przed zakresem, a następnie' normalne ' scalenie z ostatnim commitem tego zakresu (lub gałęzią, gdy jest ostatnim). Przypuśćmy więc, że tylko 2345 i 3456 commity master zostaną scalone w gałąź funkcji:

master:
1234
2345
3456
4567

W gałęzi funkcji:

git merge -s ours 4567
git merge 2345
 0
Author: Koos Vriezen,
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-08-16 12:47:03