私は、変更を加えたブランチを取得し、分岐したアップストリームと同一になるように戻そうとしています。変更は両方ともローカルであり、githubにプッシュされているため、どちらもgit reset
またはgit rebase
は履歴を変更するため、本当に実行可能です。これは、すでにプッシュされているブランチでは悪いことです。
私も試しましたgit merge
さまざまな戦略がありますが、いずれもローカルの変更を元に戻しません。つまり、ファイルを追加した場合、マージによって他のファイルが元に戻る可能性がありますが、アップストリームにはないファイルが残っています。
アップストリームから新しいブランチを作成することもできますが、変更履歴を適用してすべての変更を適用してブランチを取得し、再びアップストリームと同じにすることで、その変更を安全にプッシュできます履歴を壊すことなく。そのようなコマンドまたは一連のコマンドはありますか?
カスタムマージドライバー「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
あなたがする必要があるように思えます:
$ git reset --hard Origin/master
プッシュアップストリームに変更がなく、単にアップストリームブランチを現在のブランチにしたい場合は、これを行います。これをローカルで行うことは有害ではありませんただしマスターにプッシュされていないローカルの変更**は失われます。
**コミットはまだgit reflog
、通常少なくとも30日間。
これはかなり簡単にできるようになりました。
$ git fetch Origin
$ git merge Origin/master -s recursive -Xtheirs
これにより、Originと同期してローカルリポジトリが取得され、履歴が保持されます。
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
配管コマンドの助けがほとんどない方法もあります-私見は最も簡単です。 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を使用してすべてをフォローし、コミットメッセージをインタラクティブに美しくすることができます。
ブランチを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>
が何であるかを忘れてください。
ヘビーハンド、しかし地獄、何が間違っているのでしょうか?
リモートのアップストリームブランチに変更し、git merge
マージ戦略をours
に設定して。
git checkout Origin/master
git merge dev --strategy=ours
git commit ...
git Push
すべての履歴は引き続き存在しますが、余分なマージコミットがあります。ここで重要なことは、目的のバージョンから開始し、ours
を実際のgithubのブランチとマージすることです。
私はそれらの役割に従いました:
オリジンを取得し、ブランチからハードにリセットしてから、それらから再帰的に実行し、プッシュをブランチに強制します
自分のリスクで
git fetch Origin
git reset --hard Origin/<branch>
git merge Origin/<branch> -s recursive -Xtheirs
git Push -f <remote> <branch>