web-dev-qa-db-ja.com

あるブランチを別のブランチにするためのgitコマンド

私は、変更を加えたブランチを取得し、分岐したアップストリームと同一になるように戻そうとしています。変更は両方ともローカルであり、githubにプッシュされているため、どちらもgit resetまたはgit rebaseは履歴を変更するため、本当に実行可能です。これは、すでにプッシュされているブランチでは悪いことです。

私も試しましたgit mergeさまざまな戦略がありますが、いずれもローカルの変更を元に戻しません。つまり、ファイルを追加した場合、マージによって他のファイルが元に戻る可能性がありますが、アップストリームにはないファイルが残っています。

アップストリームから新しいブランチを作成することもできますが、変更履歴を適用してすべての変更を適用してブランチを取得し、再びアップストリームと同じにすることで、その変更を安全にプッシュできます履歴を壊すことなく。そのようなコマンドまたは一連のコマンドはありますか?

70
Arne Claassen

カスタムマージドライバー「keepTheirs」を使用して、アップストリームブランチをdevブランチにマージできます。
見る " - "git merge -s theirs”が必要—しかし、私はそれが存在しないことを知っています "。
あなたの場合、1つだけ.gitattributesが必要であり、次のようなkeepTheirsスクリプトが必要です。

mv -f $3 $2
exit 0

git merge --strategy=theirsシミュレーション#1

マージとして表示され、上流が最初の親になります。

Jefromi メンション(コメント内)merge -s ours、上流で(または上流から始まる一時ブランチで)作業をマージし、そのマージの結果にブランチを早送りします。

git checkout -b tmp Origin/upstream
git merge -s ours downstream         # ignoring all changes from downstream
git checkout downstream
git merge tmp                        # fast-forward to tmp HEAD
git branch -D tmp                    # deleting tmp

これには、上流の祖先を最初の親として記録するという利点があるため、mergeは、「このトピックブランチを破棄して置き換える」ではなく、「この古いトピックブランチを吸収する」ことを意味します。アップストリーム」

(2011年編集):

このワークフローはこれで報告されました OPによるブログ投稿

なぜこれが再び必要なのですか?

レポジトリがパブリックバージョンとは関係ない限り、これで問題ありませんでしたが、他のチームメンバーや外部の貢献者とWIPでコラボレーションできるようになりたいので、パブリックブランチが他の人が分岐したり引き出したりするための信頼性。つまり、リモートバックアップにプッシュしたものをリベースしてリセットする必要はありません。GitHubとパブリックにあるからです。

だから、私はどのように進むべきかを残しています。
99%の確率で、コピーがアップストリームマスターに送られるため、ほとんどの場合、マスターを使用してアップストリームにプッシュします。
しかし、時々、wipにあるものは、アップストリームに入るものによって無効になり、wipの一部を放棄します。
その時点で、マスターをアップストリームとの同期に戻したいが、パブリックにプッシュされたマスターのコミットポイントを破棄したくない。つまり私は、私のコピーを上流と同一にする変更セットで終わる上流とのマージを望んでいます
そしてそれがgit merge --strategy=theirsすべきです。


git merge --strategy=theirsシミュレーション#2

マージとして表示し、私たちのものを最初の親として表示します。

jcwenger により提案)

git checkout -b tmp upstream
git merge -s ours thebranch         # ignoring all changes from downstream
git checkout downstream
git merge --squash tmp               # apply changes from tmp but not as merge.
git rev-parse upstream > .git/MERGE_HEAD #record upstream 2nd merge head
git commit -m "rebaselined thebranch from upstream" # make the commit.
git branch -D tmp                    # deleting tmp

git merge --strategy=theirsシミュレーション#3

これ ブログ投稿の言及

git merge -s ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend

履歴に「がらくた」があるからではなく、これを行いたい場合もありますが、おそらくリベースを避けるべき公開リポジトリの開発のベースラインを変更したいからです


git merge --strategy=theirsシミュレーション#4

(同じブログ投稿)

または、ローカルのアップストリームブランチを早送りできるようにしたい場合、潜在的な妥協点は、sid/unstableの場合、アップストリームブランチを時々リセット/リベースできます(最終的にアウトになるイベントに基づいて)上流プロジェクトの側であなたのコントロールの)。
これは大したことではなく、その前提で作業することは、ローカルのアップストリームブランチを早送りの更新のみを行う状態に保つことが容易であることを意味します。

git branch -m upstream-unstable upstream-unstable-save
git branch upstream-unstable upstream-remote/master
git merge -s ours upstream-unstable
git diff --binary ref-to-be-merged | git apply -R --index --exclude="debian/*"
git commit -F .git/COMMIT_EDITMSG --amend

git merge --strategy=theirsシミュレーション#5

Barak A. Pearlmutter により提案):

git checkout MINE
git merge --no-commit -s ours HERS
git rm -rf .
git checkout HERS -- .
git checkout MINE -- debian # or whatever, as appropriate
git gui # edit commit message & click commit button

git merge --strategy=theirsシミュレーション#6

