你不可不知的Git常用命令

来源:互联网 发布:qbittorrent ubuntu 编辑:程序博客网 时间:2024/06/03 00:08

前言

读这篇文章之前要求读者要有一些Git的基础,否则,一些细节有可能看不明白。这里我建议大家先读读这本书的前三章。书的链接如下:

https://git-scm.com/book/en/v2

Git原理

Git与其它的VCS不同的是,客户端不是只查看文件的最新快照,而是拥有仓库的全部镜像。如果一个Server Down了,任何一个客户端都能把项目完整的还原。Git是分布式版本控制系统,那么它是没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。

配图如下:

Git原理

每次Commit或保存你Git工程的状态时,它会把你那一瞬间的所有文件制成一个快照并引用它。如果文件没有变化,它直接引用到先前存储的快照。

配图如下:

Git原理

Git的配置文件

  1. /etc/gitconfig 包含每个用户以及他们仓库的配置。
  2. ~/.gitconfig 只针对当前用户的配置。
  3. Git目录中的.git/config 针对当前仓库的配置。

以上每一个级别都会覆盖上一个级别的配置。

Git增加文件相关命令

$ git init 创建一个.git目录,以及所有必要仓库骨架。把当前目录变成git可以管理的仓库。

git init

$ git status 显示有变更的文件。$ git status -s 显示有变更的文件。??表示没有被tracked的文件 A表示没有被加到暂存区(index)的文件 M表示被修改过的文件
$ git add [文件或目录] 把文件添加到暂存区(index)里面去。
$ git commit -m [提交信息] 把暂存区(index)的内容提交到仓库。如果不加-m选项,则会启动你默认的编辑器让你编辑提交信息。$ git commit [文件1] [文件2] ... -m [提交信息] 提交暂存区的指定文件到仓库。$ git commit --amend 使用一次新的commit,替代上一次提交。

git commit

$ git diff 显示暂存区和工作区的差异$ git diff --staged 显示暂存区和上一个commit之间的差异

git diff
上图中:第一个vim我创建了diff.intro的文件,内容是“显示暂存区和工作区的差异”。第二个vim我将文件的内容加了“aaaaa”。
git diff
上图中是显示暂存区和上一个commit之间的差异的一个例子。

$ git log 显示当前分支的版本历史

git log

$ git log -p -2 显示当前分支的版本历史,并显示每个文件的diff信息,并限制输出2个commit

git log

$ git log --oneline 如下图$ git log --oneline --decorate 如下图

git log

$ git log --oneline --decorate --graph --all 显示commit历史,及分支信息,具体如下图。

git log
git log有很多形式的选项来限制输出信息,具体请查阅文档。

Git撤消文件的修改相关命令

在介绍一些撤消文件的修改命令之前,我先介绍一下2个比较奇怪的符号~和^。它们是指定某个commit的速记法(shorthand),有了它们以后我们就不需要用像cb8bb8c这样的Hash Name来指定某个commit了。具体实例如下:

  • HEAD~是HEAD~1的简写,它们都表示当前HEAD所指定的commit的第一个双亲。HEAD~2表示当前HEAD所指定的commit的第一个双亲的第一个双亲。以此类推……
  • 一个标准的Merge commit有两个双亲-第一个是merge到当前的commit,第二个是被merge的commit。通常情况下merge实际上有可能有任意多个父亲(octopus merges)。HEAD^(or HEAD^1)表示当前HEAD所指定的commit的父母。HEAD^2表示当前HEAD所指定的commit的第二个父母。
  • ^和~可以混合一起使用。例如:HEAD~3^2,它表示当前HEAD所指定的commit的第三个双亲的第二个父亲。HEAD^^2,它表示当前HEAD所指定的commit的第一个父亲的第二个父亲。HEAD^^^和HEAD~3是等价的。

referencing commits from HEAD using ~ and ^

下图为我当前分支状态:

分支状态

现在我要将README.md文件中的内容恢复为“aaaaa”,运行如下命令:

