<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>{&#124;ihower.tw&#124; blog } &#187; Git</title>
	<atom:link href="http://ihower.tw/blog/archives/category/git/feed" rel="self" type="application/rss+xml" />
	<link>http://ihower.tw/blog</link>
	<description>Ruby, Ruby on Rails, Mac and Agile development</description>
	<lastBuildDate>Tue, 27 Jul 2010 06:48:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>使用 rebase 避免無謂的 merge</title>
		<link>http://ihower.tw/blog/archives/3843</link>
		<comments>http://ihower.tw/blog/archives/3843#comments</comments>
		<pubDate>Mon, 15 Feb 2010 07:12:39 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Git]]></category>

		<guid isPermaLink="false">http://ihower.tw/blog/?p=3843</guid>
		<description><![CDATA[git pull 預設的行為是將遠端的 repo. 與本地的 repo. 合併，這也是 DVCS 的初衷，將兩個 branch 合併。但是，很多時候會發生以下這種情形：

這是因為，我們團隊的開發模式是本地的 branch 和遠端的 branch 會同步地非常頻繁(通常就是同名稱的 branch，例如 master)，這兩個 branch 幾乎是完全同步。這時候就會發現這些 merge 動作其實沒有必要，會造成線圖無謂的複雜。這時候，會推薦使用以下這個指令：
 git pull --rebase 
加上 rebase 的意思是，會先 1.把本地 repo. 從上次 pull 之後的變更暫存起來 2. 回復到上次 pull 時的情況  3. 套用遠端的變更 4. 最後再套用剛暫存下來的本地變更。詳細說明可以參考 pull with rebase。
畫圖說明一下好了:
假設合併前是這樣：

      D---E master
     [...]]]></description>
			<content:encoded><![CDATA[<p>git pull 預設的行為是將遠端的 repo. 與本地的 repo. 合併，這也是 DVCS 的初衷，將兩個 branch 合併。但是，很多時候會發生以下這種情形：</p>
<p><a href="http://ihower.tw/blog/wp-content/uploads/2010/02/git-merge.jpg"><img src="http://ihower.tw/blog/wp-content/uploads/2010/02/git-merge.jpg" alt="" title="git-merge" width="211" height="376" class="alignnone size-full wp-image-3844" /></a></p>
<p>這是因為，我們團隊的開發模式是本地的 branch 和遠端的 branch 會同步地非常頻繁(通常就是同名稱的 branch，例如 master)，這兩個 branch 幾乎是完全同步。這時候就會發現這些 merge 動作其實沒有必要，會造成線圖無謂的複雜。這時候，會推薦使用以下這個指令：</p>
<pre> git pull --rebase </pre>
<p>加上 rebase 的意思是，會先 1.把本地 repo. 從上次 pull 之後的變更暫存起來 2. 回復到上次 pull 時的情況  3. 套用遠端的變更 4. 最後再套用剛暫存下來的本地變更。詳細說明可以參考 <a href="http://www.gitready.com/advanced/2009/02/11/pull-with-rebase.html">pull with rebase</a>。</p>
<p>畫圖說明一下好了:</p>
<p>假設合併前是這樣：</p>
<pre>
      D---E master
     /
A---B---C---F origin/master
</pre>
<p>使用 merge 合併後：</p>
<pre>
      D--------E
     /          \
A---B---C---F----G   master, origin/master
</pre>
<p>如果是 rebase 的方式，就不會有 G 合併點：</p>
<pre>
A---B---C---F---D'---E'   master, origin/master
</pre>
<p>你會問說，有 conflict 怎麼辦? rebase 跟 merge 類似，出現 conflict 一會暫停 rebase 動作，需要你手動修復後，然後才可以繼續動作。這也是 rebase 比 merge 複雜一點的地方：merge 如果發生 conflict，你只需要解決衝突一次，然後 commit 出去就完成了。而 rebase 的 conflict 可能會發生在上述步驟 4 的每一次重新套用上，所以可能需要解決衝突好幾次 (rebase 時所謂的解決衝突，其實是直接修改你之前的變更內容，所以上圖中變成 D&#8217; 跟 E&#8217; )。</p>
<p>所以到底何時該用 merge? 何時可以 rebase? 你可能心理也有答案了，如果你修改比較多，預期會有較多的 conflict，建議用 merge (不過，如果是多次大範圍的主題式修改，那是不是應該一開始就多開一個 branch 來做呢?)。如果修改範圍較小，不太預期有 conflict，則建議可以用 rebase。</p>
<p>每次 git pull 都要多打 &#8211;rebase 容易忘記，這時候可以在 .git/config 加上</p>
<pre>
<code>
[branch "master"]
  remote = origin
  merge = refs/heads/master
  rebase = true
</code>
</pre>
<p>也可以直接加到 ~/.gitconfig 讓之後的  tracked branches 都自動套用這個設定：</p>
<pre>
<code>
[branch]
  autosetuprebase = always
</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/3843/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Git 版本控制系統(2) 開 branch 分支和操作遠端 repo.</title>
		<link>http://ihower.tw/blog/archives/2620</link>
		<comments>http://ihower.tw/blog/archives/2620#comments</comments>
		<pubDate>Fri, 24 Apr 2009 14:23:46 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Git]]></category>

		<guid isPermaLink="false">http://ihower.idv.tw/blog/?p=2620</guid>
		<description><![CDATA[後記：寫一寫覺得這個系列對初學者可能不太容易了解&#8230; XD 要寫出簡單易懂的說明還真是需要花點功夫，想想拖稿太久還是作罷。
用 Git 就是要愛用 Branch 啊，Branch 很好用，開 Branch 不用錢。開 Branch 的情境除了在上一篇中提到因應產品 release 需求的 stable/production branch 之外，其他開 branch 情況有：

帶有實驗性質的變更，例如想改寫新的演算法、重構程式碼等
新功能 feature 開發
Bug fixes，你可能需要做些實驗才知道到底怎麼修

這些事情都可以先在本地開 local branch 做，而不需要立即 Push 分享給別人。

git branch &#60;new_branch_name> 建立本地 local branch
git branch -m &#60;old_name> &#60;new_name> 改名字 (如果有同名會失敗，改用 -M 可以強制覆蓋)
git branch 列出目前有那些 branch 以及目前在那個 branch
git checkout &#60;branch_name> 切換 branch (注意到如果你有檔案修改了卻還沒 commit，會不能切換 branch，解法稍後會談)
git checkout -b &#60;new_branch_name> [...]]]></description>
			<content:encoded><![CDATA[<p>後記：寫一寫覺得這個系列對初學者可能不太容易了解&#8230; XD 要寫出簡單易懂的說明還真是需要花點功夫，想想拖稿太久還是作罷。</p>
<p>用 Git 就是要愛用 Branch 啊，Branch 很好用，開 Branch 不用錢。開 Branch 的情境除了在上一篇中提到因應產品 release 需求的 stable/production branch 之外，其他開 branch 情況有：</p>
<ul>
<li>帶有實驗性質的變更，例如想改寫新的演算法、重構程式碼等</li>
<li>新功能 feature 開發</li>
<li>Bug fixes，你可能需要做些實驗才知道到底怎麼修</li>
</ul>
<p>這些事情都可以先在本地開 local branch 做，而不需要立即 Push 分享給別人。</p>
<p><code><br />
git branch &lt;new_branch_name> 建立本地 local branch<br />
git branch -m &lt;old_name> &lt;new_name> 改名字 (如果有同名會失敗，改用 -M 可以強制覆蓋)<br />
git branch 列出目前有那些 branch 以及目前在那個 branch<br />
git checkout &lt;branch_name> 切換 branch (注意到如果你有檔案修改了卻還沒 commit，會不能切換 branch，解法稍後會談)<br />
git checkout -b &lt;new_branch_name> (&lt;from_branch_name>) 本地建立 branch 並立即 checkout 切換過去<br />
git branch -d &lt;branch_name> 刪除 local branch<br />
</code></p>
<p>開 Branch 最大的好處除了可以不影響 stable 和其他分支版本的開發，另一個超棒的地方是&#8221;你可以決定 Merge 的方式&#8221;。Git 的 Merge 方式可以分成四種：</p>
<ul>
<li>Straight merge 預設的合併模式，會有全部的被合併的 branch commits 記錄加上一個 merge-commit，看線圖會有兩條 Parents 線，並保留所有 commit log。
<li>Squashed commit 壓縮成只有一個 merge-commit，不會有被合併的 log。SVN 的 merge 即是如此。</li>
<li>cherry-pick 只合併指定的 commit</li>
<li>rebase 變更 branch 的分支點：找到要合併的兩個 branch 的共同的祖先，然後先只用要被 merge 的 branch 來 commit 一遍，然後再用目前 branch 再 commit 上去。這方式僅適合還沒分享給別人的 local branch，因為等於砍掉重練 commit log。</li>
</ul>
<p>其中 rebase 比較難理解會在下一篇再詳述：</p>
<p><code><br />
git merge &lt;branch_name> 合併另一個 branch，若沒有 conflict 衝突會直接 commit。若需要解決衝突則會再多一個 commit。<br />
git merge --squash &lt;branch_name> 將另一個 branch 的 commit 合併為一筆，特別適合需要做實驗的 fixes bug 或 new feature，最後只留結果。合併完不會幫你先 commit。<br />
git cherry-pick 321d76f 只合併特定其中一個 commit。如果要合併多個，可以加上 -n 指令就不會先幫你 commit，這樣可以多 pick幾個要合併的 commit，最後再 git commit 即可。<br />
</code></p>
<p>使用 merge 可能會有部分程式碼會 conflict 衝突：簡單的情況只要編輯檔案處理 &lt;&lt;&lt;&lt; ===== >>>>> 即可，然後重新 add 到 staging area 並 commit (沒有像 SVN 的 resolve 指令)。複雜一點的可以再用 git mergetool 選檔案合併的 GUI 工具 (OS X 下面可以用 opendiff, linux 可以用 kdiff3 )，處理好後 git commit。</p>
<p>一旦 merge 好了，git branch -d &lt;branch_name> 可以刪除 branch。但如果要刪除的 branch 還沒有合併，就會有錯誤訊息。如果真的要強制刪除可以用 -D</p>
<p>Git 的 working tree 是從 SVN 換過來一個不習慣的地方，因為它只是一個工作暫存區，在切換 Branch 時就會整個換掉。也因為如此，<strong>如果有檔案有修改還沒有 commit 出去，切換 branch 時就會出現 error 不能切換</strong> (除非是新的 untracking 檔案)，例如有修改還沒 add 會出現 error: Entry &#8216;ooxx&#8217; not uptodate. Cannot merge. 有修改且已經add(還沒ci)會出現 error: Entry &#8216;ooxx&#8217; would be overwritten by merge. Cannot merge.</p>
<p>最理想的處理當然是事情剛好做到一個段落，把東西 commit 出去才切換 branch 做事。不過事情總有臨時，如果要換 branch 的暫時的解決方式是使用 git stash 會先把修改暫存下來，要回復則執行 git stash pop。下一篇等你學會 git reset 之後，你會發現就算把還沒完成的東西 commit 也不會怎麼樣，只要還沒 push 出去一切 commit 紀錄都是可以改的。</p>
<h3>Remote  repo. 操作</h3>
<p>首先要認識的是 Protocol，像在 Github 上面看自己的 Project，會有分 Public Clone URL 跟 Your Clone URL，這有什麼差?</p>
<ul>
<li>git://github.com/ihower/project.git 這種的是使用 Git 自己的 prototol，優點是速度快，但是沒有認證機制，只適合 read only (port:9418)</li>
<li>git@github.com/ihower/project.git 這種的是使用 SSH，可以有認證(SSH key)</li>
<li>Git 也可以透過 HTTPS 的方式，不過速度較慢，比較適合對 firewall 有限制的情況</li>
</ul>
<p>其中 Github 就是同時用 SSH + Git protocol，兼顧認證需求及速度。</p>
<p><code><br />
git clone &lt;remote_address><br />
git checkout --track -b foobar origin/foobar 將遠端的 branch checkout 回來並建立一個新的 local branch，加上 --track 表示你之後還要pull、push回去，所以請 Git 記住對應關係。<br />
git pull (&lt;local_branch_name> origin/&lt;remote_branch_name>) 去遠端 fetch 新版並 merge 進 local branch<br />
git push 將 local branch 的 commit 紀錄更新到遠端</p>
<p></code></p>
<p>git pull 要注意的是，如果別人在你上次 pull 之後有 push 新東西上去(也就是說跟你的 branch 產生分岔了)，此時有兩種情況： 一是 Git 可以順利 auto merge 的話，git 會自動多一次 merge commit，這也就為什麼常常 log 會跑出 Merge branch &#8216;master&#8217; of git@foobar.com。二是如果有 conflict，這時候就需要你手動處理然後 commit。話說如果覺得這種 local branch 和 remote branch 的 merge commit log 很煩，建議可以改使用 git pull &#8211;rebase 指令來變成 fast-forward 形式 (就會變得像 svn up，而不會有 merge commit log)。rebase 的意思可能要下一篇才會詳細說明的清楚，簡單的說(?)，就是先砍掉 local branch 分岔點之後自己的 commit，然後把遠端的 commit 先一個個 apply 進來，最後再把自己的 commit 再 apply 進去 (如果有 conflict 會中途停下來，等你修好才會繼續 apply)，如此一來看線圖就會變成一條線而已，也就沒有所謂 merge 這個動作了。</p>
<p>git push 預設的遠端是 origin，並且會將所有有和 remote 有對應的 local branch 都 push 上去。如果要把新的 local branch push 上去，需要下  git push origin &lt;local_vranch_name> 指令。</p>
<p>git push 也可能會失敗，例如出現  ! [rejected] master -> master (non-fast forward)，這個 non-fast forward 的意思是你的 parent commit 和遠端的不相同，也就是線圖有分岔，需要先 pull 回來處理好 merge 才能 push 上去。</p>
<p>fast-forward 在 Git 是一種 merge 術語，當 B branch (例如一個 local branch) 是從 A branch (例如一個 remote branch) 的最新版(HEAD)分支出來的，那當 A 要把 B merge 進來時，因為 B 的 parent commit 是 A 的 HEAD，所以這兩個 branch 唯一的差異就是 B 後來的 commit 而已，而不會有任何 conflict。所以實際上的動作只要把 A 的 HEAD 改成 B 的 HEAD 就好了，線圖上這兩個 branch 根本是同一條線，此謂 fast-forward。</p>
<p>其他操作還有:</p>
<p><code><br />
git fetch 把遠端的 branch 更新下載回來，但不會 merge 到 local branch<br />
git branch -r 顯示 local 有追蹤的遠端 branch。注意到你不能直接修改這個 remote branch，一定要用一個 local branch 對應它。<br />
git remote show origin 顯示遠端 server 的 branch<br />
git remote add foobar git:// 可以新增別的 repo. 位置，於是 pull 的時候就可以指定要從哪一個遠端更新回來。<br />
git push origin :foobar 刪除遠端的 branch<br />
</code></p>
<p>因為遠端的操作指令比較雜，所以也有人寫了 <a href="http://github.com/webmat/git_remote_branch/tree/master">git_remote_branch</a> 來簡化操作。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/2620/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Git 版本控制系統 (1)</title>
		<link>http://ihower.tw/blog/archives/2591</link>
		<comments>http://ihower.tw/blog/archives/2591#comments</comments>
		<pubDate>Fri, 27 Mar 2009 13:24:07 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Git]]></category>

		<guid isPermaLink="false">http://ihower.idv.tw/blog/?p=2591</guid>
		<description><![CDATA[自從去年 Rails 改用 Github hosting 之後，就想學 Git 很久了(一直以來都只會像 svn 一樣操作 add, rm commit, push, pull 而已，如果你的程度也是如此，建議你可以再多學學)。今年許下的第一個目標就是認真學會 Git，而直到上個月和多開始陸陸續續把所有的 svn repo. 都換成 git，才開始非得天天用 git 的日子 :p
Git 是一套由 Linus 發展出來的 content tracker 系統，它的內部設計像是檔案系統，而不是 SCM 系統，雖然它最主要的用處是拿來做 DVCS。
這裡最重要的理解就是：他追蹤的是內容，不是檔案名稱，所以即使檔案名稱不同或是在不同的 branch 裡面，相同的內容仍然只會有一份實體，其他都是利用 metadata 建立 reference 關聯。這也是為什麼它比起 SVN 又快又省空間又有效率，分支 branch 跟 tag 超快(只是建立 reference 而已)，而且也可以改檔名(在 SVN 要刪除再新增，真是 sucks)。
因為 Git 比起 SVN 實在先進多了，除了比較難上手一些之外，我想這幾年應該會大規模的取代 SVN [...]]]></description>
			<content:encoded><![CDATA[<p>自從去年 Rails 改用 <a href="http://ihower.idv.tw/blog/archives/1733">Github</a> hosting 之後，就想學 Git 很久了(一直以來都只會像 svn 一樣操作 add, rm commit, push, pull 而已，如果你的程度也是如此，建議你可以再多學學)。今年許下的第一個目標就是認真學會 Git，而直到上個月<a href="http://handlino.com">和多</a>開始陸陸續續把所有的 svn repo. 都換成 git，才開始非得天天用 git 的日子 :p</p>
<p>Git 是一套由 Linus 發展出來的 content tracker 系統，它的內部設計像是檔案系統，而不是 SCM 系統，雖然它最主要的用處是拿來做 DVCS。</p>
<p>這裡最重要的理解就是：他追蹤的是內容，不是檔案名稱，所以即使檔案名稱不同或是在不同的 branch 裡面，相同的內容仍然只會有一份實體，其他都是利用 metadata 建立 reference 關聯。這也是為什麼它比起 SVN 又快又省空間又有效率，分支 branch 跟 tag 超快(只是建立 reference 而已)，而且也可以改檔名(在 SVN 要刪除再新增，真是 sucks)。</p>
<p>因為 Git 比起 SVN 實在先進多了，除了比較難上手一些之外，我想這幾年應該會大規模的取代 SVN 成為新霸主吧(<a href="http://zh-tw.whygitisbetterthanx.com/">Why Git is Better than X</a>)，它目前最大的缺點是 Windows 上的支援還不是非常成熟。如果您想看看其他選擇，聽說 <a href="http://www.selenic.com/mercurial/wiki/">Hg</a> 這套 DVCS 也是非常不錯 (快把 SVN 丟了吧)。</p>
<p>認真學會了一套分散式版本控制系統 DVCS，對專案開發真是幫助不少，以往我會對 branch 感到害怕，覺得是高級的技巧，學會 Git 之後這件事變成一個非常 easy 的開發技巧，不像 svn copy 跟 svn merge 令人抗拒。這對一個已經在上 production 的軟體來說幫助極大，因為必需同時維護 stable 的版本只做 bug fixes，以及數個 development branch 同時開發不同 topic/features。</p>
<p>另一好處是分散式 SCM 有本地端 Repo.，因此不需要網路就可以 commit 了，因此有時候做高鐵或等車想寫 Code 也就不需要網路了。而且本地端 Repo. 看 log 超快超方便，看 SVN Log 真是超級痛苦的網路延遲。另一個比較進階的長處是：<strong>只要在本地端還沒有 Push 分享給別人，你都可以修改 commit histroy</strong>。這是非常 powerful 的能力，例如我可以取消前一次或任一次的 commit、變更 commit 順序、移動 local branch 的分支點、將數個 commit 合併成一個、將一個 commit 打散成數個等等，因此可以在本地端都確認 okay 準備好才 Push 分享給別人。這種流程我自己也在試著改變，以往 svn 的經驗會讓你習慣一 commit 就馬上 push，但是使用 git 的話其實不需要這麼急著把還不完整的程式分享出去。</p>
<p>我的主要教材的是 <a href="http://www.pragprog.com/titles/tsgit/pragmatic-version-control-using-git">Pragmatic Version Control Using Git</a> 一書和 <a href="https://peepcode.com/products/git-internals-pdf">Git Internals PDF</a>，前者很容易閱讀，後者比較概括性一些甚至開頭就先介紹了內部的運作。除了<a href="http://www.kernel.org/pub/software/scm/git/docs/">官方的說明文件</a>，其他推薦的 Git 學習網頁有：</p>
<ul>
<li><a href="http://git-scm.com">http://git-scm.com</a></li>
<li><a href="http://github.com/guides/home">http://github.com/guides</a></li>
<li><a href="http://learn.github.com/">http://learn.github.com/</a></li>
<li><a href="http://www.gitready.com/">http://www.gitready.com/</a></li>
<li><a href="http://gitcasts.com/">http://gitcasts.com/</a></li>
</ul>
<p>除了安裝 Git command，使用 GUI 軟體看分支線圖可是使用 Git 的樂趣之一。其中 MAC 上的 <a href="http://gitx.frim.nl/">GitX</a> 軟體超級推薦，內建的則有 gitk 和 git-gui。</p>
<h3>Setup</h3>
<p>使用 Git 的第一步是務必設定好你的名子跟email，該檔案會在 ~/.gitconfig，可以用以下指令直接加入：</p>
<p><code><br />
git config --global user.name "ihower"<br />
git config --global user.email "ihower@gmail.com"<br />
</code></p>
<p>接著是建立 repo.，有兩種方式：</p>
<p><code><br />
git init &lt;dir_name> 會在本地新建一個 repo.。<br />
git clone &lt;remote_location> 會從遠端複製一份 repo 回來。<br />
</code></p>
<p>以下介紹的操作都跟 remote repo. 沒有關係，都只是在本地 repo. 操作。(作為一個 DVCS，本地端目錄就會包含所有的 commit 紀錄)</p>
<h3>add, status, commit (working tree and staging area)</h3>
<p>Working tree 是你當下的工作目錄，就像 SVN checkout 出來的工作目錄。這裡要特別學習的新概念是 Staging area，這是 Git 獨有的功能。它是一塊暫存的 cached 區域，用來紀錄什麼是你待會要 commit 檔案。</p>
<p><img src="http://zh-tw.whygitisbetterthanx.com/images/index1.png" /></p>
<p><code><br />
git add . 加入所有檔案，包括所有還沒有被追蹤(untracked)的檔案<br />
git add -i 進入互動模式，你甚至可以只 Add 檔案裡面其中的一段程式碼到 staging area 去(稱作patch)<br />
git add -u 只加更新的檔案，不加入還沒有追蹤的檔案 (跟 git commit -a 涵蓋的範圍相同)<br />
</code></p>
<p>使用 git add 會將檔案加入 staging area 中，特別注意到待會的 commit 是 <strong>commit 你執行 add 時當下的檔案</strong>，而不是最後的版本。(也就是如果你 add 完之後又再次修改同個檔案，commit 出去的檔案是第二次修改前的版本)</p>
<p>接著也是最常用的 git status，會列出以下狀態：</p>
<ul>
<li>Changed but not updated 有修改但是沒有加入 staging area 的檔案</li>
<li>Changes to be committed (staging area) 已經加入 staging area 的檔案</li>
<li>Untracked 還沒有被追蹤的新檔案</li>
</ul>
<p>然後是 commit 指令，會把 Staging area 裡面的東西 commit 出去：</p>
<p><code><br />
git commit -m "blah" 如果沒加 -m 的話, 會開編輯器輸入 commit log (可以在.gitconfig中設定編輯器)<br />
git commit -a -m "foobar" 全部修改的檔案都 add 後 commit 出去 (<strong>不包括 untracked 的新檔案</strong>)<br />
git commit -v 會開編輯器加上 diff 註解<br />
</code></p>
<p>其他常見操作有：</p>
<p><code><br />
git rm foobar 刪除<br />
git mv old_file new_file 改檔名<br />
</code></p>
<p>Git 沒有 git copy，因為既然 Git 不是 track file, 而是 track content，所以當你新建一個檔案把相同內容貼上去，Git 會知道你貼上去的東西從哪裡來的，也不需要你告訴 Git 你在 copy。</p>
<p>也因為多了一層 staging area 的存在，所以 diff 細分成三種</p>
<p><code><br />
git diff 是比較 working tree 跟 staging area<br />
git diff --cached 是比較 staging area 跟本來的 repo.<br />
git diff HEAD 是比較 working tree 跟本來的 repo.<br />
</code></p>
<p>後幾篇還會提到更多如何做回復動作，這裡先介紹兩個指令：</p>
<p><code><br />
git reset HEAD filename 會從 staging area 狀態回到 unstaging 或 untracked (檔案內容並不會改變)<br />
git checkout filename 會從 unstaging 狀態回到最初 repo. 的檔案(檔案內容變回修改前)<br />
</code></p>
<p>最後一提的是 .gitignore，這個檔案可以編輯列出哪些檔案是要忽略不需要 tracked 的，像 Rails 就會加入 log/*.log 和 tmp/**/* 。</p>
<p>Git 還有項比較特立獨行的行為是<strong>空目錄是不會 commit 出去的</strong>，這在某些專案可能會是問題(例如 Rails 如果少了 log 或 tmp 目錄會不能啟動)，解決辦法是在該目錄下 touch 一個空的檔案，慣例是 .gitignore。</p>
<p>(請期待續集：開 Branch 分支、操作遠端 Repo.、還沒 push 前可以幹的壞事以及其他奇技淫巧)</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/2591/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Github 分散式版本控制的殺手級應用</title>
		<link>http://ihower.tw/blog/archives/1733</link>
		<comments>http://ihower.tw/blog/archives/1733#comments</comments>
		<pubDate>Sun, 18 May 2008 21:53:44 +0000</pubDate>
		<dc:creator>ihower</dc:creator>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://ihower.idv.tw/blog/?p=1733</guid>
		<description><![CDATA[最近常常推薦人家去玩 Github，到底有用在哪裡? 就來寫一篇廣告文吧。
GitHub 是基於 Git 這套分散式版本控制系統的 Repository hosting 應用，一開始我也沒聽過 Git ，覺得用 Subversion 好好的為什麼這些人要換。抱著嚐鮮的念頭用了之後，發現實在好玩極了。目前已經有非常多的 Rails 相關應用都已經在上面進行開發，包括Ruby on Rails core、RSpec、will_paginate plugin、attachment fu_plugin等等，幾乎所有我用到的 Rails plugins 在上面都可以找的到。
到底有那些特色呢?

你可以 watch 你所關注的專案，Github 提供 private RSS 訂閱。有了這個功能，我有用到的 plugins 的進度我都可以掌握。
可以看到哪個專案最多人 watch，比較哪個比較多人用(比較多人用比較保險?)。
你可以 follow 你所關注的開發者動態(例如ihower)，看看又有什麼新的好東西 :p
你可以對專案 fork 出自己的版本進行開發，甚至最後發 pull request 要求 merge。
根據 fork 我就可以看到這個專案的分支 Network 狀態。有時候可能本來的程式不好用或爛掉了，你就可以查看看有沒有人寫做 patch 改進。
漂亮的 Source code browser，並可以針對 commit 來做留言討論，甚至標明是 source code 的哪一行(請把滑鼠移到原始碼的行數旁)。
提供 [...]]]></description>
			<content:encoded><![CDATA[<p>最近常常推薦人家去玩 <a href="http://github.com">Github</a>，到底有用在哪裡? 就來寫一篇廣告文吧。</p>
<p><a href="http://github.com">GitHub</a> 是基於 <a href="http://git.or.cz/">Git</a> 這套分散式版本控制系統的 Repository hosting 應用，一開始我也沒聽過 Git ，覺得用 Subversion 好好的為什麼這些人要換。抱著嚐鮮的念頭用了之後，發現實在好玩極了。目前已經有非常多的 Rails 相關應用都已經在上面進行開發，包括<a href="https://github.com/rails/rails/tree">Ruby on Rails core</a>、<a href="http://github.com/dchelimsky/rspec/">RSpec</a>、<a href="http://github.com/mislav/will_paginate/">will_paginate plugin</a>、<a href="http://github.com/technoweenie/attachment_fu/">attachment fu_plugin</a>等等，幾乎所有我用到的 Rails plugins 在上面都可以找的到。</p>
<p>到底有那些特色呢?</p>
<ol>
<li>你可以 watch 你所關注的專案，Github 提供 private RSS 訂閱。有了這個功能，我有用到的 plugins 的進度我都可以掌握。</li>
<li>可以看到哪個專案<a href="http://github.com/popular/watched">最多人 watch</a>，比較哪個比較多人用(比較多人用比較保險?)。
<li>你可以 follow 你所關注的開發者動態(例如<a href="http://github.com/ihower">ihower</a>)，看看又有什麼新的好東西 :p</li>
<li>你可以對專案 fork 出自己的版本進行開發，甚至最後發 <a href="http://github.com/guides/pull-requests">pull request</a> 要求 merge。</li>
<li>根據 fork 我就可以看到這個專案的分支 Network 狀態。有時候可能本來的程式不好用或爛掉了，你就可以查看看有沒有人寫做 patch 改進。</li>
<li>漂亮的 Source code browser，並可以針對 commit 來做留言討論，甚至標明是 source code 的哪一行(請把滑鼠移到原始碼的行數旁)。</li>
<li>提供 tarball 下載，即使沒裝 git command 也十分方便下載。</li>
<li>GitHub 可以直接當做 <a href="http://github.com/blog/51-github-s-rubygem-server">Ruby gem server</a></li>
<li>針對 Repository 可以搜尋 code, commit message, author 等</li>
<li>Git (我的感覺)比 SVN 又快又穩，用 SVN 常常會因為檔案太多中途失敗。</li>
</ol>
<p>Github 根本就是 Open source developer 的 social networking 啊，聽說這股浪潮已經從 Ruby/Rails 圈吹到 JavaScript 跟 Perl 了(?)，這都要歸功於 Git 這套優異的分散式版本控制系統。</p>
<p>BTW，幫忙宣傳 Jserv 在這週二的演講：<a href="http://blog.linux.org.tw/~jserv/archives/002019.html">我愛 Git &#8211; 有效使用分散式版本控制系統</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://ihower.tw/blog/archives/1733/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
