git の master ブランチは取り込み専用で、ブランチの作成はほどほどに2018年08月02日 17時26分23秒

git は分散管理の履歴管理システム。それゆえ、使い方や信条などもどうしても多岐に渡ってしまう。両極端な master ブランチ強行派や、変更毎のブランチ作成必須派。master ブランチは触らないが、ほどほどブランチ作成派。単独での利用であれば、一人で好きな様にやって良いが、複数での開発になると、それぞれの流派の得手不得手が出て来る。

まずは、絶対に避けたいのが master を直接変更すること。pull リクエストなどを使いコードリビュー等を行う場合には大概不便な使い方。自分の master ブランチからの pull リクエストが、即座に受け入れられない場合は git pull --rebase の merge の原因になる。他の誰かの変更が、自分の変更よりも先に受け入れられてしまうと、自分のレポジトリでは既にコミットされている変更の前に他人の変更が加わることになる。その為、手元に沢山の merge を溜めることなり、git log に役に経たない情報が増える元になる。

それに比べると一つの変更毎にブランチを作成するのはそんなに悪くない。ブランチを作成して pull リクエストをするので、master には全てが綺麗に git pull --rebase で戻って来る。ただ、何百も変更を行い、ブランチの数も多くなってくると、名前の重複に困ったり、最近作業したブランチ名を忘れてしまったりといった弊害はある。ブランチはもちろん消すことはできるのだが、あれこれ二度手間になる部分も。

結局のところ、最近はほどほどの数のブランチを使い回すやり方に収束してきた。大きめの変更の時は、専用のブランチを作ったりはする。小さな細かい修正などは、幾つかのブランチを git pull --rebase で更新しつつ、使い回している。例えば、簡単な古いコードの削除などは cleanup ブランチでチョコチョコと行う。

pull リクエストの squash merge 等を行うと、また違った問題と解決策が必要になってくる。ただ、個人的には squash merge はあまり好まない。

git filter-branch で残すファイルを列挙する2018年06月12日 18時41分03秒

git filter-branch で特定のファイルだけを残すではファイル名を正規表現を用いて、特定のファイルを残した。

今回は、三十近いファイルを残す必要が出来て、正規表現では記述できないので、前回のものを若干応用。git レポジトリの外にファイルを置く。

% git filter-branch --tree-filter ' find * -type f  | fgrep -v -f /tmp/FILELIST | xargs rm' --prune-empty

前回

三種の git add で新しいファイルと削除されたファイルをステージする2018年05月12日 16時52分44秒

git は add コマンドで、コミットする前に一度溜める。大きめの変更などを準備している時に、一区切りなどつけるのに利用する。そうすると git diff が、この時点からの物になるので、以前の変更点は気にしなくて良くなる。 この時点ではコミットはされていない。

逆に、多めの変更をした時に面倒な事になる事もある。得に、自動生成したファイルを盲目的に取り込むときは、厄介になる。一時的な変更を行い、コミットから除外したい時も、結構うっとうしい場面にあう。

git add には幾つかのオプションがある。変更されたファイルに加えて、新しいファイルと削除されたファイルをどうするかで、以下のように三種類ある。

git add -A
全ての変更をステージする
git add .
新しいファイルと変更されたファイルをステージする。削除されたファイルはステージされない。
git add -u
変更されたファイルと削除されたファイルをステージする。新しいファイルはステージされない。

git rm で消したファイルのうちの一つを復活させる2018年05月09日 20時37分26秒

要らないファイルがあるので git rm で一つずつ消していった。点検のため、消したファイルを確認する。そのうちの幾つかは、今回消さないで次回に延長したくなった。ただ、消したファイル、消したいファイルも多いので、流石に作業前の状態には戻したくない。
% git reset -- file
% git checkout --file
reset と checkout にファイル名を指定すると、特定のファイルだけ rm から復旧できる。

git clone --depth 1 で最新の履歴だけを取得2018年04月13日 12時13分18秒

git clone --depth 1 で一部のみの取得が可能。コミット数が多いときにディスクとファイルの転送を削減できるので便利。

git log でハッシュコードを取得2018年02月03日 12時42分01秒

git log で色々な情報を取得できる。ハッシュコードは最後にコミットされた物を識別するのにも重要。

しっかりと全部出力すると、だいぶ長い。短い方でも認識するに十分で場所も取らない。

$ git log -1 --format='%h' 
9046ff0
$ git log -1 --format='%H' 
9046ff06904077b217b7a2e71a09228aa4edefa7

git filter-branch で特定のファイルだけを残す2018年01月31日 09時18分41秒

git filter-branch でディレクトリを残すではあるディレクトリに入っているファイルを消す方法を紹介した。

awk が間に入っているので、文字のエスケープに手間が掛かる。find で特定のファイル名を除外した方が楽な場合も多い。

% git filter-branch --tree-filter 'find * ! -name file_name.sh -type f | xargs rm' --prune-empty
もし複数のファイルを残したいのなら二重のエスケープが必要になる。
% git filter-branch --tree-filter 'find * ! -name "*.sh" -type f | xargs rm' --prune-empty

git はディレクトリの管理を行わない。そのため、上のコマンドで消すのは -type f を使って、ファイルのみとしている。

前回

git fetch&& git svn rebase で継続的に svn の変更を git に反映2018年01月19日 12時51分35秒

git は svn の変更履歴を git 形式に変換できる。
% git clone 
で最初の変換が出来る。

その後は、そのディレクトリの中で

% git fetch
% git rebase
とやると、前回の続きから svn の履歴から最新までを変換できる。

fetch は svn から履歴を取ってくるだけでなので、rebase を行わないと取ってきた履歴は反映されない。

git の [rejected] master -> master (non-fast-forward) の対処法2017年09月14日 10時55分03秒

git push と git pull を繰り返しているうちに、手元の git レポジトリと共有元の履歴が合わなくなるときがある。変更履歴が手元の複製と共有用で変わってしまった場合だ。そんなときに、pig push をすると以下のようなエラーが出る。
% git push
[rejected] master -> master (non-fast-forward)

共有用を常に元として作業をするようにしているので、このような状況に陥ったときは、手元のものを共有用と同じ状態にしたい。

% git rebase origin master
とすると origin、つまり手元の履歴を rebase できる。これで、共有用の履歴に合わせることが出来る。

git filter-branch でディレクトリを残す2017年07月20日 12時21分18秒

filter-branch --subdirectory-filter を使うと、指定したディレクトリの下のみを残す。例えば、libs ディレクトリがあって、libAAA のディレクトリ構造を残したままには出来ない。
% filter-branch --subdirectory-filter libs/libAAA
だと、libAAA 直下のファイルだけが残る。

Subversion 等にあったため、一旦、libs 以下のファイルを各ライブラリ毎の git レポジトリに分割したい。ところがこの形だと、後々にまた、二つのライブラリを統合するときに、 衝突が起きるので、libs/libAAA を libAAA のディレクトリを残したままにして、他の全てのファイルとディレクトリを消したい。

思考錯誤の後、以下の形に落ち着いた。

% cd libs
% git filter-branch --tree-filter 'ls | nawk "\$0 !~ /^libAAA\$/" | xargs rm -rf' --prune-empty
tree-filter はシェルコマンドを受け取るので、awk 等では文字のエスケープが若干厄介だが、この形だとほぼどのディレクトリ名でも定型で処理することが出来ている。

前回