$ git checkout HEAD^2^ 恢复文件到commit b8cd6e3的状态。

分支状态

$ git checkout [文件] 恢复暂存区的指定文件到工作区。$ git checkout [commit] [文件] 恢复某个commit的指定文件到工作区。$ git checkout . 恢复上一个commit的所有文件到工作区。$ git checkout -- [file] 丢弃工作区文件的改变,与上一次commit的文件一致。
$ git reset --hard [commit] 重置暂存区与工作区,与指定的commit保持一致。

git reset

$ git reset --mixed [commit] 它是git reset的默认选项。它重置暂存区,但不重置工作区。

git reset

$ git reset --soft [commit] 它不会重置你的工作区和暂存区

比如说你提交错了一个文件或者commit信息你写错了,那么你可以用这个命令取消上一次的commit,修改正确以后在重新提交。例子如下图:
git reset

从上图我们好看到了重置以后,如果你想的话可以直接提交,因为它并没有重置你的暂存区。上图中我只修改了一下提交信息,你也可以重新修改文件,重新commit。加上-c ORIG_HEAD将打开一个编辑器初始化先前commit的log message,允许你编辑它,如果你想直接使用先前的commit并不想编辑它,用-C代替。

$ git reflog  查看所有分支的所有操作记录,包括commit和reset的操作以及被删除的commit记录$ git reflog show [分支]  查看某个分支的所有操作记录

Git删除文件相关命令

$ git rm [file1] [file2] ...  删除工作区文件,并且将这次删除放入暂存区。$ git rm --cached [file1] [file2] ...  停止追踪指定文件,但该文件会保留在工作区。$ git mv [file-original] [file-renamed]  改名文件,并且将这个改名放入暂存区

git rm

Git标签相关命令

$ git tag 列出所有tag, 按字母表顺序。$ git tag -a [标签名] 针对上一次提交创建一个重量级标签。$ git tag -a [标签名] [commit] 为指定的commit创建一个重量级标签。$ git tag -d [标签名] 删除指定的标签。$ git show [标签名] 显示对应这个标签的commit信息。

Git远程同步相关命令

$ git remote -v  显示所有远程仓库。$ git remote rename [srcremote] [desremote]  修改远程仓库名。$ git remote show [remote]  显示某个远程仓库的信息。$ git remote add [shortname] [url]  增加一个新的远程仓库,并命名。$ git remote rm [remote] 移除远程仓库。
$ git fetch [remote]  下载所有远程仓库的变动到你的本地仓库,但是不merge到你当前的工作空间。并且有了所有远程分支的引用。$ git push [remote] [branch] 上传本地指定分支到远程仓库。
$ git push [remote] [tag]  提交指定tag到远程仓库。$ git push [remote] --tags  提交所有tag到远程仓库。

Git分支相关命令

$ git branch  列出所有本地分支。$ git branch -r  列出所有远程分支。$ git branch -a  列出所有本地分支和远程分支。$ git branch -vv  列出所有本地分支及其跟踪的分支。$ git branch [branch-name]  新建一个分支,但依然停留在当前分支。$ git branch -d [branch-name]  删除分支$ git checkout -b [branch-name] 新建一个分支,并切换到该分支。$ git checkout [branch-name] 切换到指定分支,并更新工作区。$ git merge [branch]  合并指定分支到当前分支。
$ git branch --track [branch] [remote-branch] 新建一个分支,与指定的远程分支建立追踪关系。$ git branch --set-upstream-to=[remote-branch]  当前所在的分支与指定的远程分支之间建立追踪关系。
$ git branch [branch] [commit]  新建一个分支,指向指定commit。$ git branch --set-upstream-to=[remote-branch]  当前所在的分支与指定的远程分支之间建立追踪关系。$ git push  [remote]  --delete [branch] 删除远程分支。

Git 一些常用的实践场景及解决方案