(同じ提案 Michael Gebetsroither ):

Michael Gebetsroitherは、私が「ごまかしている」と主張し、低レベルの配管コマンドで別のソリューションを提供しました。

(gitのみのコマンドでは不可能な場合はgitではありません。diff/ patch/applyを使用したgit内のすべては実際の解決策ではありません;)。

# get the contents of another branch
git read-tree -u --reset <ID>
# selectivly merge subdirectories
# e.g superseed upstream source with that from another branch
git merge -s ours --no-commit other_upstream
git read-tree --reset -u other_upstream     # or use --prefix=foo/
git checkout HEAD -- debian/
git checkout HEAD -- .gitignore
git commit -m 'superseed upstream source' -a
93
VonC

あなたがする必要があるように思えます:

$ git reset --hard Origin/master

プッシュアップストリームに変更がなく、単にアップストリームブランチを現在のブランチにしたい場合は、これを行います。これをローカルで行うことは有害ではありませんただしマスターにプッシュされていないローカルの変更**は失われます。

**コミットはまだgit reflog、通常少なくとも30日間。

13
wuputah

これはかなり簡単にできるようになりました。

$ git fetch Origin
$ git merge Origin/master -s recursive -Xtheirs

これにより、Originと同期してローカルリポジトリが取得され、履歴が保持されます。

12
user1828582

git merge -s theirs ref-to-be-mergedの別のシミュレーション:

git merge --no-ff -s ours ref-to-be-merged         # enforce a merge commit; content is still wrong
git reset --hard HEAD^2; git reset --soft HEAD@{1} # fix the content
git commit --amend

ダブルリセットの代わりに、リバースパッチを適用します。

git diff --binary ref-to-be-merged | git apply -R --index
5
michas

配管コマンドの助けがほとんどない方法もあります-私見は最も簡単です。 2つの分岐の場合に「彼ら」をエミュレートしたいとします:

head1=$(git show --pretty=format:"%H" -s foo)
head2=$(git show --pretty=format:"%H" -s bar)
tree=$(git show --pretty=format:"%T" -s bar)
newhead=$(git commit-tree $tree -p $head1 -p $head2 <<<"merge commit message")
git reset --hard $newhead

これは、任意の数のヘッド(上記の例では2)をそれらの1つのツリー(上記の例では「theirs」ツリーを提供)を使用してマージし、diff/fileの問題を無視します(commit-treeは低レベルコマンドなので、それらは気にしません)。頭はちょうど1であることに注意してください( "theirs"を使ったチェリーピックと同等です)。

どの親の頭が最初に指定されるかは、いくつかのことに影響を与える可能性があることに注意してください(たとえば、git-logコマンドの--first-parentを参照)-それを覚えておいてください。

Git-showの代わりに、ツリーとコミットハッシュを出力できるものなら何でも使用できます-解析に使用されるものは何でも(cat-file、rev-list、...)。 git commit --amendを使用してすべてをフォローし、コミットメッセージをインタラクティブに美しくすることができます。

3
Michal Soltys

Git reset BACKWARDSを使用してください!

ブランチをgit resetを使用して他のコミットのように見せることはできますが、ラウンドアバウト方法で行う必要があります。

コミット<old>のブランチをコミット<new>のようにするには、次のようにします。

git reset --hard <new>

<new>を作業ツリーのコンテンツにするため。

それから

git reset --mixed <old> 

ブランチを元のコミットに戻すにはただし、作業ツリーを残します<new>state

その後、ブランチを<new>コミットの内容と正確に一致させるために、変更を追加してコミットできます。

<old>状態から<new>状態に移行するには、git resetを実行する必要があるのは直観に反しますfrom<new>to<old>。ただし、オプション--mixedを使用すると、作業ツリーは<new>に残され、ブランチポインターは<old>に設定されるため、変更がコミットされるとブランチは希望どおりに見えます。

警告

コミットの追跡を忘れないでください。 <old>を実行するときにgit reset --hard <new>が何であるかを忘れてください。

1
Ivan

ヘビーハンド、しかし地獄、何が間違っているのでしょうか?

  • Yのように見せたいブランチXを確認します。
  • cp -r .git/tmp
  • ブランチYをチェックアウトする
  • rm -rf .git && cp -r /tmp/.git。
  • 違いをコミットしてプッシュ
  • できました。
1
sscarduzio

リモートのアップストリームブランチに変更し、git mergeマージ戦略をoursに設定して。

git checkout Origin/master
git merge dev --strategy=ours
git commit ...
git Push

すべての履歴は引き続き存在しますが、余分なマージコミットがあります。ここで重要なことは、目的のバージョンから開始し、oursを実際のgithubのブランチとマージすることです。

1
kelloti

私はそれらの役割に従いました:

オリジンを取得し、ブランチからハードにリセットしてから、それらから再帰的に実行し、プッシュをブランチに強制します

自分のリスクで

git fetch Origin
git reset --hard Origin/<branch>
git merge Origin/<branch> -s recursive -Xtheirs
git Push -f <remote> <branch>
0
esso