--- tags: notes, git --- # Git筆記 git博大精深,留一些學習上遇到的困惑,當作以後的小抄。 我覺得寫得很棒的教學: [Learn git in 30 days.](https://github.com/doggy8088/Learn-Git-in-30-days) 學習branch、merge的線上圖形遊戲: [Learn Git Branching](https://learngitbranching.js.org/index.html?locale=en_US) Commit message該怎麼寫: [Commit convention](https://www.conventionalcommits.org/en/v1.0.0/) ## Commands * `git init` Initialize a git repo at the current working directory. * `add` * `git add <file>` Add **new** or **modified** file into **Staged**. * `git add -A` Add all changes(including **new**, **modified**, and deleted files). * `git add --all` The same as above. * `git add .` The same as above. * `git add -u` Add all **modified** and deleted. Use this to avoid staging ignore files. ![](https://i.stack.imgur.com/KwOLu.jpg) * `commit` * `git commit` Transfer all **Staged** files into `git repo` and establish a new version. * `git commit <file>` Commit a specific `<file>`. It could be either **Staged** or **Modified**. * `git commit -a` This `add` all unstaged(**Modified**) files automatically. And then `commit`. **Untracked** files won't be `add` nor `commit`. * `git commit -m "msg"` `msg` is a note for each commit shown in `git log`. A commit note is reuquried. Without `-m "msg"`, git opens an editor and ask for typing a message. * `reset` * `git reset <commit>` Unstage all **Staged** files, which means, reseting *index* to `<commit>`. And set *HEAD* to `<commit>`. If `<commit>` is empty, then resets *index* to *HEAD*. The working tree are not affected. * `git reset --hard <commit>` Unstage files and copy files from *HEAD* of *git repo* to the disk. In other words, reset *index* and working tree in the same time. If the file in the working tree was modified, the change would be discarded. * `branch` * `git branch <branch name>` Create a new branch, staying at current branch(not changing *HEAD*). * `git branch -v` Display all the banches, including `HEAD`. * `checkout` * `git checkout <branch/commit> <file>` Pull specific file from `<branch/commit>` to working tree and `index`, without changing `HEAD`. * `git chekcout <branch/commit>` Switch *HEAD* to a specific `<branch/commit>` and pull all the files from `<branch/commit>` to working tree. * `merge` 1. `git checkout master` 2. `git merge hotfix2`: Merge `hotfix2` into master. * `mv` * `git mv <file name> <new file name>` Rename the file/dir. * `git mv <file name> <new path>` After changing the file path without git command, `git mv <the file> <path>` fails to execute. * `remote` * `git remote` Display names of remotes. * `git remote -v` Display names of remotes and their destinations. * `git remote show <remote name>` Display more details about a remote. * `git remote add <remote name> <URL>` Add a remote. * `git remote remove <remote name>` Remove a remote. * `.gitignore` Change of `.gitignore` takes effect immediately right after it is modified without staging or commiting it. `.gitignore` can also be ignored. * `diff` Show changes between commits, commit and working directory, etc. | Instruction | Compare 1 | Compare 2 | |:--------------------------------- |:--------------------- |:--------------- | | `git diff` | Working directory | Current version | | `git diff HEAD` | Working directory | Index | | `git diff commit_id` | Working directory | Commit version | | `git diff --cached/--staged HEAD` | Index | Current version | | `git diff commit_1 commit_2` | Commit 1 | Commit 2 | | `git diff HEAD^ HEAD` | Last version | Current version | | `git diff <file>` | The file in directory | Current version | Note: Working directory = Working tree = Unstaged. ## Concepts ### File Status Lifecycle * There are 4 kinds of status of a file: * **Untracked**: The file is totally new to *HEAD*. * **Modified**: The file is modfied after it was *Committed*, which means the file in the disk is different from the file in *HEAD*. It wont be *Commited* unless it is *Staged.* * **Staged**: The file to be committed. `git commit` copies/sends this kind of file into *git repo/HEAD*. A file in the *index* is called a *Staged* file. * **Committed**: The content of the file in the disk is the same as the one in *HEAD*. * ps: *HEAD* is the current working version. And it is usually the latest one in the *git repo*. * Full file lifecycle: ```graphviz digraph life_cycle{ fontsize="13"; labelloc="b"; //location of title, "b" for bottom rankdir="LR" //node direction from left to right. RL, TB, BT also available graph [fontname = "源樣明體"]; node [fontname = "consolas", fontsize=11]; edge [fontname = "consolas", color="#002a57", fontsize=12]; untak[label="Untracked", shape=box, color="#6e1430", fontcolor=white, style=filled] unmod[label="Committed\n(unmodified)", shape=oval, color="#ffffa3", fontcolor=black, style=filled] moded[label="Modified", shape=box, color="#6e1430", fontcolor=white, style=filled] stag[label="Staged", shape=box, color="#009447", fontcolor=white, style=filled] {rank=same stag unmod } untak->stag[label="add <file>", weight="4"] stag->untak[label="  rm --cached <file> ", weight="1"] unmod->moded[label=" \n\n\n modified ", weight="2"] moded->stag[label=" add <file>", weight="0"] unmod->stag[headlabel="*rm --cached <file>", weight="0",headport=s,tailport=nw,labelangle=46,labeldistance=7.3] stag->unmod[label=" commit", weight="1",headport=ne] unmod->untak[label="\n\n\n\n rm --cached <file>", weight="0"] moded->unmod[headlabel="commit -a", labeldistance=9, labelangle=18,headport=se,tailport=sw] } ``` > *`git rm --cached <file>` where `<file>` is already committed and you want to remove it from the *HEAD*.   * Typical flow example: Step by step ```graphviz digraph life_cycle{ fontsize="13"; labelloc="T"; //location of title, "b" for bottom rankdir="LR" //node direction from left to right. RL, TB, BT also available graph [fontname = "源樣明體"]; node [fontname = "consolas", fontsize=11]; edge [fontname = "consolas", color="#002a57", fontsize=12]; untak[label="Untracked", shape=box, color="#6e1430", fontcolor=white, style=filled] unmod[label="Committed\n(unmodified)", shape=oval, color="#ffffa3", fontcolor=black, style=filled] moded[label="Modified", shape=box, color="#6e1430", fontcolor=white, style=filled] stag[label="Staged", shape=box, color="#009447", fontcolor=white, style=filled] init[label="original\nfiles"] {rank=same unmod stag} {rank=same init untak} init->untak[label="        1$ git init\n "] untak->stag[label="2$ git add .", weight="4"] stag->untak[label="  rm --cached <file> ", weight="1", style="invis"] unmod->moded[label=" 4$ modified file ", weight="2"] moded->stag[label=" 5$ git add .", weight="0"] stag->unmod[label="3$ git commit ", weight="0"] unmod->untak[label="\n\n rm --cached <file>", weight="0", style="invis"] unmod->unmod[label="*rm --cached <file>", weight="0",headport=sw,tailport=sp, style="invis"] } ``` Typical Flow Example: (from $1~$2) ![Typical Flow Example](https://i.imgur.com/l4MTQQi.png) Typical Flow Example: (from $3~$5) ![](https://i.imgur.com/ZgKomhZ.png) 1. hi 2. hihi 3. hihihi 4. matjax $hi$