Wie kann man eine Reihe von Commits auswählen und sich in einen anderen Zweig verschmelzen?

StackOverflow https://stackoverflow.com/questions/1994463

  •  22-09-2019
  •  | 
  •  

Frage

Ich habe das folgende Repository -Layout:

  • Master Branch (Produktion)
  • Integration
  • Arbeiten

Was ich erreichen möchte, ist, eine Reihe von Commits aus dem Arbeitszweig auszuwählen und sie in den Integrationszweig zu verschmelzen. Ich bin ziemlich neu in Git und ich kann nicht herausfinden, wie ich genau das machen soll (die Kirschwolke von Commit -Bereichen in einer Operation, nicht die Verschmelzung), ohne das Repository durcheinander zu bringen. Irgendwelche Zeiger oder Gedanken dazu? Vielen Dank!

War es hilfreich?

Lösung

Wenn es um eine Reihe von Commits geht, Cherry-Picking ist war nicht praktisch.

Wie unten genannten durch Keith Kim, Git 1.7.2+ führte die Fähigkeit ein, eine Reihe von Commits zu packen (aber Sie müssen sich dessen bewusst sein Folge des Kirschpicks für die zukünftige Zusammenführung)

Git Cherry-Pick "lernte, eine Reihe von Commits zu wählen
(z.B "cherry-pick A..B" und "cherry-pick --stdin"), auch"git revert"; diese unterstützen die schönere Sequenzierungskontrolle nicht"rebase [-i]"hat aber.

Damian Kommentare und warnt uns:

In dem "cherry-pick A..B" bilden, A sollte älter sein als B.
Wenn sie die falsche Reihenfolge sind, scheitert der Befehl stillschweigend.

Wenn Sie die auswählen möchten Angebot B durch D (inklusive) das wäre B^..D.
Sehen "Git erstellen Branch aus Reichweite früherer Commits?" als Illustration.

Wie Jubobs Erwähnungen in den Kommentaren:

Dies setzt das voraus B ist kein Wurzelbefehl; Du wirst eine "bekommen"unknown revision"Fehler ansonsten.

Hinweis: Ab GIT 2.9.x/2.10 (Q3 2016) können Sie eine Reihe von Läufen direkt auf einem Orphan-Zweig (leerer Kopf) einstellen: siehe "Wie man den bestehenden Zweig zu einem Waisen in Git macht".


Originalantwort (Januar 2010)

EIN rebase --onto Wäre besser, wo Sie die angegebene Spektrum des Commits zusätzlich zu Ihrer Integrationszweig wiederholen, als Charles Bailey beschrieben hier.
(Suchen Sie auch nach "Hier ist, wie Sie einen Themenzweig basierend auf einem Zweig zur anderen transplantieren" in der Git Rebase Man Page, um ein praktisches Beispiel von zu sehen git rebase --onto)

Wenn Ihr aktueller Zweig Integration ist:

# 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

Das wird alles zwischen:

  • Nach dem Elternteil von first_SHA-1_of_working_branch_range (daher die ~1): Das erste Commit, das Sie wiederholen möchten
  • bis zu "integration"(was auf das letzte Commit hinweist, das Sie wiederholen möchten, von der working Zweig)

zu "tmp"(was darauf hinweist, wo integration zeigte vorher)

Wenn es einen Konflikt gibt, wenn einer dieser Commits wiedergegeben wird:

  • Entweder lösen und rennen "git rebase --continue".
  • Oder überspringen Sie diesen Patch und laufen Sie statt. "git rebase --skip"
  • Oder abbrechen alles mit einem "git rebase --abort"(und leg das zurück integration Zweig auf der tmp Zweig)

Danach rebase --onto, integration wird am letzten Commit der Integrationszweig zurück sein (dh "tmp"Zweig + alle wiederholten Commits)

Mit Kirschpicking oder rebase --onto, Vergessen Sie nicht, dass es Konsequenzen auf nachfolgende Zusammenführungen hat wie hier beschrieben.


Ein reines "cherry-pick"Lösung ist Hier besprochen, und würde so etwas wie:

Wenn Sie einen Patch-Ansatz verwenden möchten, sind "git format-patch | git am" und "git cherry" Ihre Optionen.
Zur Zeit, git cherry-pick Akzeptiert nur ein einziges Commit, aber wenn Sie den Bereich auswählen möchten B durch D das wäre B^..D in Git lingo so

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

Wenn Sie jedoch eine Reihe von Commits "wiedergeben" müssen, sollte das Wort "Wiederholung" Sie dazu drängen, das zu verwenden "rebase"Merkmal von Git.

