Bagaimana cara memilih strategi penggabungan untuk git rebase?

147

git-rebasesebutan halaman manual -X<option>dapat diteruskan ke git-merge. Kapan / bagaimana tepatnya?

Saya ingin rebase dengan menerapkan tambalan dengan strategi rekursif dan opsi mereka (menerapkan tongkat apa pun, daripada melewatkan seluruh komitmen yang saling bertentangan). Saya tidak ingin bergabung, saya ingin membuat sejarah linier.

Saya sudah mencoba:

git rebase -Xtheirs

dan

git rebase -s 'recursive -Xtheirs'

tetapi git menolak -Xdalam kedua kasus.


git rebase -Xtheirsberfungsi dalam versi terbaru, kecuali konflik pohon perlu diselesaikan secara manual. Anda perlu menjalankan git rebase -Xtheirs --continue(dengan -Xdiulang) setelah menyelesaikan konflik tersebut.

Kornel
sumber
Catatan: ini sekarang juga berfungsi dengan baik git rebase --interactive. Lihat [jawaban saya yang diperbarui di bawah ini ( stackoverflow.com/a/2945367/6309 ).
VonC

Jawaban:

231

Anda dapat menggunakan ini dengan Git v1.7.3 atau versi yang lebih baru.

git rebase --strategy-option theirs ${branch} # Long option
git rebase -X theirs ${branch} # Short option

(yang merupakan kependekan dari yang git rebase --strategy recursive --strategy-option theirs ${branch}dinyatakan oleh dokumentasi )

Dari Git v1.7.3 Catatan Rilis:

git rebase --strategy <s>belajar --strategy-option/ -Xpilihan untuk lulus opsi tambahan yang dipahami oleh strategi penggabungan dipilih.

NB: "Milik kita" dan "milik mereka" berarti kebalikan dari apa yang mereka lakukan selama penggabungan lurus. Dengan kata lain, "milik mereka" mendukung komitmen pada cabang saat ini .

Saya gila
sumber
6
untuk memperjelas: $ git rebase --strategy rekursif -X milik mereka
Gregg Lind
28
Ketika saya mencoba ini, makna oursdan theirstampaknya menjadi kebalikan dari apa yang saya harapkan. Saya perlu menggunakan theirsuntuk mendukung cabang saya saat ini.
Craig McQueen
19
@CraigMcQueen, saat menggunakan rebase, komit Anda yang tidak diterbitkan (tidak disucikan) dikesampingkan, cabang disejajarkan dengan remote (fast-forwarded), dan komit Anda sedang diputar ulang di atas cabang Anda. . Komit Anda adalah "milik mereka" menurut operasi penggabungan, dan status cabang lokal saat ini (dialihkan) adalah "milik kami". Mungkin tampak berlawanan dengan intuisi, tetapi begitu Anda menyadari apa yang sebenarnya terjadi, itu masuk akal.
patrikbeno
6
@ Patrikbeno: Mengutip Obi-Wan Kenobi, "Jadi yang saya katakan adalah benar ... dari sudut pandang tertentu."
Craig McQueen
5
Saya tidak yakin bahwa itu layak menambahkan, tapi setidaknya dalam versi yang relatif saat ini, kehadiran -Xmenyiratkan -s recursive, sehingga Anda sekarang dapat menggunakan hanya git rebase ${branch} -X theirs. (sumber git-scm.com/docs/git-rebase#git-rebase--Xltstrategy-optiongt )
Matt
20

Ini untuk menggabungkan strategi yang datang dengan set opsi mereka sendiri

git rebase <branch> -s recursive -X theirs

harus berfungsi, meskipun tambalan ini menyebutkan (Februari 2010):

Halaman manual mengatakan bahwa git-rebasemendukung strategi penggabungan, tetapi perintah rebase tidak tahu tentang -X, dan memberikan penggunaan saat disajikan dengan itu.

Jadi jika itu masih tidak berhasil, ini sedang diperdebatkan sekarang!
(didukung di git terbaru)


Pembaruan dari commit db2b3b820e2b28da268cc88adff076b396392dfe (Juli 2013, git 1.8.4+),

Jangan abaikan opsi menggabungkan dalam rebase interaktif

Strategi penggabungan dan opsinya dapat ditentukan dalam git rebase, tetapi dengan -- interactive, mereka sepenuhnya diabaikan.

Ditandatangani oleh: Arnaud Fontaine

Itu berarti -Xdan strategi sekarang bekerja dengan rebase interaktif, serta rebase sederhana.

VONC
sumber
1
@porneL: Saya kira begitu. Karena itu tautan saya ke proposal tambalan.
VonC
@porneL: Ya, saya telah memperhatikan bug ini juga - saya berharap itu akan segera diatasi, apakah dengan patch itu atau tidak, karena semua fasilitas dasar ada di sana; mereka hanya harus memutuskan dengan tepat bagaimana mereka akan berkomunikasi mulai dari rebase hingga merger.
Cascabel
@porneL: itu termasuk dalam git 1.7.3. Jika Anda masih pengguna 1.7.1 seperti saya, ada solusi mudah, periksa jawaban saya di bawah ini
MestreLion
7

Seperti yang dikatakan iCrazy , fitur ini hanya tersedia untuk git 1.7.3 dan seterusnya. Jadi, untuk jiwa-jiwa miskin (seperti saya) masih menggunakan 1.7.1, saya menyajikan solusi yang saya lakukan sendiri:

git-rebase-milik mereka

Ini adalah skrip yang dipoles dengan sangat baik (dan panjang), dimaksudkan untuk penggunaan produksi: opsi ui, menangani beberapa file, memeriksa apakah file benar-benar memiliki penanda konflik, dll, tetapi "inti" dapat diringkas dalam 2 baris:

cp file file.bak
awk '/^<+ HEAD$/,/^=+$/{next} /^>+ /{next} 1' file.bak > file

Dan inilah skrip lengkapnya:

#!/bin/bash
#
# git-rebase-theirs - Resolve rebase conflicts by favoring 'theirs' version
#
#    Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program. If not see <http://www.gnu.org/licenses/gpl.html>

#Defaults:
verbose=0
backup=1
inplace=0
ext=".bak"

message() { printf "%s\n" "$1" >&2 ; }
skip()    { message "skipping ${2:-$file}${1:+: $1}"; continue ; }
argerr()  { printf "%s: %s\n" "$myname" "${1:-error}" >&2 ; usage 1 ; }
invalid() { argerr "invalid option: $1" ; }
missing() { argerr "missing${1:+ $1} operand." ; }

usage() {
    cat <<- USAGE
    Usage: $myname [options] [--] FILE...
    USAGE
    if [[ "$1" ]] ; then
        cat >&2 <<- USAGE
        Try '$myname --help' for more information.
        USAGE
        exit 1
    fi
    cat <<-USAGE

    Resolve git rebase conflicts in FILE(s) by favoring 'theirs' version

    When using git rebase, conflicts are usually wanted to be resolved
    by favoring the <working branch> version (the branch being rebased,
    'theirs' side in a rebase), instead of the <upstream> version (the
    base branch, 'ours' side)

    But git rebase --strategy -X theirs is only available from git 1.7.3
    For older versions, $myname is the solution.

    It works by discarding all lines between '<<<<<<< HEAD' and '========'
    inclusive, and also the the '>>>>>> commit' marker.

    By default it outputs to stdout, but files can be edited in-place
    using --in-place, which, unlike sed, creates a backup by default.

    Options:
      -h|--help            show this page.
      -v|--verbose         print more details in stderr.

      --in-place[=SUFFIX]  edit files in place, creating a backup with
                           SUFFIX extension. Default if blank is ""$ext"

       --no-backup         disables backup

    Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]>
    License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>
    USAGE
    exit 0
}
myname="${0##*/}"

# Option handling
files=()
while (( $# )); do
    case "$1" in
    -h|--help     ) usage            ;;
    -v|--verbose  ) verbose=1        ;;
    --no-backup   ) backup=0         ;;
    --in-place    ) inplace=1        ;;
    --in-place=*  ) inplace=1
                    suffix="${1#*=}" ;;
    -*            ) invalid "$1"     ;;
    --            ) shift ; break    ;;
    *             ) files+=( "$1" )  ;;
    esac
    shift