在这个小节中,我会把我在实际工作中用到的一些场景介绍给大家。针对这些场景我们应该用什么样的git命令解决呢?请大家向下看吧。

保存working directory的变化

假如我有2个分支,一个叫master,另一个叫dev,我当前所在的分支为dev,并对这个分支中的一些文件做了修改。假设,在master分支上现在有些问题需要你马上去解决,但是你当前dev分支的一个功能你并没有完全做完,因此你不能commit,那么问题来了,我们如何回到master去解决问题,然后在回到dev分支继续解决我未完成的问题?下面的这些命令可以解决这个问题。

$ git branch ------ 列出本地的分支,* 表示我当前所在的分支* devmaster$ git status ------ 下面的2个文件都做了一些修改,但是还没有完全改完On branch devChanges 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:   AuthorizationInterceptor.java    modified:   spring-mvc.xml$ git stash -p ------ 你可以选择你想stash的文件,每个字母所表示的含义在下面的引用中。$ git stash list ------ 可以看到所有的stash,如果你有多个stash那么0代表你最新的stashstash@{0}: WIP on dev: 10183b5 Change logic of task completion$ git stash show stash@{0} ------ 这里我指定了stash@{0},如果你不指定,Git会默认选择最新的stashAuthorizationInterceptor.java | 292 +++++++++++++++++++++++++++++------------------------------spring-mvc.xml                |  11 +--2 files changed, 148 insertions(+), 155 deletions(-)$ git checkout master ------ 现在你可以放心地切换回master分支去解决问题吧$ git checkout dev ------ 解决问题过后,回到dev分支$ git checkout master ------ 现在你可以放心地切换回master分支去解决问题吧$ git stash apply stash@{0} ------ 它会把stash@{0}应用到当前的工作目录,如果不指定,默认为stash@{0}$ git stash pop stash@{0} ------ 和apply基本一样,但是它会把指定的stash从stash列表中移除

通过上面我给出的那些命令,你可以解决我上面给出场景的问题了。

git stash -p 提示时, 每个字母所表示的含义

y - stash this hunk
n - do not stash this hunk
q - quit; do not stash this hunk or any of the remaining ones
a - stash this hunk and all later hunks in the file
d - do not stash this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

引用链接: Stash only one file out of multiple files that have changed with Git?

把一个指定的文件还原到指定的commit

假设我把一个文件改的不好,我想回到先前commit的版本,用下面的命令就可以做到了。

$ git log login.jsp ------ 查看login.jsp的commit历史,你也可以加一些选项来过滤$ git checkout cb0226e login.jsp ------ 把这个文件还原到cb0226e这个commit

取消我本地的commit

假设我更改了一个文件叫做qa,然后把这个文件commit了。过一会我发现qa文件不应该那样去修改,我给改错了。但是,我已经把它commit上去了,那么我应该如何取消错误地那个commit,然后把qa文件正确的修改过后在commit上去呢?下面的命令可以做到:

$ git commit -m "qa文件错误地commit" ----- 这是我错误地commit$ git reset HEAD~ ------- 把当前HEAD重置到指定的commit$ vim qa ----------- 现在你来修改qa文件$ git add qa$ git commit -c ORIG_HEAD ----- 重用你错误地那个commit对象,并提交

注意:这仅仅是用这个新的commit去替换你那个错误地commit,而不是把你那个错误地commit删除,然后在提交。还有就是git commit 的那个参数c 和 C 是有区别的,用git help commit 自己去看看吧,很简单。

后记

当我们用 git fetch [remote]命令时,我们并没有一个新创建的分支,我们只有一个不能修改的指向远程仓库的引用,例如:origin/master.但是我们可以将其merge到当前工作区,你就有一个可以修改的分支了。

还有最后一个特别方便的命令:

$ git config --global alias.ci commit 设置别名。

以后在提交的时候用git ci就可以工作了。

相关资料

http://mislav.net/2010/07/git-tips/ 你还不知道的几个Git技巧

文章修改于2017.2.16

0 0