Mosh的课程网址
初始化一个仓库 1 2 3 mkdir Moon cd Moongit init
在目录Moon下有一个.git隐藏文件夹,可以用以下命令看到:
删除.git:
Git Workflow 本地directory→staging area (index)→repository
Staging Files
用
查看,标红是因为新建的两个txt文件还没在staging area中。
使用下面的命令将两个文件的变化 (新建/删除文件,文件内容更改)存入staging area中:
1 git add file1.txt file2.txt
上面三种方式,(1)就add这两个文件;(2)add所有txt文件;(3)add所有文件
然后再查看,就绿了:
Committing Changes 提交到仓库
1 git commit -m "Initial commit."
Committing Best Practices
commit的时候文件的变化量应该适中(不要太多,也不要太少)
Commit often: 想要记录下某个状态时,就commit
Make it mean something
例如:对于两个改变 (1) Bug Fix, (2) Typo 最好不要一起commit,不然不知道改了啥,最好分开commit
Skipping the Staging Area 使用 -a 选项跳过git add
可以将两个选项 -a 和 -m 合并写成 -am
1 git commit -am "Fix the bug"
Remove Files 1 2 3 4 5 6 7 8 9 10 11 12 13 $ rm file1.txt $ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: file1.txt no changes added to commit (use "git add" and/or "git commit -a" ) $ git ls-files file1.txt file2.txt
在本地目录下删除file1.txt,但是用git ls-files查看staging area中的文件会发现file1.txt还在其中。使用git add更新staging area然后commit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ git add file1.txt $ git ls-files file2.txt $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) deleted: file1.txt $ git commit -m "Remove unused code" [master b184de1] Remove unused code 1 file changed, 7 deletions(-) delete mode 100644 file1.txt
除了上面的方法,也可以使用以下方法(git rm)一次性删除本地目录和staging area中的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ git rm file2.txt rm 'file2.txt' $ git ls-files $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) deleted: file2.txt $ git commit -m "Remove unused code" [master 3fd1e3e] Remove unused code 1 file changed, 1 deletion(-) delete mode 100644 file2.txt
Renaming and Moving Files 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $ mv file1.txt main.js $ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: file1.txt Untracked files: (use "git add <file>..." to include in what will be committed) main.js no changes added to commit (use "git add" and/or "git commit -a" ) $ git add file1.txt $ git add main.js warning: LF will be replaced by CRLF in main.js. The file will have its original line endings in your working directory $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: file1.txt -> main.js
文件的更名涉及到两个变化,原文件file1.txt删除,以及新文件main.js的创建。
当然,也可以使用便捷的方式:
1 2 3 4 5 6 7 8 9 10 11 12 $ git mv file1.txt main.js $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: file1.txt -> main.js $ git commit -m "Refactor code" [master 70800e8] Refactor code 1 file changed, 0 insertions(+), 0 deletions(-) rename file1.txt => main.js (100%)
注意到0 insertions(+), 0 deletions(-),改名而已。
Ignoring Files 1 2 3 4 5 6 7 8 9 10 11 $ mkdir logs $ echo hello > logs/dev.log $ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) logs/ nothing added to commit but untracked files present (use "git add" to track)
但是事实上我们并不想将log文件提交。方法:将 logs/ 写入.gitignore中
1 $ echo logs/ > .gitignore
用vscode打开文件.gitignore
可以在 .gitignore 中的下一行写上*.log表示要忽略的文件类型。然后提交 .gitignore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore nothing added to commit but untracked files present (use "git add" to track) $ git add .gitignore warning: LF will be replaced by CRLF in .gitignore. The file will have its original line endings in your working directory $ git commit -m "Add gitignore" [master 9ed82f0] Add gitignore 1 file changed, 2 insertions(+) create mode 100644 .gitignore
之后log文件的改变都会被staging area忽略了:
1 2 3 4 5 $ echo hello > logs/main.log $ git status On branch master nothing to commit, working tree clean
可以看到nothing to commit。
如果已经 用 git add 不小心将 log 文件提交到 staging area 了(在写入.gitignore之前就交了),可以用命令删除 staging area 中的文件。先 help 一下看看用啥选项:
1 2 3 4 5 6 7 8 9 10 11 12 $ git rm -h usage: git rm [<options>] [--] <file>... -n, --dry-run dry run -q, --quiet do not list removed files --cached only remove from the index -f, --force override the up-to-date check -r allow recursive removal --ignore-unmatch exit with a zero status even if nothing matched --pathspec-from-file <file> read pathspec from file --pathspec-file-nul with --pathspec-from-file, pathspec elements are separated with NUL character
1 $ git rm --cached -r logs/
Short Status git status 给出的信息易于理解,但是冗长:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ echo sky >> file1.js $ echo sky > file2.js $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: file1.js Untracked files: (use "git add <file>..." to include in what will be committed) file2.js no changes added to commit (use "git add" and/or "git commit -a" )
加 -s 选项:
观察 M 的颜色变化,git add 之后 M 由红变绿,?? 变 A
Viewing the Staged & Unstaged Changes Motivation: 有时候在将changes上传到staging area或commit到repository之前,要先看看改了啥,改得对不对。
查看staged changes (在staging area中但是还没commit):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ git diff --staged diff --git a/file1.js b/file1.js index ce01362..7633964 100644 --- a/file1.js +++ b/file1.js @@ -1 +1,3 @@ hello +sky +sun diff --git a/file2.js b/file2.js new file mode 100644 index 0000000..f5e95e7 --- /dev/null +++ b/file2.js @@ -0,0 +1 @@ +sky
查看unstaged changes (在本地目录下,不在staging area中):
比如在file1.js中将hello 改为 hello world:
a是在staging area中的copy,b是本地目录下的copy
@@ -1,3 +1,3 @@ 表示旧版本(staging area中的)从第一行开始,有3行(-1,3);新版本(本地目录下的)从第一行开始,有3行(+1,3)
标红的是旧版本内容,标绿的是新版本内容,白色的是未更改内容。
1 2 3 4 👉 KDiff3 👉 P4Merge 👉 WinMerge (Windows Only) 👉 VSCode
我们选用VSCode来可视化changes。配置:
1 2 3 4 5 $ git config --global diff.tool vscode $ git config --global difftool.vscode.cmd "code --wait --diff $LOCAL $REMOTE " $ git config --global -e
查看unstaged changes:
查看staged changes(旧版本是前一次提交到仓库的版本,新版本是如今在staging area中的版本):
1 2 3 4 5 6 7 $ git difftool --staged Viewing (1/2): 'file1.js' Launch 'vscode' [Y/n]? y Viewing (2/2): 'file2.js' Launch 'vscode' [Y/n]? y
Viewing the History 用以下命令查看提交历史:
查看简短描述 (最近更改显示在上面):
换显示顺序 (最近更改显示在下面):
1 $ git log --oneline --reverse
Viewing a Commit 可以通过ID查看历史commit,如果ID前几位就唯一标识了某历史commit,那么用前几位即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 $ git log --oneline fdb7fb6 (HEAD -> master) add data 62416e2 add files fde6777 modified f264740 modified 9ed82f0 Add gitignore 70800e8 Refactor code d6f4cc6 Initial commit 3fd1e3e Remove unused code b184de1 Remove unused code dd03e4e Fix the bug 3b634ca add Lines a787fca add line 568c0fc Initial commit. $ git show 62416 commit 62416e293cdb5f7334ea6dc09a8fbb0314eedcc2 Author: Stone <masaike@qq.com> Date: Thu Apr 22 11:32:51 2021 +0800 add files diff --git a/file1.js b/file1.js new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/file1.js @@ -0,0 +1 @@ +hello
也可以用HEAD:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ git show HEAD~1 commit 62416e293cdb5f7334ea6dc09a8fbb0314eedcc2 Author: Stone <masaike@qq.com> Date: Thu Apr 22 11:32:51 2021 +0800 add files diff --git a/file1.js b/file1.js new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/file1.js @@ -0,0 +1 @@ +hello
HEAD是当前commit的reference, HEAD~1是指从HEAD往后的一个commit,此例中就是ID为62416e2的commit。
也可以查看某历史 commit 中存于 repository 的内容(而不是changes):
1 2 3 4 5 $ git show HEAD~1:.gitignore logs/ bin/ *.log *.bin
也可以查看某历史 commit 中存于 repository 的所有文件:
1 2 3 4 5 6 $ git ls-tree HEAD 100644 blob 1cd4d4e7fe27c57dc89d6e68d1f535f00382e563 .gitignore 040000 tree 38051ae48accaf0025a257eaa7a3a328e1f0fe56 data 100644 blob 29887f938f21333a5eee9dfd0decb4b0a207d855 file1.js 100644 blob f5e95e70e524ec32d0200e10ba179ab4c5f13884 file2.js 100644 blob ce013625030ba8dba906f756967f9e9ca394464a main.js
格式:ID, 文件类型, 唯一标识符 (根据文件内容确定的), 文件名
data是个文件夹,所以类型为tree,里面有个文件main.txt。
根据文件唯一标识符查看文件内容:
1 2 3 4 5 6 7 $ git show 3805 tree 3805 main.txt $ git show f5e95 sky
f5e95 是 file2.js 的唯一标识符的前几位,该文件的内容只有一行,就是 sky
1 2 3 4 5 总结:Git Objects 👉 Commits 👉 Blobs (Files) 👉 Trees (Directories) 👉 Tags
Unstaging Files file1.js有两次changes,我们用 git add 将 file1.js 的第一个变化上传到 staging area中了,第二次 change 还在本地目录中。
我们不想同时 commit file1.js 和 file2.js 两个文件的变化。所以要 undo 这个 git add 操作:
1 $ git restore --staged file1.js
现在 file1.js 的两次变化都只在本地目录下而不在 staging area 中了。
原理:staging area 从目前的 repository 读取 file1.js 。因为两次变化都还没 commit ,repository 中的 file1.js 就是原始的 (两次变化之前的)。
如果要撤销 file2.js 的 git add 操作。repository 中还没有 file2.js, 所以撤销之后 file2.js 是一个untracked file (用??表示)。
Discarding Local Changes 用
可以撤销本地目录下的改变。file2.js 依然是untracked file,因为本地目录要从staging area 读取上一次状态,而staging area 中没有 file2.js, 就不知道该做啥。所以要用
从你的工作目录中删除所有untracked,没有被管理 过的文件。
参数说明:
1 2 3 4 5 6 7 8 9 10 11 12 $ git clean -h usage: git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>... -q, --quiet do not print names of files removed -n, --dry-run dry run -f, --force force -i, --interactive interactive cleaning -d remove whole directories -e, --exclude <pattern> add <pattern> to ignore rules -x remove ignored files, too -X remove only ignored files
Restoring a File to an Earlier Version 下面的 demo 显示了删除了 file1.js 后用 git restore 从历史 commit 中恢复此文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 $ git rm file1.js rm 'file1.js' $ git status -s D file1.js $ git commit -m "Delete file1.js" [master 78daaab] Delete file1.js 1 file changed, 1 deletion(-) delete mode 100644 file1.js $ git log --oneline 78daaab (HEAD -> master) Delete file1.js 133904b commit file1.ls 0f62ff0 remove all js files fdb7fb6 add data 62416e2 add files fde6777 modified f264740 modified 9ed82f0 Add gitignore 70800e8 Refactor code d6f4cc6 Initial commit 3fd1e3e Remove unused code b184de1 Remove unused code dd03e4e Fix the bug 3b634ca add Lines a787fca add line 568c0fc Initial commit. $ git restore --source =HEAD~1 file1.js $ git status -s ?? file1.js