vim-markdownをアップデート で vim-markdown をアップデートした、という話をしましたが、 このレポジトリはもともとForkしたもので、元のレポジトリの変化を追いつつ アップデートしたので(というか今回は元のレポジトリのアップデートをマージしただけ) その流れについてまとめておきます。
- レポジトリ設定
- Fork元のレポジトリにつなげる
- 元のレポジトリのアップデートをmasterにpull
- modをmaster(=Fork元の最新版)にrebase
- mergetoolでマージ
- originにpush
- 操作の取り消し等
レポジトリ設定
plasticboy/vim-markdown というレポジトリをForkして rcmdnk/vim-markdown というレポジトリを作りました。
元々のレポジトリにはmasterとmaster-hartsteinというブランチがありますが、 master-hartsteinというのは最初に他からインポートしたもの?か何かで 基本masterを使っています。
これをForkした rcmdnk/vim-markdown では、modというブランチを作ってここで変更を行っています。
masterは元のレポジトリを追いかける用に。
GitHubの方の設定で、レポジトリの Settings Default branchでデフォルトになるブランチをmodに変更しておきます。
これで通常git clone...
するとremotes/origin/HEADがorigin/modを指すようになり、
最初にこのブランチが現れる様になります。
Fork元のレポジトリにつなげる
まず、元のレポジトリをremoteとして加えます。
$ git remote add plasticboy [email protected]:plasticboy/vim-markdown
次に、このplasticboy/masterをorigin/masterに同期させたいわけですが、
その前に色々チェックしたいのでplasticboyをfetch
しておきます。
$ git fetch plasticboy
$ git br -a
master
* mod
remotes/origin/HEAD -> origin/mod
remotes/origin/marc-hartstein
remotes/origin/master
remotes/origin/mod
remotes/plasticboy/marc-hartstein
remotes/plasticboy/master
これで
$ git diff origin/master plasticboy/master
でplasticboy側でのその後の変化を見たり、
$ git diff origin/mod origin/master
で自分の所でどうアップデートしたのかを確認しておきます。
それから後でチェックするのを簡単にするため
$ git checkout master
$ git checkout -b master-tmp
$ git checkout mod
$ git checkout tag -a v0.0.1 -m "first version"
$ git push --tag
と、masterの現在地をテンポラリーブランチにとして作っておいて 1、 modの現在地の方はタグにしてGitHubの方へも送って置きました 。
元のレポジトリのアップデートをmasterにpull
$ git pull plasticboy master:master
plasticboyのmasterを意味するmaster:の部分は省略可能ですが、 これでplasticboyのmasterをローカルのmasterブランチにpull。
masterブランチは何もいじってないので特に問題なくアップデート出来ます。
modをmaster(=Fork元の最新版)にrebase
$ git rebase master mod
これで上手く行ったらpushして終了。 ただ、大概コンフリクトが出るのでその処理を。
$ git rebase master mod
First, rewinding head to replay your work on top of it...
Applying: first modified version
Using index info to reconstruct a base tree...
M README.md
M syntax/mkd.vim
Falling back to patching base and 3-way merge...
Auto-merging syntax/mkd.vim
CONFLICT (content): Merge conflict in syntax/mkd.vim
Auto-merging README.md
Failed to merge in the changes.
Patch failed at 0001 first modified version
The copy of the patch that failed is found in:
.../vim-markdown/.git/rebase-apply/patch
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
mergetoolでマージ
git mergetool
という便利なコマンドがあるのでこれを使います。
vimdiff
をこのコマンド内の編集用として使いたいので、
~/gitconfigに
[merge]
tool = vimdiff
keepBackup = false
を加えておきます 2。
これで、上の様なコンフリクトが起きた時に、
$ git mergetool
とするだけでvimdiff
によるマージ編集が立ち上がります。
この時に、keepBackup
がtrue
だと編集終了後に*.orig
というバックアップが
出来ますが、false
にしておくとこのバックアップ生成を無くすことが出来ます。
立ち上げると、
$ git mergetool
Merging:
syntax/mkd.vim
Normal merge conflict for 'syntax/mkd.vim':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (vimdiff):
こんな感じでどのファイルを修正するか表示してから編集に入ります。
編集画面は
|-----------------------|
| | | |
| LOCAL | BASE | REMOTE |
| | | |
|-----------------------|
| |
| MERGED |
| |
|-----------------------|
の様な4分割画面になります。 それぞれ:
- LOCAL: merge前の状態(上の場合ではpullした後のmasterの状態)
- BASE: LOCALとREMOTEの共通祖先の状態(上の場合ではpullする前(=master-tmp))の状態)
- REMOTE: LOCALとREMOTEの共通祖先の状態(上の場合ではmerge前のmodの状態)
- MERGED: 最終的にmerge後のファイル
となっています 3。
LOCAL(左)とBASE(真中)を比較しFork元のアップデートを確認、 REMOTE(右)とBASE(真中)を比較して自分の変更を確認、といった感じ。
Fork元のアップデートしたものに対して 自分の変更をマージする、という形なので ちょっとやっててLOCALとREMOTEの逆感を感じましたが。
そして、下のMERGEDの所にコンフリクトの結果の
....
<<<<<<< HEAD
aaaaaa
=======
bbbbbb
>>>>>>> master
といった感じの部分があるので、これらを編集してコンフリクトを解消していきます。
最終的にMERGEDが思い通りになったら保存して他のウィンドウの物は 編集せずにそのまま終了すればOK。
一つ解消できたら
$ git rebase --continue
で先ほどのrebaseの続きを実行。 で、これでコンフリクトが出てこなくなるまで頑張ります。
originにpush
$ git push origin master
でmasterを送って、
modの方は変更がコンフリクトするので強制上書きするため-f
を使って
$ git push -f origin mod
で送ってあげます。
以上で終了。
以下はおまけ。
操作の取り消し等
ファイルの変更の取り消し
file.txtに対する変更を取り消して元に戻したいときは
$ git checkout -- file.txt
--
は通常は必要ないですが、もし、戻したいファイル/ディレクトリと同名の
ブランチがあるとき、checkout
がブランチの変更になってしまうので、
そのようなときは--
を付けてあげるとファイル/ディレクトリに対する操作になります。
すべて戻したいときは
$ git checkout .
もし、作業中の物を全部破棄して前回コミット直後まで戻りたいときは
$ git reset --hard HEAD
で、綺麗サッパリに元通りに。
commitの取り消し
HEADと同様に、適当なコミット状態をgit log
等で見つけてきてそこまでもどりたいときは
$ git reset -hard 84984ad457bd4d8b38731207b226b0b763ed56b0
な感じでリビジョン番号を指定してあげればOK。
commitのやり直し
$ git commit --amend -m "re-commit..."
--amend
オプションで前回commitの上書き。
前回commit後にadd
とかしてなければメッセージだけ変更、
add
してるものがあれば前回のとまとめて一つのcommitを作ります。
rebaseを取り消す
rebaseするとcommitも順番が色々変わるので 上の方法だと上手くありません。
戻るにはgit reflog
でHEADの変更を確認して
$ git reflog
48fa912 HEAD@{0}: rebase finished: returning to refs/heads/mod
48fa912 HEAD@{1}: rebase: Update README.md
5e61711 HEAD@{2}: rebase: added bitdeli
f20f6e9 HEAD@{3}: rebase: fixed liquied tags
1b053fd HEAD@{4}: rebase: update comment (valid for non-single like tag)
1427250 HEAD@{5}: rebase: added liquid output
...
03e10b1 HEAD@{47}: checkout: moving from mod to master
edf3bc9 HEAD@{48}: clone: from [email protected]:rcmdnk/vim-markdown
$ git reset --hard HEAD@{48}
HEAD is now at edf3bc9 Update README.md
こんな感じで適当なところへHEAD@{n}
と指定して戻ります。
pushの取り消し
上の場合なんかでrebaseしたものをpushした後にやっぱり戻したいとき等。
まず、ローカルを上の方法で元に戻します。
その後、
$ git push -f origin mod
の様に-f
でリモートのmodを元に戻したローカルのmodで強制上書き。
-
とりあえず色々ごちゃごちゃしてわからなくなった時に確認出来るように。。。 ↩
。 もしくはコマンドラインから
$ git config --global mergetool.tool vimdiff $ git config --global mergetool.keepBackup false
また、もし、デフォルトのmergetoolを他のにしておきたい場合でも
vimdiff
を使いたい場合は$ git mergetool -t vimdiff
でその時だけ
vimdiff
が使えます。MERGED(file.txtとすると)と同じディレクトリにそれぞれ
- file.txt.LOCAL.xxxx.txt
- file.txt.BASE.xxxx.txt
- file.txt.REMOTE.xxxx.txt
と言った名前で生成されていて、mergeが済むと消える様になっています。 ↩