Louissu
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- tags: 學習筆記, 版本控制 --- Git 介紹與常用指令 === 什麼是 Git? --- Git 是一種分散式版本控制系統。 ### 版本控制系統? 未導入版本控制系統之前,我們對專案進行修改或整合時,必須耗費大量的人力來對程式碼做備份和比對的工作。這在專案規模逐漸擴大或是多人協作的場景時,每個人的程式碼進度不一,哪段程式碼被修改或覆蓋?這段程式碼和上一次的版本有什麼不同?導致程式碼混亂不堪,難以維護,而版本控制系統就是要解決這樣的問題。 ### 分散式? 版本控制主要分為集中式(Centralized Version Control Systems,CVCSs)和分散式(Distributed Version Control Systems, DVCSs)兩種,前者如 SVN,後者如 Git。 在 Git 中,每個協作者都會擁有一個自己完整的版本庫,你可以在自己的版本庫中盡情的開 branch、修改程式碼,只要不 push 到主要的版本庫,你不會影響任何一個與你協作的夥伴。 而只要將專案 clone 到自己的設備,你不需要連網,就可以在自己的版本庫中查看歷史紀錄(git log)、創建分支(git branch)、切換分支(git checkout)、甚至是提交(git commit)。也就是說假設你遇難隻身一人漂流到孤島,突然有一股修改專案的衝動,打開筆電就可以開始工作。 若您在公司使用的是SVN,但又想體驗 Git 自由自在的感覺,Git 也有和 SVN 溝通的 bridge,請 Google git svn。 概念 --- ![Git](https://i.imgur.com/94TZTAv.png "Git") Workspace 是工作目錄,index 或者 stage 是暫存區(所以也有一些文章將暫存區翻譯為索引),local repository 是本地數據庫,remote repository 是遠端數據庫。 基本的開發流程是在 workspace 修改程式碼完成功能或修改之後,分批的將修改 add 進 index(stage) 中,再將這部分的修改 commit 到 local repository 並寫好符合規定的 description。 或許 stage 對於初使用 Git 的人來說有點不直覺,可能會認為每一次 commit 之前還要先 add 有點多此一舉。但在工作目錄(workspace)和數據庫(local repository)多一個暫存區(stage)的設計讓 Git 有更多彈性。 實際使用時可能會有很多需要分批上傳的情景,例如目前的 workspace 有兩個 feature 的修改,我可以將 featureA 先 add 後 commit,再做 featureB 部份的上傳,這樣的好處是不同的修改都可以擁有自己的 commit description,在 commit tree 中可以明確地看出來。 另外有一個有趣的地方需要注意,如果先對 hello.php 做了 functionA 部份的修改後 add,再對同樣在 hello.php 中的 functionB 部份做修改,這時候 commit 的話只會對第一次修改做上傳,如果在上傳之前 git status 會看見 hello.php 同時出現在 Changes to be committed 和 Changes not staged for commit 中,這是因為 add 是對修改做快照,而不是檔案。 常用指令 --- ### git init 切換到專案目錄並輸入,會在該目錄新增一個 .git目錄,代表 Git 開始對該目錄進行版控。 --- ### git clone ```git= git clone git://XXXXXXXX ``` 從目標專案複製到本地,這個複製幾乎包含了該專案的所有資料,包含歷史紀錄、分支、標籤等,而不僅僅是檔案,並會自動設定此遠端數據庫為 origin。 --- ### git remote 查看遠端數據庫,若目前的本地數據庫是從遠端數據庫 clone 來的,則會看到預設的 origin。 <br> ```git= git remote -v ``` 參數 -v 會在名稱後方顯示 URL <br> ```git= git remote add name git://XXXXXXXX ``` add 指令可以新增一個遠端數據庫,並取名為 name。 --- ### git status 查看當前專案的狀態,是否有新增刪除檔案或修改程式碼。 <br> ```git= git status -s ``` 參數 -s 可以看到比較簡潔的輸出格式 M = modified D = deleted R = renamed C = copied U = updated but unmerged --- ### git diff 直接輸入 `git diff` 可以看到當前工作目錄和暫存區的差別。 ```git= git diff <commitId1> <commitId2> ``` 可以比較兩次 commit 的差別。 <br> ```git= git diff --staged ``` 參數 --staged 則顯示暫存區和上次 commit 的差別 --- ### git log 從新到舊列出所有提交的歷史紀錄,包含 Commit 的作者、時間和description。 <br> ```git= git log -p -2 ``` 參數 -p 可以列出提交的內容,-2則限制最近的兩筆更新 <br> ```git= git log --stat ``` 參數 --stat 則顯示更新內容的簡略內容,包含被更動的檔案、更動多少檔案、有多少行被修改 <br> ```git= git log --graph ``` 參數 --graph 會在 log 旁用 ASCII 畫出分支的分歧和合併 --- ### git add ```git= git add hey.php ``` 可以將尚未被追蹤或有修改的檔案加入暫存區 <br> ```git= git add *.php ``` 也可以使用萬用字元 <br> ```git= git add -A ``` 參數 -A 可以將所有修改加入暫存區,等效於 `git add .` 或 `git add --all` --- ### git rm 刪除檔案並將刪除記錄存進暫存區 <br> ```git= git rm --cached ``` 參數 --cached 將檔案從 git 中移除,並沒有真的刪除檔案,而是將檔案變成 untracked。 --- ### git mv 修改檔名並將修改記錄存進暫存區 ```git= git mv oldName newName ``` --- ### git commit 將暫存區提交到儲存庫,這個指令會打開編輯器,輸入這次的 commit description 後離開編輯器,git 便會完成提交。 <br> ```git= git commit -m "This is commit descriptions" ``` 參數 -m 可以直接輸入 commit description <br> ```git= git commit -a ``` 參數 -a 可以省略 `git add` 的步驟,直接將修改存入暫存區並上傳 --- ### git branch 顯示分支列表,有*代表當前分支。 <br> ```git= git branch myfeature ``` 建立 myfeature 分支 <br> ```git= git branch -m oldName newName ``` 將 oldName 這個分支的名稱改為 newName <br> ```git= git branch -d myfeature ``` 刪除 myfeature 分支 --- ### git merge ```git= git merge myfeature ``` 會將 myfeature 這個分支合併到當前分支,所以在 merge 前記得先 checkout 到(通常是) master 分支 --- ### git rebase `git rebase` 是一個很有趣的功能,也有其他不同功能的用法,這裡主要介紹它在合併上的使用,進階的使用請見下方「我可以修改以前的 commit 嗎?」。 base 是基準點,也就是分支從哪裡長出來,所以 rebase 的意思接近於「重新定義分支的參考基準」。 假設我們從 master 分出了兩條 branch ,分別是 feature01 跟 feature02。我如果在 feature02 這個分支輸入: ```git git rebase feature01 ``` 意思就是「我 (feature02) 要重新定義 (re) 我的參考基準 (base),那個參考基準就是 feature01 」。 以結果來說,feature02 的 commit 會直接接在 feature01 的後面,看起來很像剪下貼上,但對 Git 來說 feature02 的那些 commit 都是新的 commit ,可以從 `git log --oneline`看到他們和原本的 SHA-1 值不一樣。 至於在 feature01 時 rebase feature02 ,和在 feature02 時 rebase feature01 的差別,只在最後 log 上 commit 的順序不同。 --- ### git push ```git= git push origin master ``` 將分支 master 推上遠端數據庫 origin 若有設定 remote,不帶參數執行 `git push` 相當於 `git push <remote>` 若沒有設定 remote ,不帶參數執行 `git push` 相當於 `git push origin` --- ### git pull ```git= git pull origin master ``` 將遠端數據庫 origin 的 master 分支拉下並合併到本地數據庫 若有設定 remote,不帶參數執行 `git pull` 相當於 `git pull <remote>` 若沒有設定 remote ,不帶參數執行 `git pull` 相當於 `git pull origin` `git pull` 做的事情實際上等於 `git fetch` + `git merge`,`git fetch` 會比對本地與遠端的差別,並在本地形成分支,`git merge` 則會將分支合併。 --- 你遇到這樣的問題了嗎? --- ### 正確的使用姿勢? `git init` 或是 `git clone` 之後,你可能會手癢先 `git status` 看一下,你會看到一個乾淨的目錄,然後開始編寫程式碼,一邊寫一邊 `git diff` 看自己到底改了哪些東西,改了一個段落在 `git add` 之前或許會 `git branch` 確定一下自己在哪個分支,有錯的話趕快 `git checkout branchName` 到正確的分支,接著 `git add` 把修改存到暫存區,`git status` 看一下是不是正確的狀態,然後 `git commit -m "This is my new git description"`,最後 `git push` 。 --- ### 這行誰寫的! 一覺醒來發現網站掛了,怎麼多了這一行扣!`git blame index.php` 可以看到 index.php 裡每一行的作者是誰。 --- ### 這個 commit 到底修改了啥? 先 `git log` 找到那次修改的 commit ID,你或許會用到 ```git= git log --author="Louis.Su" ``` 來篩選出 commit 作者,或者是 ```git= git log --grep="Hey" ``` 來找到 description 裡面包含 Hey 的 commit,又或者 ```git= git log -S "functionA" ``` 來找到上傳檔案有包含 functionA 的 commit。 最後`git show commitID`,就可以看到修改記錄了。 --- ### 我想修改剛剛的 commit 想修改最後一次的 commit,可以輸入 ```git= git commit --amend -m "This is right description" ``` 對人類來說只是修改 commit 的訊息,但對 git 來說,這其實是一個全新的 commit 了,可以從 `git log --oneline` 中看到 commit 的 SHA-1 值是不同的。 --- ### 我可以修改更之前的 commit 嗎? 這通常發生在自己開的 branch 裡 commit 雜亂無章的情況,想做好修剪之後再 push。盡量不要在已經 push 到中央伺服器的 commit 進行這種操作,除非你和你的團隊非常清楚自己在做什麼,這會造成協作者的混亂,因為同樣的程式碼有不同的版本,而且它會改變歷史 (這也是 rebase 屬於危險指令的原因)。 Git 本身並沒有修改歷史的工具。但可以使用 rebase 來做到對過去 commit 的修改。 <br> ```git= git rebase -i ``` 可以開啟對話模式,要給他一個參數,這個參數可以是 `git rebase -i HEAD~3` 這樣從當前分支往前算的形式,也可以是 `git rebase -i 6ee9b6b` 這樣的 SHA-1 值,意思是「從這一個 commit 往後算到現在位子的所有 commit 」。 之後會出現像這樣的列表: ``` pick f7f3f6d fix some bugs pick 310154e add some files pick a5f4a0d feat: complete a feature # Rebase 710f0f8..a5f4a0d onto 710f0f8 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out ``` 前幾行 pick 的意思是保留 commit 不做修改,如果你是想修改 commit message 的話,把 pick 改成 reword : ``` reword f7f3f6d fix some bugs pick 310154e add some files pick a5f4a0d feat: complete a feature ``` 表示我要修改這個 commit ,存檔離開後會再跳出另一個編輯器畫面,將 fix some bugs 改成你想要的 commit message 之後存檔離開, git 就會處理完剩下的事情。 如同上文中對 rebase 的描述,聰明如你肯定也猜到了,是的,這個 commit 同樣是全新的一個 commit ,而在這裡要注意的是,因為修改了過去的歷史,在這個 commit 之後的所有 commit 因為歷史的改變,所以整串 commit 都會變成新的 commit 。 因為過去被改變了,所以未來也會產生相應的變化,~~這就是平行時空的概念~~。 而 edit 和 reword 不同的地方在於: edit 同時還能修改 commit 內容,他會在 rebase 的過程中暫停等待你修改,所以當你: ``` edit f7f3f6d fix some bugs pick 310154e add some files pick a5f4a0d feat: complete a feature ``` 存檔離開後, git 會 checkout 到你想修改的 commit ,當你進行完你想做的修改之後, `git add [你有修改的檔案]` ,之後再 `git commit --amend ` 修改 commit message ,最後再輸入 `git rebase --continue` 將 rebase 完成。 另外的 squash 和 fixup 則是用來合併 commit,不同的地方是當你用 squash 要合併時,會把多個要合併的 commit message 放進編輯器裡面讓你修改最後合併的 commit message ;而 fixup 則是把這個 commit 合併到上一個 commit 中,並直接捨棄這個 commit message。 --- ### 挫賽!我可以重來嗎? git 的強大之處在於他大部分的指令都是可逆的,但它同樣也是危險的,因為並不是所有操作都可逆,一不小心就會搞得整個環境亂七八糟,在實戰時執行指令前都要謹慎思考,清楚知道自己在幹嘛,強烈建議可以搭配 Github 開一個自己來玩玩看。 這一 part 會先介紹如何反悔,再說明 reset 這個指令的意義,建議看完再操作。 #### 如何將暫存區的檔案移出 這樣的場景會出現在你修改了兩個檔案,想要分別提交,但你手速太快不小心打了 `git add -A` 全部加到暫存區了。 ```git= git reset HEAD <filename> ``` #### 如何將剛剛的 commit 拆回來 這樣的場景則出現在後悔剛剛那個 commit 的內容,想拆回來重做,你可以先下 `git log` 或 `git log --oneline` 來看到 SHA-1 值,然後: ```git= git reset 6ee9b6b ``` 也可以用相對的方式: ```git= git reset HEAD^ ``` #### 哇塞我整個專案都玩壞了,怎麼回復成原本的樣子 ```git= git reset --hard HEAD~2 ``` 這行指令的意思是最後的兩個版本(HEAD、HEAD^)我都不要了,我也不想讓人看見他,專案會直接回到 HEAD^^ 的狀態,所以在下指令前請確保你的 HEAD、HEAD^ 都是不要的。 #### 我還想要 HEAD 或 HEAD^,能回復嗎? 其實還是救的回來,先下: ```git= git reflog ``` reflog 裡面存的是「HEAD移動的紀錄」,你會看到你剛剛 reset 的紀錄,所以要取消 reset 的話,就要「reset 到 reset 前的那個 commit 」: ```git= git reset --hard <commitID> ``` 講到這裡聰明的你一定已經隱約感覺到 reset 的意義了,在中文會比較接近「前往」。 而 `--hard` 是參數,有三種常見的: `--mixed` 、 `--soft` 、 `--hard` ,這個參數決定的是「那些我不要的東西最後要去哪裡」 `--mixed` 是預設,這個模式下的 reset commit 會把 commit 內容丟進工作目錄裡面 `--soft` 則會把 commit 內容丟進暫存區 `--hard` 則是工作目錄和暫存區都不會留 所以前文說的「拆」 commit 其實並不準確,而是「回到」那個 commit 的狀態,不同參數則決定了路過的那幾個檔案將何去何從。 參考資料 --- Git官方文件:https://git-scm.com/book/zh-tw/v2 為你自己學Git:https://gitbook.tw/ 連猴子都能懂的Git入門指南:https://backlog.com/git-tutorial/tw/

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully