实践中的Git常用指令分析
从工作开始,一直都在使用为知笔记(作为程序员需要知道的内容很多---不需要很深入理解,一段时不使用的东西可能就会忘记)。但本周一同步不同PC端时,了解到为知会在2017/1/1开始收费!
既然收费了,咱就不用了;但同步功能真得很好用。看看自己平日里做的笔记,恰好给自己一个写作的机会(那就把它们整理一下,发表到博客园上吧)。
“好记性不如烂笔头嘛!”是James一直坚信的理念。希望你也如此!(下述图片为转载)
之前的博客《Git--常用场景解析》,说道了一下安装和基本常识;本篇说说更加深入一点的内容,包括:
1. 如何获取Git平台的所有可用指令,以及对特定Command的帮助文档;
2. Git的add指令分析;
3. Git的commit指令分析;
4. Git的rm指令分析;
5. Git的mv指令分析;
6. Git的show指令分析;
7. Git的diff指令分析;
8. Git的push指令分析;
9. Git的init指令分析;
10. Git的clone指令分析。
主题1:Git平台的帮助文档
如果想知道Git到底有多大,那就应该知道Git平台到底有多少可用指令。
james@james-PC MINGW64 /d/GitDemo/remoteGit (BARE:master) $ git usage: git [--version] [--help] [-C <path>] [-c name=value] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] <command> [<args>] These are common Git commands used in various situations: start a working area (see also: git help tutorial) clone Clone a repository into a new directory init Create an empty Git repository or reinitialize an existing one work on the current change (see also: git help everyday) add Add file contents to the index mv Move or rename a file, a directory, or a symlink reset Reset current HEAD to the specified state rm Remove files from the working tree and from the index examine the history and state (see also: git help revisions) bisect Use binary search to find the commit that introduced a bug grep Print lines matching a pattern log Show commit logs show Show various types of objects status Show the working tree status grow, mark and tweak your common history branch List, create, or delete branches checkout Switch branches or restore working tree files commit Record changes to the repository diff Show changes between commits, commit and working tree, etc merge Join two or more development histories together rebase Reapply commits on top of another base tip tag Create, list, delete or verify a tag object signed with GPG collaborate (see also: git help workflows) fetch Download objects and refs from another repository pull Fetch from and integrate with another repository or a local branch push Update remote refs along with associated objects 'git help -a' and 'git help -g' list available subcommands and some concept guides. See 'git help <command>' or 'git help <concept>' to read about a specific subcommand or concept.
上述git指令给出的结果,对Git平台上涉及到的指令进行了分类,并给出了指令格式:—command –args。想要知道Git平台的所有指令,还需要执行以下指令:
james@james-PC MINGW64 /d/GitDemo/remoteGit (BARE:master) $ git help --all usage: git [--version] [--help] [-C <path>] [-c name=value] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] <command> [<args>] available git commands in 'C:\Program Files\Git\mingw64/libexec/git-core' add fsck-objects rebase--helper add--interactive gc receive-pack am get-tar-commit-id reflog annotate grep relink apply gui remote archimport gui--askpass remote-ext archive gui--askyesno remote-fd askpass gui.tcl remote-ftp bisect hash-object remote-ftps bisect--helper help remote-http blame http-backend remote-https branch http-fetch repack bundle http-push replace cat-file imap-send request-pull check-attr index-pack rerere check-ignore init reset check-mailmap init-db rev-list check-ref-format instaweb rev-parse checkout interpret-trailers revert checkout-index log rm cherry ls-files send-email cherry-pick ls-remote send-pack citool ls-tree sh-i18n--envsubst clean mailinfo shortlog clone mailsplit show column merge show-branch commit merge-base show-index commit-tree merge-file show-ref config merge-index stage count-objects merge-octopus stash credential merge-one-file status credential-manager merge-ours stripspace credential-store merge-recursive submodule credential-wincred merge-resolve submodule--helper cvsexportcommit merge-subtree subtree cvsimport merge-tree svn cvsserver mergetool symbolic-ref daemon mktag tag describe mktree unpack-file diff mv unpack-objects diff-files name-rev update-index diff-index notes update-ref diff-tree p4 update-server-info difftool pack-objects upload-archive difftool--helper pack-redundant upload-pack fast-export pack-refs var fast-import patch-id verify-commit fetch prune verify-pack fetch-pack prune-packed verify-tag filter-branch pull web--browse fmt-merge-msg push whatchanged for-each-ref quiltimport worktree format-patch read-tree write-tree fsck rebase git commands available from elsewhere on your $PATH flow 'git help -a' and 'git help -g' list available subcommands and some concept guides. See 'git help <command>' or 'git help <concept>' to read about a specific subcommand or concept.
通过上述结果,可想而知:Git是如此庞大。
若想要知道某个具体command的含义,只需要执行:git help <command>。
主题2:git add指令
Git显式地将本地代码分为三个层级,或者本地目录下的文件分为三个状态。对于最后一种说法,Git分为的三个状态分别是:工作区,暂存区和版本区(最终修改提交的位置)。
使用:git add <file> 或者 git add .,将文件加入暂存区中。
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) index.html nothing added to commit but untracked files present (use "git add" to track) james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git add . warning: LF will be replaced by CRLF in index.html. The file will have its original line endings in your working directory.
对于新建的一个文件,Git会提示文件状态为:Untracked files,并提示对应可用的指令:git add <file>...
此时执行:git status可查看文件状态的改变:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: index.html
使用add指令后,文件状态发生了改变:Changes to be committed(可被commit的状态)
根据提示,使用下述指令可以将文件从暂存区移除:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git rm --cached index.html rm 'index.html' james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) index.html nothing added to commit but untracked files present (use "git add" to track)
使用rm指令,文件状态回到了Untracked状态(状态做了翻转)。
主题3:git commit指令
提交新文件new file(已存在于暂存区中)到代码仓库,可以执行以下指令:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: index.html james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git commit -m "Initial contents of public_html" [master (root-commit) dc785f6] Initial contents of public_html 1 file changed, 1 insertion(+) create mode 100644 index.html
执行了:git commit ...指令后就是将暂存区中的代码提交到了代码仓库中。
git log...可以查看历次提交commit内容:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git log commit dc785f69abdcb1b2897d5a76bf38562186029e39 Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 10:14:26 2016 +0800 Initial contents of public_html
再次修改该文件(前提是:仓库中已经有该文件),代码仓库已知晓该文件:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ cat index.html <html> <body> My websit is alive! </body> </html> james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: index.html no changes added to commit (use "git add" and/or "git commit -a")
git status状态指出,文件已修改(但对于Commit而言,本次修改没有被暂存:Changes not staged for commit)
再次提交时,直接给出已修改文件的文件名,否则达不到提交的效果:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git commit index.html [master 4b6d0b2] Convert to HTML 1 file changed, 4 insertions(+) james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git log commit 4b6d0b2a8b3268f9515eec522c4725980fe2feed Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 10:30:14 2016 +0800 Convert to HTML commit dc785f69abdcb1b2897d5a76bf38562186029e39 Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 10:14:26 2016 +0800 Initial contents of public_html
在上述执行了:git commit index.html时,会跳转到vim界面并编辑commit的log message。本次提交直接将工作目录的修改提交到了代码仓库,中间跳过了Staged状态。
git commit -m "descr..." 默认将 index 中的所有改动(如果workspace中的改动提交给了index,即执行了 git add 操作,但忽略那些没有提交的改动)提交到local respository中。
git commit -a -m "modify: all file" 执行结果:提交了对所有结果的改动,直接影响到了所有文件(是对所有已存在于index区域的文件改动有效,对未存在于index的文件无效,不管有没有执行 git add <modify>...)。
git commit -m "descr..." <file>... 将index中的指定文件的改动提交到local respository中(此时在workspace中的该文件必须是提交给index,若是未提交给index的文件,将会找不到)。
git commit --amend 对最新提交进行修改(对最近一次提交进行修改),重写commit信息,而不会产生另外的新提交;git commit -m "commit lg" --amend:重写最近一次提交说明,不进入vim界面。
对于git commit指令不推荐使用参数 -a,否则,将会丢失对提交内容进行控制的能力。
主题4:git rm指令
Git中提到的rm指令,实际是:remove,移除或去除。
删除仓库中本身存在的文件,使用一次提交即可实现:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git rm poem.html rm 'poem.html' james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: poem.html james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git commit -m "Remove poem.html" [master 4481246] Remove poem.html 1 file changed, 1 deletion(-) delete mode 100644 poem.html
使用:git rm ...指令实现删除文件操作。git rm ..实际上执行了两个步骤:1.删除文件;2.将删除文件这一改动添加到暂存区中。
遍历目录内容:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ ls -al total 9 drwxr-xr-x 1 james 197121 0 十二 3 20:51 ./ drwxr-xr-x 1 james 197121 0 十二 3 09:41 ../ drwxr-xr-x 1 james 197121 0 十二 3 20:51 .git/ -rw-r--r-- 1 james 197121 49 十二 3 10:26 index.html
主题5:git mv指令
重命名Git仓库中的文件有两种手法,前者为后者指令的分解操作。
git-mv - Move or rename a file, a directory, or a symlink.
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ mv test.txt testOtherName.txt james@james-PC MINGW64 /d/GitDemo/public_html (master) $ ls index.html testOtherName.txt james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: test.txt Untracked files: (use "git add <file>..." to include in what will be committed) testOtherName.txt no changes added to commit (use "git add" and/or "git commit -a")
步骤1:mv指令将源文件重命名为后者;Git当前的状态显示:已将源文件删除,另增加了未存在于仓库的新文件。
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git rm test.txt rm 'test.txt' james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: test.txt Untracked files: (use "git add <file>..." to include in what will be committed) testOtherName.txt
步骤2:执行git rm ...或者git add ...将删除的文件修改添加到暂存区中。Git当前状态显示:源文件已删除,其改动已存在于暂存区中;但新生成了一个新文件,且没有没有存放到暂存区。
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git add . james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) renamed: test.txt -> testOtherName.txt
步骤3:将未添加到仓库的新文件加入暂存区中.
上述Changes to be committed显示:实际是在执行文件重名。
使用Git上的一个复合指令如下:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git mv testOtherName.txt test.txt james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) renamed: testOtherName.txt -> test.txt
下一步,将上述改动提交到代码仓库即可:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git commit -m "testOtherName to test" [master 8bac1e8] testOtherName to test 1 file changed, 0 insertions(+), 0 deletions(-) rename testOtherName.txt => test.txt (100%)
主题6:git show指令
很多时候想查看某次commit的内容,或者是文件中的修改内容。
使用:git show ...指令即可;同时需要使用特定提交的commitID作为其参数。
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git show 4b6d0b commit 4b6d0b2a8b3268f9515eec522c4725980fe2feed Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 10:30:14 2016 +0800 Convert to HTML diff --git a/index.html b/index.html index 9aefa39..a698d54 100644 --- a/index.html +++ b/index.html @@ -1 +1,5 @@ +<html> +<body> My websit is alive! +</body> +</html> \ No newline at end of file
其中参数指明的是某个指定的commit:“commit 4b6d0b2a8b3268f9515eec522c4725980fe2feed”。
另外一种方式:git show-branch ...以简洁的方式查看当前分支的提交描述。
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git show-branch --more=10 [master] Convert to HTML [master^] Initial contents of public_html
参数:--more=10指明的是最近的10次提交内容。
主题7:git diff指令
比较两次commitID或者commit的不同:
执行:git diff ...
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git diff master master^ diff --git a/index.html b/index.html index a698d54..9aefa39 100644 --- a/index.html +++ b/index.html @@ -1,5 +1 @@ -<html> -<body> My websit is alive! -</body> -</html> \ No newline at end of file james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git diff master^ master diff --git a/index.html b/index.html index 9aefa39..a698d54 100644 --- a/index.html +++ b/index.html @@ -1 +1,5 @@ +<html> +<body> My websit is alive! +</body> +</html> \ No newline at end of file
其中:master代表的是最近的一次commit,master^代表的上一次提交。可以看出:参数位置的不同,也就是基准的不同,得到的比较结果也不同。
另外一种方式,同样指明commitID号:
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git diff 4b6d0b2a dc785f69a diff --git a/index.html b/index.html index a698d54..9aefa39 100644 --- a/index.html +++ b/index.html @@ -1,5 +1 @@ -<html> -<body> My websit is alive! -</body> -</html> \ No newline at end of file
主题8:git push指令
一般情况下,一个代码仓库的分支可能是如下情况:
比如此时James所在的分支为:develop,想要将本地分支合并到远程分支,可以使用下述指令:git push origin HEAD:refs/for/develop。其中origin:远程主机名;HEAD:指代本地分支名;develop:远程分支名;
另一种情况可能是这样的:
在推送代码的时候使用的是如下指令:
git push yunos HEAD:refs/for/yunos/k88c/xxx/v6-k,其中yunos:远程主机名;HEAD:指代本地的当前分支;/yunos/k88c/xxx/v6-k:想要推送的远程分支名。
用于将本地分支的更新推送到远程主机:git push <远程主机名> <本地分支名>:<远程分支名>。如果省略远程分支名,则表示将本地分支推送与之存在”追踪关系”的远程分支(通常两者同名),如果该远程分支不存在,则会被新建(一般需要写远程分支名)。如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。git push origin表示将当前分支推送到名为"origin主机"的对应分支。
如果省略本地分支名,则表示删除指定的远程分支,相当于推送一个空的本地分支到远程分支。git push origin :master,相当于是:git push origin --delete master表明删除origin主机的master分支。
主题9:git init指令
将代码托管到Git仓库中,首先要做的是初始化(新建)仓库。
对于Git来说,不管是初始化一个空的目录,还是装有很多Files的目录,初始化Git仓库都是一样的手法。
gaoyating@gaoyating-PC MINGW64 /d/GitDemo $ cd public_html/ gaoyating@gaoyating-PC MINGW64 /d/GitDemo/public_html $ ls james@james-PC MINGW64 /d/GitDemo/public_html $ echo 'My websit is alive!' > index.html james@james-PC MINGW64 /d/GitDemo/public_html $ ls index.html james@james-PC MINGW64 /d/GitDemo/public_html $ cat index.html My websit is alive! james@james-PC MINGW64 /d/GitDemo/public_html $ git init Initialized empty Git repository in D:/GitDemo/public_html/.git/ james@james-PC MINGW64 /d/GitDemo/public_html (master) $ ls index.html james@james-PC MINGW64 /d/GitDemo/public_html (master) $ ll total 1 -rw-r--r-- 1 james 197121 20 十二 3 09:41 index.html james@james-PC MINGW64 /d/GitDemo/public_html (master) $ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) index.html nothing added to commit but untracked files present (use "git add" to track)
执行:git init指令可以初始化Git仓库;隐式地,Git会创建./.git(本目录中)目录。
james@james-PC MINGW64 /d/GitDemo/public_html (master) $ ls -al total 5 drwxr-xr-x 1 james 197121 0 十二 3 09:41 ./ drwxr-xr-x 1 james 197121 0 十二 3 09:41 ../ drwxr-xr-x 1 james 197121 0 十二 3 09:42 .git/ -rw-r--r-- 1 james 197121 20 十二 3 09:41 index.html
所有关于代码托管的信息,都会存放在.git目录中。
由此上述执行指令,就为public_index目录创建了一个Git仓库;public_index目录中的所有代码即可托管于本地所在的Git仓库中。
主题10:git clone指令
仓库拷贝使用:git clone指令实现。
james@james-PC MINGW64 /d/GitDemo $ git clone public_html/ clone_public Cloning into 'clone_public'... done. james@james-PC MINGW64 /d/GitDemo $ ls clone_public/ localGit/ public_html/ remoteGit/ james@james-PC MINGW64 /d/GitDemo $ ls -al total 24 drwxr-xr-x 1 james 197121 0 十二 3 21:14 ./ drwxr-xr-x 1 james 197121 0 十二 3 09:40 ../ drwxr-xr-x 1 james 197121 0 十二 3 21:14 clone_public/ drwxr-xr-x 1 james 197121 0 十一 20 08:37 localGit/ drwxr-xr-x 1 james 197121 0 十二 3 21:11 public_html/ drwxr-xr-x 1 james 197121 0 十一 20 08:41 remoteGit/
上述指令执行后,clone_pulic代码仓库即是public_html仓库的副本。
查看clone_public仓库的状态:
james@james-PC MINGW64 /d/GitDemo $ cd clone_public/ james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git log commit 8bac1e803752ec07728a8a702043cfdae9370eac Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 21:12:14 2016 +0800 testOtherName to test commit 908c2e3a0bcc23486887700214f451b00afeb07b Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 21:02:13 2016 +0800 move test to testOtherName commit a5e536ba19d80e5ab3d4b0ee0afc255bc8d23ba3 Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 20:59:49 2016 +0800 test git mv commit 4481246b361b9b4e34da137af84b3cd09114af2c Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 20:51:45 2016 +0800 Remove poem.html commit 9cf7a35c1dc820f997c2536e2f3341fc9cb887ff Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 20:51:06 2016 +0800 test remove file commit 4b6d0b2a8b3268f9515eec522c4725980fe2feed Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 10:30:14 2016 +0800 Convert to HTML commit dc785f69abdcb1b2897d5a76bf38562186029e39 Author: ZHANGEfeng-james <zfengwust3054@163.com> Date: Sat Dec 3 10:14:26 2016 +0800 Initial contents of public_html --author=Gao Yating <gaoya@163.com>
发现仓库的历次提交均和public_html仓库相同。
再次查看clone_public仓库和public_html仓库之间的关系,猜想是否有指向关系?
james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/master james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git branch -vv * master 8bac1e8 [origin/master] testOtherName to test
指令结果显示:clone_public仓库确实指向了远程的origin/master分支,但并没有指明远程仓库的路径。
做一次commit和push实验,查看远程仓库:
james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git status On branch master Your branch is up-to-date with 'origin/master'. Untracked files: (use "git add <file>..." to include in what will be committed) clone.txt nothing added to commit but untracked files present (use "git add" to track) james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git add . james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git commit -m "clone test" [master 5b830e5] clone test 1 file changed, 1 insertion(+) create mode 100644 clone.txt james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working tree clean
结果提示,clone_public仓库的commit超前于远程仓库,需要使用git push指令进行同步。
james@james-PC MINGW64 /d/GitDemo/clone_public (master) $ git push origin HEAD:master Counting objects: 3, done. Delta compression using up to 8 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 329 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) remote: error: refusing to update checked out branch: refs/heads/master remote: error: By default, updating the current branch in a non-bare repository remote: error: is denied, because it will make the index and work tree inconsistent remote: error: with what you pushed, and will require 'git reset --hard' to match remote: error: the work tree to HEAD. remote: error: remote: error: You can set 'receive.denyCurrentBranch' configuration variable to remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into remote: error: its current branch; however, this is not recommended unless you remote: error: arranged to update its work tree to match what you pushed in some remote: error: other way. remote: error: remote: error: To squelch this message and still keep the default behaviour, set remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'. To D:/GitDemo/public_html/ ! [remote rejected] HEAD -> master (branch is currently checked out) error: failed to push some refs to 'D:/GitDemo/public_html/'
执行push操作后的结果出现错误,但是引出了远程仓库地址:D:/GitDemo/public_html;出错的原因在于:远程仓库初始化使用的是git init指令,而不是git --bare init。