done
files+=( "$@" )

(( "${#files[@]}" )) || missing "FILE"

ext=${suffix:-$ext}

for file in "${files[@]}"; do

    [[ -f "$file" ]] || skip "not a valid file"

    if ((inplace)); then
        outfile=$(tempfile) || skip "could not create temporary file"
        trap 'rm -f -- "$outfile"' EXIT
        cp "$file" "$outfile" || skip
        exec 3>"$outfile"
    else
        exec 3>&1
    fi

    # Do the magic :)
    awk '/^<+ HEAD$/,/^=+$/{next} /^>+ /{next} 1' "$file" >&3

    exec 3>&-

    ((inplace)) || continue

    diff "$file" "$outfile" >/dev/null && skip "no conflict markers found"

    ((backup)) && { cp "$file" "$file$ext" || skip "could not backup" ; }

    cp "$outfile" "$file" || skip "could not edit in-place"

    ((verbose)) && message "resolved ${file}"
done
MestreLion
sumber
Terima kasih @VonC! Saya hanya tidak yakin mengapa SO tidak memberi kode warna pada skrip bash. Sebuah skrip besar seperti ini selalu jelek dengan sendirinya ... tetapi menjadi kumpulan besar teks hitam membuatnya lebih jelek: P
MestreLion
Ini dijelaskan di stackoverflow.com/editing-help#syntax-highlighting . Saya telah menambahkan kode bahasa prettify yang sesuai sebelum blok kode Anda. Seharusnya terlihat lebih baik sekarang.
VonC
Terima kasih @VonC! Penyorotan sintaksis SO benar-benar di bawah standar, tetapi waaaay lebih baik daripada tidak sama sekali. Dan Anda sangat bijaksana! Dan, karena otoritas git THE dalam SO, Anda mungkin tertarik pada skrip pembantu lain: stackoverflow.com/a/10220276/624066 . Itu dan akun github saya memiliki alat yang dapat Anda nikmati.
MestreLion
Untuk 1.7.1, ini sepertinya bekerja untuk saya; tidak perlu untuk skrip di atas. git rebase --strategy="recursive --theirs" master
Papadeltasierra
Maaf sudah menjadi pemula git, tapi bagaimana cara menggunakan skrip git-rebase-mereka yang diberikan di atas? Apakah ini suatu opsi yang diteruskan ke git-rebase atau hanya mengurangi waktu yang dibutuhkan untuk menyelesaikan konflik secara manual?
Papadeltasierra