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 等では文字のエスケープが若干厄介だが、この形だとほぼどのディレクトリ名でも定型で処理することが出来ている。

前回

--allow-unrelated-histories が必要な git merge2017年07月08日 12時53分44秒

二つの git レポジトリを統合するのは git merge で行う。--allow-unrelated-histories は二つの独立したレポジトリを統合するときに必要になる。

同じように、repo1 に repo2 を取り込む例。

% cd path/to/repo1
% git remote add repo2 path/to/repo2
% git fetch repo2
% git merge repo2/master
fatal: refusing to merge unrelated histories
% git merge --allow-unrelated-histories repo2/master
元が一つだった場合は、ただ単に枝分かれを統合しただけだとも思う…。

前回次回

git で一部のディレクトリを新しいレポジトリとして切り出す2017年06月28日 16時27分28秒

repo に dir1 と dir2 のディレクトリがあり、それぞれにファイルがあるとしよう。dir2 を独立させて、repo2 として管理したい。このような場合には、dir1 の履歴は邪魔になる。dir2 のみを切り出す方法は幾つかあるが、--subdirectory-filter が一番簡単だ。

--subdirectory-filter は filter-branch のオプションで、手元のレポジトリで操作するので、clone を忘れないこと。

% git clone repo repo2
% cd repo2
% git filter-branch --subdirectory-filter dir2
なお注意点としては、dir2 の中身がレポジトリの直下になること。例えば、repo/dir2/Makefile があったとすると、これが、repo2/Makefile の位置になる。

repo2/dir2/Makefile の形で残したいと何度か試してみたが、今のところ --subdirectory-filter での方法は見付けられずにいる。

git で複数のレポジトリを統合する単純な方法2017年06月23日 12時18分25秒

git で複数のレポジトリを統合するのには、fetch と merge が一番単純かつ、綺麗に出来る。これが単純で済む場合の条件は同じパスが存在しないこと。

repo1 に repo2 を取り込む例。

% cd path/to/repo1
% git remote add repo2 path/to/repo2
% git fetch repo2
% git merge repo2/master
# もしうまくいかなかったら
% git merge --allow-unrelated-histories repo2/master
% git remote remove repo2
--allow-unrelated-histories は元が異なるレポジトリを統合する場合に使う。統合しようとしている二つのレポジトリが全く異なる場合はこれが必要になる。

他にも、どの様に他のレポジトリとの関係を保かによって幾つかの方法があるようだ。この用法は特に、repo2 の全てを移してから消す場合に適している。

次回

git push --set-upstream origin2017年04月25日 13時51分48秒

git では、なぜだか、push する時に、一度は必ずこのコマンドを使うのが推奨されているようだ。

git push -u origin my_branch でも代用できるみたいだ。

git clone --branch で一気にブランチに移行2015年08月01日 11時34分32秒

git clone はレポジトリを複写する方法。分散型の git に取っては、取得するチェックアウトにも相当する。git clone には -b または --branch のオプションもあり、任意のブランチに直接移行することも出来る。

試してみたら、存在しないブランチを指定すると、何も複製されない。

git clone; git branch で取得とブランチへの移行をすると、ブランチが無いときにそのまま master になってしまう。ブランチが存在しない場合に、異常終了したい場合には clone で一気にブランチを指定すると、失敗してもに何も残らない。

Eclipse ADT で git を使う2013年12月01日 13時13分15秒

Eclipse ADT をインストールしたら既に git が使えるようになっていた。特に不慣れな環境でコードを変更するのに履歴管理は手放せない。git 自体はあまり好みではないが、わざわざ他を入れる程好むものもない。そこで、そのまま git を使用。インストール済みというのは本当に大きな差だ。

プロジェクト単位で行うのが単純な操作だ。

  1. プロジェクトを右クリックし、「Team」の中の「Share Project...」を選択。「Configure Git Repository」のウインドウが出てくる。
  2. 「Use or create repository in parent folder of project」を選択すると「Create Repository」が有効化され、クリックできる。
  3. これをクリックすると、git initが実行されて、「Finished」ボタンで終わらせる。
この方法だと、各々別のレポジトリになってしまうので、コードをライブラリなどで分離して、あれこれ頻繁に移動させると履歴が正しく追えなくなる。workspace 自体をレポジトリにする等で対応できる。

git add/commit/diff の動作2009年02月12日 17時58分37秒

以前にも git のインターフェースは他と同じ名前なのに動作が違うのは指摘した。似て非なる物の為、更にとっつきが悪い。git heckout もその一例だ。