Andere Tipps

Ab GIT v1.7.2 Cherry Pick kann eine Reihe von Commits akzeptieren:

git cherry-pick lernte, eine Reihe von Commits auszuwählen (z. B. z. B. cherry-pick A..B und cherry-pick --stdin), auch git revert; Diese unterstützen die schönere Sequenzierungskontrolle nicht rebase [-i] hat jedoch.

Angenommen, Sie haben 2 Zweige,

"Brancha": Beinhaltet Commits, die Sie kopieren möchten (von "Commita" zu "Commitb"

"Branchb": Die Zweigstelle, die die Commits von "Brancha" übertragen werden sollen

1)

 git checkout <branchA>

2) Holen Sie sich die IDs von "Commita" und "Commitb"

3)

git checkout <branchB>

4)

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

5) Falls Sie einen Konflikt haben, lösen Sie ihn und tippen

git cherry-pick --continue

den Kirschpick-Prozess fortzusetzen.

Sind Sie sicher, dass Sie die Zweige nicht wirklich zusammenführen möchten? Wenn die Arbeitsabteilung einige aktuelle Commits hat, die Sie nicht möchten, können Sie einfach einen neuen Zweig mit einem Kopf an dem gewünschten Punkt erstellen.

Wenn Sie nun wirklich eine Reihe von Commits einfügen möchten, können Sie aus irgendeinem Grund eine elegante Möglichkeit, dies zu tun, nur ein Patchset zu ziehen und auf Ihren neuen Integrationszweig anzuwenden:

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

Dies ist im Wesentlichen das, was Git-Rebase sowieso tut, aber ohne die Notwendigkeit, Spiele zu spielen. Du kannst hinzufügen --3way zu git-am Wenn Sie zusammenführen müssen. Stellen Sie sicher, dass es im Verzeichnis, in dem Sie dies tun, keine anderen *.patch -Dateien vorhanden sind, wenn Sie den wörtlichen Anweisungen befolgen ...

Ich habe eingewickelt VONCs Code in ein kurzes Bash -Skript, git-multi-cherry-pick, zum einfachen Laufen:

#!/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 

Ich benutze dies derzeit, da ich die Geschichte eines Projekts wieder aufbaue, das sowohl Code auf dem dritten Party als auch die Anpassungen im selben SVN-Koffer miteinander gemischt hatte. Ich spreche jetzt den Core -Code von Drittanbietern, Modulen von Drittanbietern und Anpassungen auf ihre eigenen Git -Zweige für ein besseres Verständnis der künftigen Anpassungen auf. git-cherry-pick ist in dieser Situation hilfreich, da ich zwei Bäume im selben Repository habe, aber ohne gemeinsamen Vorfahren.

Alle oben genannten Optionen fordern Sie zur Lösung von Zusammenführungskonflikten auf. Wenn Sie Änderungen für ein Team verschmelzen, ist es schwierig, die Zusammenführungskonflikte von Entwicklern zu lösen und fortzufahren. "Git Merge" wird jedoch die Zusammenführung in einer Einstellung ausführen, aber Sie können eine Reihe von Überarbeitungen nicht als Argument bestehen. Wir müssen "Git Diff" und "Git Apply" -Beharten verwenden, um den Zusammenführungsbereich von Drehzählern durchzuführen. Ich habe beobachtet, dass "Git Apply" fehlschlägt, wenn die Patch -Datei für zu viele Dateien differenziert ist. Daher müssen wir einen Patch pro Datei erstellen und dann anwenden. Beachten Sie, dass das Skript die Dateien, die in Quellzweig gelöscht werden, nicht löschen können. Dies ist ein seltener Fall. Sie können solche Dateien manuell aus Target Branch löschen. Der Exit -Status von "Git Apply" ist nicht Null, wenn er den Patch nicht anwenden kann. Wenn Sie jedoch -3way -Option verwenden, fällt er auf 3 Wege zurück und Sie müssen sich keine Sorgen um diesen Fehler machen.

Unten ist das Skript.

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"

Eine andere Option könnte darin bestehen, sich mit Strategie zu dem Commit vor dem Bereich zu verschmelzen und dann eine „normale“ Verschmelzung mit dem letzten Commit für diesen Bereich (oder Zweig, wenn es der letzte ist). Nehmen wir also an, nur 2345 und 3456 Commits of Master, die in Feature Branch zusammengeführt werden sollen:

master:
1234
2345
3456
4567

In Feature Branch:

git merge -s ours 4567
git merge 2345
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top