2012-05-17 21 views
9

私は支店にいますa。ブランチbをブランチcにマージします。マージは早送りではありませんが、手動で解決する必要はありません。 (もっとも単純なケースではありませんが、最も難しいものではありませんので、Gitが人間を必要とせずに単独で行うことができます)チェックアウトされていないブランチに非早送りgitマージを行う方法はありますか?

これを行う方法はありますかブランチをチェックアウトせずにbからcにマージしますか?どうやって?

更新:これを行うことができる別のGit実装について知っていれば、それも有効な解決策になります。しかし、プログラムでチェックアウトを行うスクリプトを書くことは良い解決策ではありません。なぜなら、それでも私はきれいな作業ディレクトリを必要とするからです。

+0

http://stackoverflow.com/questions/6548046/merging-to-a-branch-in-git-without-switching-to-it(「git push bspec cspec'」) –

+0

'git push 'のドットはどういう意味ですか? –

+0

また、マージが早送りではないかもしれないことを私の質問で明記しました。これはまだ動作しますか? –

答えて

7

マージに両方のブランチに触れたファイルが含まれていない場合は、git read-treegit write-treeにサイドバンドGIT_INDEX_FILEが必要です。これはそれを行う必要があります。

あなたはまた bcと全く関係のない枝を治療し、その結果のマージではなくどちらかに欠損として不足しているファイルを処理するよりも、それぞれのファイルを結合するために git mktree </dev/nullの代わり merge-baseを使用することができ
#!/bin/sh 
export GIT_INDEX_FILE=.git/aux-merge-index 
trap 'rm -f '"'$GIT_INDEX_FILE'" 0 1 2 3 15 
set -e 
git read-tree -im `git merge-base $2 $1` $2 $1 
git write-tree \ 
| xargs [email protected] git commit-tree @ -p $2 -p $1 -m "Merge $1 into $2" \ 
| xargs git update-ref -m"Merge $1 into $2" refs/heads/$2 

を。

あなたのマージは早送りではないと言われていますので、上記のシーケンスをあなたが望むものにするにはread-treeのドキュメントを読む必要があります。 --aggressiveは正しいかもしれませんが、ブランチ間の実際の違いによって異なります。

編集はあなたが試すことができます回避策を私が言ったか、コメント

+1

さて、私の心はうまく吹かれました。あなたがここで何をしたのかを説明するケア? –

+1

インデックスは、あなたの作業ツリーのファイルのタイムスタンプと結合されたオブジェクトdbのほんの一部です。 read-treeは、指定されたツリーからインデックスをロードします。 -iはworktreeを無視し、-mは単純なマージを行います。 write-treeはインデックス状態をリポジトリに入れ、commit-treeはコミットを行い、update-refはrefを更新します。読んだツリーのマージオプションに関するドキュメントを読んでいく必要があります。ここでは、どんな状況でもファイルを削除しないように設定されています。いずれかのブランチで削除を伝播させたい場合は、 'git mktree jthill

+0

さて、私はついにそれを試す時間がありました。私は 'I @'を 'i @'に修正しなければなりませんでした。 (Typo?)これが確実に動作することができれば、それは間違いなく補助レポのアプローチよりも優れています。今、いくつかの質問があります。1.完全に標準的なマージ戦略を使用したい。それは? 2.マージのための標準コミットメッセージを作成することはできますか? –

1

お客様作業ディレクトリが汚れていてもスクリプトを作成してください。最初に変更を隠しておく必要があります。

git stash 
git checkout c 
git merge b 
git checkout a 
git stash pop 
+1

私は 'git stash'を使うこともお勧めします。これは私がOPと同じことをするのによく使うものです。 – neevek

+0

(私が取り組んでいる)Windowsの隠しは遅いので、それほど長く待たなければならないのは私にとって魅力的ではありません。 –

+0

次に、私は選択肢があるとは思わない、とにかくあなたがマージしたいブランチは*現在のブランチ*でなければならない。 stashやcommitをせずに、現在のブランチを 'a'のままにすることはできません...あるいはいくつかのgitエキスパートにはよりよい解決策がありますか? – neevek

5

作業ディレクトリをきれいにする必要がありますしないようにあなたの条件を考えると、私はあなたがさらにいくつかのスクリプトを経由して、作業ツリーまたはインデックスのどちらかをきれいにしたくないということを意味すると仮定します。その場合、現在のローカルリポジトリの範囲内で解決策を見つけることはできません。 Gitはマージ時にこのインデックスを広範囲に使用します。競合がなければ作業ツリーについてはわかりませんが、一般的に、マージは現在チェックアウトされているブランチと密接に結びついています。