git の add と commit の動作も他とは全く異なる。

非 git での add は、新しいディレクトリやファイルを追加するのに使われる。非 git での commit は引数に指定されたファイルをコミットするのに使われる。そして、diff はこの手元での変更を表示する。様々なオプションを指定すればタグなどとの比較も可能だが、ここで言いたいのは何もオプションを与えないときの動作のことだ。

git では、全てのコミットを事前に add する必要がある。git の add はディレクトリやファイルを追加するのではなく、変更をコミットする為の予約をするコマンドだ。そして、commit であらかじめ登録しておいた変更のうち、引数で渡されたファイルのみの差分をコミットする。commit には add が必須だ。そして、diff コマンドは、手元の変更で add されていない物のみを表示する。そのため、git add が終わった変更は、git diff にて表示されない。

hg で例をあげる。


% hg init
% echo A > file.txt
% hg add file.txt 
% hg commit -m 'Create file.txt.'
% echo B >> file.txt 
% hg diff
diff -r d3e5d96de93f file.txt
--- a/file.txt  Fri Feb 11 23:10:27 2009 -0500
+++ b/file.txt  Fri Feb 11 23:11:42 2009 -0500
@@ -1,1 +1,2 @@
 A
+B
% hg add file.txt 
file.txt already tracked!

二度目の file.txt の add は出来ないと言われる。

今度は git で試す。


% git init
Initialized empty Git repository in /tmp/git/.git/
% echo A > file.txt
% git add file.txt 
% git commit -m 'Create file.txt'
Created initial commit 58d0fcc: Create file.txt
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file.txt
% echo >> B file.txt 
% git diff
diff --git a/file.txt b/file.txt
index f70f10e..35d242b 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
 A
+B

ここでは、diff が表示される。

% git commit -m 'Added B.'
# On branch master
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#
#       modified:   file.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

しかし、これはコミットできない。

% git add file.txt 
% git diff
% git commit -m 'Added B.'
Created commit 9f0a6ac: Added B.
 1 files changed, 1 insertions(+), 0 deletions(-)

add を使い登録することで、コミットが受け付けられた。そして、diff では変更を見られなくなっている。

バージョン管理 short tours2009年02月09日 12時34分12秒

一人で各種の履歴管理システム/プログラムを使い初める為の簡単な例。以下の作業を各々のプログラムにて実行する。
  1. work ディレクトリに a.txt と 1.txt を作成。
    
    % cd /tmp
    % mkdir work
    % cd work
    % echo "A B C" > a.txt
    % echo "1 2 3" > 1.txt
    
    
  2. import/checkout の作業を行なう。
  3. 1.txt を編集し、status と diff を見る。
    
    % echo "10 11 12" >> 1.txt
    
    
  4. 1.txt の変更をコミット。
  5. a.txt を A.txt に変更し、コミット。
  6. ログを見る。

プログラムのデザインと思想によって、始め方は千差万別だ。各々、特徴的な初期化のやり方をする。しかし、そう何回も繰り返す作業ではない。

一度、使い始めると大切な作業は三つ。

  1. 変更を確認する。
  2. 変更を記録する。
  3. 履歴を見る。
これらの作業が中心となる。コマンド的には、checkout(co)、diff、commit(ci)、update、log、status 等が並ぶ。これらのコマンドがある程度使えると、不自由はしない。

そして集団で使うとなると、更に二つの作業が必要になる。

  1. 他人の変更を引っ張ってくる。
  2. 衝突を解消する。
個人的に使っていても、二つ以上の作業場を用意して、疑似体験することは出来る。大きいプロジェクトや既に安定運用している成果物だと変更箇所も分散される事が多い。また、正しく管理されている仕事であれば衝突を避けるように計画するべきなので、衝突の解消を行なう事自体は少ない。こちらについては、今回は扱っていない。

集中管理型や分散型による違い。各思想の違いもコマンドに現れていて面白い。RCS は単体ファイルのみ。CVS 以降はディレクトリ構成も含めて、ファイルを集合として扱える。新しいい物も RCS/CVS に準拠したコマンド名も多い。使い手としては、コマンドと動作がある程度似ていた方が、試しやすく抵抗感も少ない。欠点としては、RCS/CVS の動作に寄せる形になるので、設計に RCS/CVS の影響が多かれ少なかれ出てくる事だ。

旅程cvsMercurial/hggitSubversion/svnrcssvk