私は2つの並行した(しかし現在実験的な)開発ブランチを持つ新しいプロジェクトにgitを使っています。
master
:既存のコードベースのインポートと私が一般的に確信しているいくつかの改造exp1
:実験的ブランチ#1exp2
:実験的ブランチ#2exp1
とexp2
は、2つの非常に異なるアーキテクチャ上のアプローチを表します。私がさらに進んでいくまでは、どちらがうまくいくのかを知る方法がありません。私はあるブランチで進歩するにつれて、他のブランチで役立つような編集があり、それらをマージしたいと思うことがあります。
他のすべてを残しながら、ある開発ブランチから別の開発ブランチへの選択的な変更をマージするための最良の方法は何ですか?
私が検討したアプローチ:
git merge --no-commit
の後に、私がブランチ間で共通にしたくないような多数の編集の手動アンステージングが続きます。
共通ファイルを一時ディレクトリに手動でコピーし、続いて他のブランチに移動するためのgit checkout
を実行してから、一時ディレクトリから作業ツリーに手動でコピーします。
上記のバリエーション。今のところexp
ブランチを放棄し、実験用に2つの追加ローカルリポジトリを使用してください。これにより、ファイルの手動コピーがはるかに簡単になります。
これらの3つのアプローチはすべて退屈でエラーが発生しやすいようです。もっと良いアプローチがあるといいのですが。 git-merge
をより選択的にするフィルタパスパラメータに似たもの。
1つのブランチから個々のコミットを取得するには、 cherry-pick コマンドを使用します。
必要な変更が個々のコミットにない場合は、次に示す方法を使用して コミットを個々のコミットに分割します 。大まかに言えば、git rebase -i
を使用して元のコミットを編集し、次にgit reset HEAD^
を使用して変更を元に戻し、git commit
を使用して履歴内の新しいコミットとしてコミットします。
ここにはもう一つ別のNiceメソッドがあります 個々のファイルに異なる変更を分割したい場合は、git add --patch
または場合によってはgit add --interactive
を使うことができます(そのページで検索してください)。 "スプリット")。
変更を分割したら、必要なものだけを選択することができます。
私は上であなたによって言及されたのと全く同じ問題を抱えていました。しかし、私は答えを説明する際に this をより明確に見つけました。
概要:
マージしたいブランチからのパスをチェックアウトします。
$ git checkout source_branch -- <paths>...
ヒント:リンク先の投稿にあるように、--
がなくても動作します。
またはハンクを選択的にマージする
$ git checkout -p source_branch -- <paths>...
または、resetを使用してから-p
オプションを付けて追加します。
$ git reset <paths>...
$ git add -p <paths>...
最後にコミットする
$ git commit -m "'Merge' these changes"
あるブランチから別のブランチにファイルを選択的にマージするには、次のコマンドを実行します。
git merge --no-ff --no-commit branchX
ここでbranchX
は、マージしたいブランチから現在のブランチへの分岐です。
--no-commit
オプションはGitによってマージされたファイルを実際にコミットせずにステージングします。これにより、マージしたファイルを変更して自分でコミットすることができます。
ファイルをマージする方法に応じて、4つのケースがあります。
この場合、Gitがそれらを自動的にマージしてコミットする方法でマージされたファイルを受け入れます。
たとえば、現在のブランチのバージョンを保持し、マージ元のブランチのバージョンを無視したいとします。
現在のブランチのバージョンを選択するには、次のコマンドを実行してください。
git checkout HEAD file1
これは現在のブランチのfile1
のバージョンを取得し、Gitによって自動化されたfile1
を上書きします。
実行します。
git checkout branchX file1
これはbranchX
内のfile1
のバージョンを検索し、Gitによって自動マージされたfile1
を上書きします。
file1
で特定のマージのみを選択したい場合です。この場合、修正したfile1
を直接編集し、file1
のバージョンを希望するものに更新してからコミットすることができます。
Gitがファイルを自動的にマージできない場合は、ファイルを " unmerged "として報告し、手動で競合を解決する必要がある場所にコピーを作成します。
例を使ってさらに説明するために、branchX
を現在のブランチにマージしたいとしましょう。
git merge --no-ff --no-commit branchX
次にgit status
コマンドを実行して、変更されたファイルの状況を表示します。
例えば:
git status
# On branch master
# Changes to be committed:
#
# modified: file1
# modified: file2
# modified: file3
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: file4
#
file1
、file2
、およびfile3
は、gitが正常に自動マージしたファイルです。
これが意味するのは、これら3つのファイルすべてに対するmaster
とbranchX
の変更が、矛盾なくまとめられているということです。
git diff --cached
を実行して、マージがどのように行われたかを調べることができます。
git diff --cached file1
git diff --cached file2
git diff --cached file3
git commit
file1
をマージしたくなくて、現在のブランチにそのバージョンを保持したい場合実行する
git checkout HEAD file1
file2
をマージせず、branchX
内のバージョンのみを必要とする場合実行する
git checkout branchX file2
file3
を自動的にマージしたい場合は、何もしないでください。Gitはこの時点ですでにマージしています。
上記のfile4
はGitによる失敗したマージです。これは、同じ行で発生する両方の分岐に変更があることを意味します。これは、競合を手動で解決する必要がある場所です。ファイルを直接編集するか、file4
にしたいブランチのバージョンに対してcheckoutコマンドを実行することで、マージした内容を破棄できます。
最後に、git commit
を忘れないでください。
私は上記のアプローチが好きではありません。チェリーピックを使用することは単一の変更を選択するのに最適ですが、いくつかの悪い変更を除いてすべての変更を取り入れたいのであれば面倒です。これが私のアプローチです。
Git mergeに渡すことができる--interactive
引数はありません。
これが代替案です:
ブランチの 'feature'に変更があり、全部ではなく一部を 'master'に移動させたい(つまり、それぞれを選択してコミットしたくない)。
git checkout feature
git checkout -b temp
git rebase -i master
# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change
# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
git checkout master
git pull . temp
git branch -d temp
シェルスクリプトでそれをラップして、masterを$ toに、featureを$ fromに変更してください。
#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp
別の方法があります:
git checkout -p
これはgit checkout
とgit add -p
の組み合わせであり、まったくあなたが探しているものかもしれません。
-p, --patch
Interactively select hunks in the difference between the <tree-ish>
(or the index, if unspecified) and the working tree. The chosen
hunks are then applied in reverse to the working tree (and if a
<tree-ish> was specified, the index).
This means that you can use git checkout -p to selectively discard
edits from your current working tree. See the “Interactive Mode”
section of git-add(1) to learn how to operate the --patch mode.
これらの答えのいくつかはかなり良いものですが、実際にはOPの元の制約である特定のブランチから特定のファイルを選択することに答えた人はいないように感じます。このソリューションはそれを行いますが、多くのファイルがある場合は退屈かもしれません。
master
、exp1
、およびexp2
のブランチがあるとします。各実験ブランチから1つのファイルをマスターにマージします。私はこのようなことをします:
git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b
# save these files as a stash
git stash
# merge stash with master
git merge stash
これにより、必要なファイルごとにファイル内差分が得られます。これ以上何もない。それ以下。バージョン間で根本的に異なるファイル変更があると便利です。私の場合は、アプリをRails 2からRails 3に変更します。
EDIT:これはファイルをマージしますが、スマートマージを行います。ファイル内の差分情報を取得するためにこのメソッドを使用する方法を見つけることができませんでした(おそらくそれは極端な違いのためかもしれません。-s recursive -X ignore-all-space
オプションを使用しない限り、空白のような厄介な小さなものがマージされます)
1800情報の答えは完全に正しいです。しかし、gitの新参者として、 "use git cherry-pick"は私がインターネットをもう少し掘り下げることなしにこれを理解するのに十分ではなかったので、私は誰か他の誰かが似たようなボート。
私のユースケースは、他の誰かのgithubブランチから自分のものに変更を選択的に引き込みたいというものでした。変更があるローカルブランチがすでにある場合は、ステップ2と5から7を実行するだけで済みます。
変更を加えたローカルブランチを作成します(作成されていない場合)。
$ git branch mybranch <base branch>
それに切り替えます。
$ git checkout mybranch
他の人のアカウントから必要な変更を引き下げます。まだ持っていないのなら、リモートとして追加したいでしょう。
$ git remote add repos-w-changes <git url>
彼らの枝からすべてを引き下げます。
$ git pull repos-w-changes branch-i-want
コミットログを表示して、必要な変更を確認します。
$ git log
変更を取り入れたいブランチに戻ります。
$ git checkout originalbranch
チェリーは、ハッシュを使用してコミットを1つずつ選択します。
$ git cherry-pick -x hash-of-commit
ハットチップス: http://www.sourcemage.org/Git_Guide
これがmaster
ブランチのMyclass.Java
ファイルをMyclass.Java
ブランチのfeature1
に置き換える方法です。 master
にMyclass.Java
が存在しなくても機能します。
git checkout master
git checkout feature1 Myclass.Java
これは上書きされ(マージではなく)、マスターブランチでのローカルの変更は無視されます。
2つのブランチからの特定のファイルを実際に merge 特定のファイルに置き換えるのではなく、特定のファイルを別のブランチからのファイルに置き換えるのではありません。
git diff branch_b > my_patch_file.patch
現在のブランチとbranch_bの間の違いのパッチファイルを作成します
git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch
Includeパターンでは*
をワイルドカードとして使用できます。
スラッシュはエスケープする必要はありません。
また、代わりに--excludeを使用してパターンに一致するファイルを除くすべてのものに適用するか、または-Rでパッチを元に戻すことができます。
-p1オプションは* unix patchコマンドと、パッチファイルの内容に各ファイル名の先頭にa/
またはb/
(またはパッチファイルの生成方法に応じてそれ以上)を追加したものです。パッチが適用される必要があるファイルへのパスに実際のファイルを見つけ出してください。
その他のオプションについてはgit-applyのmanページをチェックしてください。
明らかにあなたはあなたの変更をコミットしたいと思うでしょう、しかしあなたがあなたがあなたのコミットをする前にしたいと思う他のいくつかの関連する微調整がないと言うのは誰です。
たとえ「単純な」マージが、あなたが望まないもっと多くの変更をもたらしていたとしても、他のブランチからのほんの2、3のファイルを最小限の手間で追跡することができるのです。
最初に、あなたがコミットしようとしているのは作業ディレクトリ内のファイルに対して何もしないで、コミットしようとしていることがマージであることを事前に宣言するという珍しいステップを踏みます。
git merge --no-ff --no-commit -s ours branchname1
。 。 。 "branchname"は、あなたがマージしていると主張するものなら何でもです。あなたがすぐにコミットしようとした場合、それは変更を加えることはありませんが、それはまだ他のブランチからの祖先を示すでしょう。もっとブランチ/タグ/ etcを追加することができます。必要ならコマンドラインにも。ただし、現時点では、コミットする変更はありませんので、次に他のリビジョンからファイルを入手してください。
git checkout branchname1 -- file1 file2 etc
他の複数のブランチからマージしている場合は、必要に応じて繰り返します。
git checkout branchname2 -- file3 file4 etc
もう一方のブランチからのファイルは、履歴付きでコミットされる準備ができているインデックスにあります。
git commit
そのコミットメッセージで説明することがたくさんあります。
それがはっきりしていない場合には、注意してください、これはやるべきことがめちゃくちゃになることです。それは「ブランチ」が何のためにあるのかという精神ではありません、そしてここでチェリーピックはあなたがしていることをするためのもっと誠実な方法です。前回持っていなかった同じブランチ上の他のファイルに対して別の「マージ」を実行したい場合は、「既に最新」のメッセージが表示されて停止します。 「from」ブランチには複数の異なるブランチがあるはずです。
この記事 は最も単純な答えを含んでいます。ただしてください:
$ #git checkout <branch from which you want files> <file paths>
例:
$ #pulling .gitignore file from branchB into current branch
$ git checkout branchB .gitignore
詳細については投稿を参照してください。
私は少し遅れていることを知っていますが、これは選択的ファイルをマージするための私のワークフローです。
#make a new branch ( this will be temporary)
git checkout -b newbranch
# grab the changes
git merge --no-commit featurebranch
# unstage those changes
git reset HEAD
(you can now see the files from the merge are unstaged)
# now you can chose which files are to be merged.
git add -p
# remember to "git add" any new files you wish to keep
git commit
最も簡単な方法は、リポジトリをマージしたいブランチに設定してから実行することです。
git checkout [branch with file] [path to file you would like to merge]
走れば
git status
ファイルがすでにステージングされているのがわかります。
それから走りなさい
git commit -m "Merge changes on '[branch]' to [file]"
簡単です。
Gitがまだそのような便利なツールを持っていないのは不思議です。現在のバージョンブランチからの ほんの一部の バグ修正によって、(まだ多くのソフトウェアユーザがいる)古いバージョンブランチを更新するとき、私はそれを頻繁に使用します。この場合、トランク内のファイルから ほんの数 - 行のコードをすばやく取得する必要があります(他の多くの変更を無視します(古いバージョンに入ることは想定されていません)...そしてもちろん 対話型の3方向 mergeがこの場合必要です。git checkout --patch <branch> <file path>
はこの選択的なマージ目的には使用できません。
あなたはそれを簡単にすることができます:
グローバルの[alias]
またはローカルの.gitconfig
ファイルの.git/config
セクションにこの行を追加するだけです。
[alias]
mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; /C/BCompare3/BCompare.exe $2.theirs $2 $2.base $2; rm -f $2.theirs; rm -f $2.base;' -"
それはあなたが比較を超えて使用することを意味します。必要ならばあなたの選んだソフトウェアに変えるだけです。対話型選択マージを必要としない場合は、3方向自動マージに変更することもできます。
[alias]
mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; git merge-file $2 $2.base $2.theirs; rm -f $2.theirs; rm -f $2.base;' -"
その後、このように使用してください:
git mergetool-file <source branch> <file path>
これにより、他のブランチにあるすべてのファイルの真の選択的な tree-way mergeの機会が得られます。
私は上であなたによって言及されたのと全く同じ問題を抱えていました。しかし、私は このgitブログ /答えを説明することでより明確に - を見つけた。
上記のリンクからのコマンド:
#You are in the branch you want to merge to
git checkout <branch_you_want_to_merge_from> <file_paths...>
それはあなたが探していたものではありませんが、私にとっては役に立ちました。
git checkout -p <branch> -- <paths> ...
それはいくつかの答えの組み合わせです。
私は上記の 'git-interactive-merge'の回答が好きですが、もっと簡単なものがあります。対話式および以下のリベースの組み合わせを使用して、gitにこれをさせてください。
A---C1---o---C2---o---o feature
/
----o---o---o---o master
そのため、 'feature'ブランチ(ブランチポイント 'A')のC1とC2が必要ですが、現時点ではそれ以外は必要ありません。
# git branch temp feature
# git checkout master
# git rebase -i --onto HEAD A temp
これは、上記のように、対話型エディタに移動し、そこでC1とC2の 'pick'行を選択します(上記のとおり)。保存して終了すると、リベースが続行され、master + C1 + C2のブランチ[temp]とHEADが表示されます。
A---C1---o---C2---o---o feature
/
----o---o---o---o-master--C1---C2 [HEAD, temp]
それから、masterをHEADに更新してtempブランチを削除すればいいのです。
# git branch -f master HEAD
# git branch -d temp
私はやります
git diff commit1..commit2ファイルパターン| git-apply --index && git commit
これにより、ブランチからのファイルパターンのコミット範囲を制限できます。
から盗まれた: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
私はこの質問が古く、他にもたくさんの答えがあることを知っていますが、私は自分自身でディレクトリを部分的にマージするための 'pmerge'と呼ばれるスクリプトを書きました。それは進行中の作業であり、私はまだgitとbashスクリプトの両方を学んでいます。
このコマンドはgit merge --no-commit
を使用してから、指定されたパスと一致しない変更を適用解除します。
使用法:git pmerge branch path
例:git merge develop src/
私はそれを徹底的にテストしていません。作業ディレクトリには、コミットされていない変更や追跡されていないファイルがないようにします。
#!/bin/bash
E_BADARGS=65
if [ $# -ne 2 ]
then
echo "Usage: `basename $0` branch path"
exit $E_BADARGS
fi
git merge $1 --no-commit
IFS=$'\n'
# list of changes due to merge | replace nulls w newlines | strip lines to just filenames | ensure lines are unique
for f in $(git status --porcelain -z -uno | tr '\000' '\n' | sed -e 's/^[[:graph:]][[:space:]]\{1,\}//' | uniq); do
[[ $f == $2* ]] && continue
if git reset $f >/dev/null 2>&1; then
# reset failed... file was previously unversioned
echo Deleting $f
rm $f
else
echo Reverting $f
git checkout -- $f >/dev/null 2>&1
fi
done
unset IFS
git reset --soft branch
はどうですか?まだ誰も言及していないことに驚きました。
私にとっては、他のブランチから選択的に変更を選択するのが最も簡単な方法です。なぜなら、このコマンドは私の作業ツリーにすべてのdiffの変更を入れ、必要なものを簡単に選択または元に戻すことができるからです。このようにして、私はコミットされたファイルを完全に制御することができます。
read-tree
を使って、与えられたリモートツリーを現在のインデックスに読み込んだりマージしたりできます。
git remote add foo [email protected]/foo.git
git fetch foo
git read-tree --prefix=my-folder/ -u foo/master:trunk/their-folder
マージを実行するには、代わりに-m
を使用してください。
以下も参照してください。 サブディレクトリをgitにマージするにはどうすればよいですか。
ファイルによる選択的なマージ/コミットのための簡単なアプローチ:
git checkout dstBranch
git merge srcBranch
// make changes, including resolving conflicts to single files
git add singleFile1 singleFile2
git commit -m "message specific to a few files"
git reset --hard # blow away uncommitted changes
2つのブランチの現在のコミットの間にいくつかのファイルだけが変更された場合は、異なるファイルを調べて手動で変更をマージします。
git difftoll <branch-1>..<branch-2>
特定のディレクトリをマージして他のものをそのまま残して履歴を保存するだけでよい場合は、おそらくこれを試すことができます。実験する前にmaster
から新しいtarget-branch
を作成します。
以下の手順では、target-branch
とsource-branch
の2つのブランチがあり、マージしたいディレクトリdir-to-merge
がsource-branch
にあると仮定しています。また、ターゲットにdir-to-retain
のような他のディレクトリがあって、それを変更したくない、履歴を保持したくないディレクトリがあるとします。また、dir-to-merge
にマージの競合があると仮定します。
git checkout target-branch
git merge --no-ff --no-commit -X theirs source-branch
# the option "-X theirs", will pick theirs when there is a conflict.
# the options "--no--ff --no-commit" prevent a commit after a merge, and give you an opportunity to fix other directories you want to retain, before you commit this merge.
# the above, would have messed up the other directories that you want to retain.
# so you need to reset them for every directory that you want to retain.
git reset HEAD dir-to-retain
# verify everything and commit.
変更されたファイルがそれほど多くない場合は、追加のコミットは不要です。
1.一時的にブランチを複製する $ git checkout -b temp_branch
2.最後に必要なコミットにリセット $ git reset --hard HEAD~n
、ここでn
は戻る必要があるコミットの数です。
3.元のブランチから各ファイルをチェックアウト $ git checkout Origin/original_branch filename.ext
必要に応じて、今すぐコミットして強制的にプッシュ(リモートを上書き)することができます。