しかし、あなたの現在のレポで何かを変更する必要はありません。ただし、レポの複製を作成または作成する必要があります。基本的には、レポをクローンし、クローンでマージして元のレポに戻します。どのように動作するかの簡単な例があります。

最初に、作業するサンプルレポが必要です。次の一連のコマンドで作成されます。現在のブランチにはmaster、そしてマージする準備が整ったブランチはchange-foochange-barという2つのブランチになります。

mkdir background-merge-example 
cd background-merge-example 
git init 
echo 'from master' > foo 
echo 'from master' > bar 
git add . 
git commit -m "add foo and bar in master" 
git checkout -b change-foo 
echo 'from foo branch' >> foo 
git commit -am "update foo in foo branch" 
git checkout -b change-bar master 
echo 'from bar branch' >> bar 
git commit -am "update bar in bar branch" 
git checkout master 

さて、あなたはmasterで作業している、とあなたはchange-foochange-barをマージしたいしていることを想像してみてください。

$ git log --oneline --graph --all 
* c60fd41 update bar in bar branch 
| * e007aff update foo in foo branch 
|/ 
* 77484e1 add foo and bar in master 

次のシーケンスは、現在のマスターブランチを妨害することなくマージを実行します。マージを行う、それを押して、

# clone with absolute instead of relative path, or the remote in the clone will 
# be wrong 
git clone file://`realpath .` tmp 
cd tmp 
# this checkout auto-creates a remote-tracking branch in newer versions of git 
# older versions will have to do it manually 
git checkout change-foo 
# creating a tracking branch for the other remote branch is optional 
# it just makes the commit message look nicer 
git branch --track change-bar origin/change-bar 
git merge change-bar 
git push origin change-foo 
cd .. 
rm -rf tmp 

簡単に言えば、サブディレクトリに現在のレポのクローンを作成し、そのディレクトリを入力します:スクリプトにこれをパック、あなたが素敵な「バックグラウンド・マージ」コマンドを持っています元のレポに戻ります。終了後、サブディレクトリが削除されます。大規模なプロジェクトでは、毎回新しくクローンを作成するのではなく、最新の状態に保たれた専用のクローンを作成したい場合があります。マージしてプッシュすると、次のようになります。

$ git log --oneline --graph --all 
* 24f1916 Merge branch 'change-bar' into change-foo 
|\ 
| * d7375ac update bar in bar branch 
* | fed4757 update foo in foo branch 
|/ 
* 6880cd8 add foo and bar in master 

質問がありますか?

+0

大規模な書き込みをありがとう。私はまだこれを消化しています。その間にいくつかの質問があります:1.私はgitクローンの3つのタイプがあることについて読むことを覚えています:スタンダード、フルコピー、そして共有。 (用語はgit-guiに特有のものかもしれません。)私はFull Copyを使っただけです。私はこれのために他のものを使うべきですか? 2. Gitは作業ディレクトリがない "裸の" reposも許可していると聞きました。 Gitはこれらの種類のリポジトリでマージを許可していますか?もしそうなら、それは一時リポジトリにとっては良い選択でしょうか? –

+2

3種類:浅い、裸、 "正常"。この場合、gitリポジトリの浅いコピーは勧められません(クローン作成時に--depthオプションを使用)。私は、あなたが2つのブランチの共通の親を逃した場合、特に浅いコピーで2つのブランチのマージを実行できることを証明しません。しかし、gitは 'git pull'を使うことができるので、浅いクローン(裸のリポジトリではない)でのマージが可能です。この場合、私は完全な/単純なクローンを行います。 –

+0

上記の文について、「Gitはマージ時に広範囲に索引を使用します」:別のレポを作成するのではなく、Gitがマージを行うのと同じリポジトリに補助索引ファイルを作成する方法があると思いますか? –

-1

このanswerに暗黙の左いくつかのペイロードを説明巻き上げ無関係木編集2 を処理するために、空のツリーベースを追加しました。

いいえ、ありません。コンフリクトを解決できるようにするために、ターゲットブランチのチェックアウトが必要です(Gitが自動的にマージできない場合)。

ただし、マージが早送りのものであれば、実際には何もマージする必要がないので、ターゲットブランチをチェックアウトする必要はありません。ブランチを更新するだけです新しい頭頂部を指すようにします。これはgit branch -fで行うことができます。

git branch -f branch-b branch-a
branch-bをbranch-aの先頭を指すように更新します。

+0

(a)彼は早送りではなく、(b)これは壊れた歴史を残すと言った – jthill

+0

あなたは正しいです。私はそれが*早送りのように質問を誤解しました。私の悪い。 – sparrow

関連する問題