之前梳理介绍过subversion版本控制,本文承接《Mac下git通过SSH进行免密码安全连接github》,基于一个初级的git版本控制流程贯串示例讲解git日常操作,备忘查阅。
在 macOS Terminal 中执行 which 或 whereis 命令可以查看 git 的位置:
➜ bin which git
/usr/bin/git
➜ bin whereis git
/usr/bin/git
which git
返回的结果是 /usr/bin/git
,同svn一样,它们是 Xcode 安装 Command Line Tools 时安装的 git wrapper,或者叫 shims or wrapper executables,真正的工具包实体在 Xcode.app 里面:
➜ ~ xcrun -f git
/Applications/Xcode.app/Contents/Developer/usr/bin/git
在终端输入 git version
或 git --version
查看系统自带的 git 版本比较旧,为 2.3.8:
➜ ~ git version
git version 2.3.8 (Apple Git-58)
执行 ls git*
可查看 git binUtils 组成:
➜ ~ cd /usr/bin
➜ bin ls git*
git git-receive-pack git-upload-archive
git-cvsserver git-shell git-upload-pack
可从 git 官网下载git for Mac下载安装包(git-2.5.3-intel-universal-mavericks.dmg),点击 git-2.5.3-intel-universal-mavericks.pkg
可安装 git binUtils,默认安装到 /usr/local/git
目录下:
➜ ~ cd /usr/local/git/bin
➜ bin git:(master) ls
git git-receive-pack git-upload-pack
git-credential-osxkeychain git-shell gitk
git-cvsserver git-upload-archive
setup git PATH for non-terminal programs.sh
脚本设置新版 git 为非命令行程序的默认 git。/Applications/Xcode.app/Contents/Developer/usr/bin
下即可。git
或 git --help
可以查看 git usage,一览 most commonly used git commands 要义:git add
帮助的两种方式:➜ ~ git --help add(git help add)
或
➜ ~ man git add
按下Q
键退出 manual。
gitk - The Git repository browser
Graphical Interfaces
GUI Clients
Git各大平台(win/Linux/Mac)图形化界面客户端大汇总
github
The Power of Git – in a Windows Shell
Windows Explorer Extension to Operate Git
TortoiseSVN 孪生兄弟,建议 Windows 采用。
Documentation
Get your commit done.
SmartGit runs on Windows, macOS and Linux.
SmartGit is a graphical Git client with support for SVN and Pull Requests for GitHub and Bitbucket.
SmartSVN 孪生兄弟,建议 Windows/macOS 采用。
SmartGit初步使用
SmartGit 安装及使用(一):安装及配置
SmartGit一直强提示让确认“于非营利目的”解决步骤 - 注册非商业许可证
A free Git client for Windows and Mac
Simplicity and power in a beautiful Git GUI
没法看整个仓库的文件和单个文件的历史,用命令行或 gitk 辅助?
git 配置分为系统级别、用户级别和项目级别,--global
选项指定用户级别的配置。
➜ ~ git config --global user.name fan2
➜ ~ git config --global user.email [email protected]
配置完成后,可以输入 git config --list
命令查看当前配置。
后面该用户的 git 提交信息中将自动嵌入用户信息,即 git log 查看到的每条 log 的 Author 及 Mail 等信息。
也可针对具体项目(cd到 .git
所在目录)执行 git config 命令,而无需指定 --system
或 --global
选项,配置适用于独立项目的作者信息或代理信息(http.proxy)。
➜ ~ cd Projects/Xcode/resizableImageWithCapInsets
查看当前目录:
➜ ~ pwd
/Users/faner/Projects/Xcode/resizableImageWithCapInsets
当前目录为空文件夹,ls
或 ls -a
列举无内容。
使用 git status
命令可以查看当前工作目录的 git 版本控制状态(增删改等)。
➜ resizableImageWithCapInsets git status
fatal: Not a git repository (or any of the parent directories): .git
Not a git repository
表明当前工程(项目)尚未纳入 git 版本控制。
创建初始化 git 版本库,需要使用 git init
命令:
➜ resizableImageWithCapInsets git init --help
NAME
git-init - Create an empty Git repository or reinitialize an existing one
DESCRIPTION
This command creates an empty Git repository - basically a .git directory with
subdirectories for objects, refs/heads, refs/tags, and template files. An
initial HEAD file that references the HEAD of the master branch is also
created.
对当前项目(目录)执行 git init
命令,即可初始化一个本地 git 仓库:
➜ resizableImageWithCapInsets git init
Initialized empty Git repository in /Users/faner/Projects/Xcode/resizableImageWithCapInsets/.git/
此时运行 ls -a
列举当前目录:
➜ resizableImageWithCapInsets git:(master) ls -a
. .. .git
可以发现该目录下新增了一个隐藏的 .git
文件夹,即初始化了一个本地仓库(git repository)。
若是从 github 等远程仓库克隆(clone)下来的项目,则默认即是一个追踪了远程仓库的 git repository,无需再执行 git init
初始化。
此时,再次执行 git status
命令可查看初始化的本地仓库状态:
➜ resizableImageWithCapInsets git:(master) git status
On branch master
Initial commit
nothing to commit (create/copy files and use "git add" to track)
由于当前 Git Repo 刚初始化,没有任何增删改操作,故没啥好提交的:nothing to commit
。
它提示我们创建(create)或从别处拷贝(copy)文件过来,并调用 git add
命令添加追踪。
注意
:以下 git 操作都是基于 当前工作目录,即包含 .git
的 Working directory/Working Tree。
touch README.md
命令新建 README.md 文件:➜ resizableImageWithCapInsets git:(master) touch README.md
➜ resizableImageWithCapInsets git:(master) ✗ ls
README.md
vim README.md
打开 vim 进行编辑:➜ resizableImageWithCapInsets git:(master) ✗ vi README.md
i
: insert模式编辑;esc
: 退出insert编辑模式;:wq
: 保存退出cat README.md
,可查看文件内容:➜ resizableImageWithCapInsets git:(master) ✗ cat README.md
README for resizableImageWithCapInsets.
git status
命令可查看当前本地仓库状态:➜ resizableImageWithCapInsets git:(master) ✗ git status
On branch master
Initial commit
Untracked files:
(use "git add ..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
Untracked files
,即新建的README.md文件未被git追踪(Unversioned/Untracked)。use "git add" to track
,提示使用git add
命令将未追踪文件添加追踪(add to version control),纳入版本控制(tracked)。添加本地文件到git版本控制,需要使用 git add 命令:
➜ ~ git add --help
NAME
git-add - Add file contents to the index
DESCRIPTION
This command updates the index using the current content found in the working
tree, to prepare the content staged for the next commit. It typically adds the
current content of existing paths as a whole, but with some options it can also
be used to add content with only part of the changes made to the working tree
files applied, or remove paths that do not exist in the working tree anymore.
The "index" holds a snapshot of the content of the working tree, and it is this
snapshot that is taken as the contents of the next commit. Thus after making
any changes to the working directory, and before running the commit command,
you must use the add command to add any new or modified files to the index.
It typically adds the current content of existing paths as a whole, but with some options it can also be used to add content with only part of the changes made to the working tree files applied, or remove paths that do not exist in the working tree anymore.
The “index” holds a snapshot of the content of the working tree, and it is this snapshot that is taken as the contents of the next commit. Thus after making any changes to the working directory, and before running the commit command, you must use the add command to add any new or modified files to the index.
index 有时候也被称作 Staging area
或 Cache
,git add
命令会将文件改动暂存到 index 中(.git/index)。
基本语法:git add
可以是 .
,表示添加当前目录下所有(as a whole)未追踪的文件或修改(unversioned/untracked files or modification)到git索引。添加README.md文件:
➜ resizableImageWithCapInsets git:(master) ✗ git add README.md
由于当前文件只有一个 Untracked files,因此也可执行 git add .
。
再次执行 git status
命令可查看当前本地仓库状态:
➜ resizableImageWithCapInsets git:(master) ✗ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached ..." to unstage)
new file: README.md
提示有改动需要提交(Changes to be committed):新增了文件(new file: README.md)。
此时,若反悔了,想解除对 README.md 文件的追踪(Undo an Added new file),亦可执行 git rm --cached
:
➜ resizableImageWithCapInsets git:(master) ✗ git rm --cached README.md
rm 'README.md'
则 README.md 文件又恢复到 git add
之前的状态——Untracked。
注意
:
git rm --cached README.md
只是将 README.md 文件从暂存区(Index/Staging area)移除,文件依旧保留(keep the file);git rm -f README.md
,则强制物理删除(force removal)本地文件。将暂存区中的变更提交到到git仓库,需要使用 git commit
命令:
➜ ~ git commit --help
NAME
git-commit - Record changes to the repository
DESCRIPTION
Stores the current contents of the index in a new commit along with a log
message from the user describing the changes.
OPTIONS
-m <msg>, --message=<msg>
Use the given <msg> as the commit message. If multiple -m options are
given, their values are concatenated as separate paragraphs.
之前在 resizableImageWithCapInsets 这个WC(Working directory/Working tree)新增(git add)了 README.md 文件。
这个 git add
新增变更是记录在 index(staging area)中,下面将其添加到本地 git 仓库。
➜ resizableImageWithCapInsets git:(master) ✗ git commit -m "This is the first commit."
[master (root-commit) ee53e68] This is the first commit.
1 file changed, 1 insertion(+)
create mode 100644 README.md
再次执行 git status
命令查看当前本地仓库状态:
➜ resizableImageWithCapInsets git:(master) git status
On branch master
nothing to commit, working directory clean
"nothing to commit, working directory clean"
表示变更已入库,当前工作目录是干净(clean)的。
执行 git commit
提交后,可通过 git log
命令查看提交日志:
commit ee53e68e599695f15b8e91d5eb3fd490f945a23e
Author: fan2 <[email protected]>
Date: Sun Sep 13 15:34:13 2015 +0800
This is the first commit.
输入Q
键退出log。
后续多次提交后,可通过 git log
的 -n
选项指定 Limit the number of commits to output,例如 git log -n 2
查看最近两次的提交log。
本地仓库由 git 维护的三棵“树”组成:
将 README.md 文件add添加到 git 版本控制并commit提交到 git 仓库后,稍微改动一下 README.md 文件,增加第二行空行,第三行增加"this is the content. "。
然后,使用 git diff
命令查看工作目录与索引区文件之间的差异:
➜ resizableImageWithCapInsets git:(master) ✗ git diff README.md
diff --git a/README.md b/README.md
index 717aedf..0a1832d 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,3 @@
README for resizableImageWithCapInsets.
+
+this is the content.
按下Q
键退出diff。
关于 git diff 命令,可参考 git diff 和 读懂diff。
再次执行 git status
命令查看当前本地仓库状态:
➜ resizableImageWithCapInsets git:(master) git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working irectory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
提示修改了 README.md 文件(状态为modified),但是修改没有添加到缓存(Changes not staged)。
此种状态下,可以执行两种操作:
若执行 git add
命令可以将更改提交到暂存区(index/staging area):
➜ resizableImageWithCapInsets git:(master) ✗ git add README.md
➜ resizableImageWithCapInsets git:(master) ✗ git status
On branch master
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: README.md
git add
添加到暂存区的变更,进一步执行 git commit
提交到本地git仓库,这两步操作也可糅合为 git commit -a
一步到位。git commit
提交到HEAD之前,想要放弃通过 git add
提交到暂存区中的修改(Unstaging a Staged File/Undo an Added new modification),可执行 git reset HEAD
撤销提交到暂存中的修改:➜ resizableImageWithCapInsets git:(master) ✗ git reset HEAD README.md
Unstaged changes after reset:
M README.md
执行 reset HEAD 后,Index/Staging Area 中记录的 README.md 文件恢复恢复到上次commit完 local repository 中的 HEAD 文件记录。
Working tree 中 README.md 文件的状态则恢复为 modified(Changes Unstaged relative to index),可执行 git status
查看最新状态。
将README.md文件添加到git版本控制并且提交到git仓库后,在正式推送到远程仓库之前,若想撤销最近一次的commit怎么办呢?可参考《git 撤销commit》、《Git 撤销修改1》、《Git 撤销修改2》。
另一方面,我们也可以删除本地git仓库中的tracked/versioned文件:
➜ resizableImageWithCapInsets git:(master) git rm README.md
rm 'README.md'
再次执行 git status
命令查看当前本地仓库状态:
➜ resizableImageWithCapInsets git:(master) ✗ git status
On branch master
Changes to be committed:
(use "git reset HEAD ..." to unstage)
deleted: README.md
可执行 git reset HEAD
撤销提交到暂存中的 git rm
操作(recover by local repository’s HEAD to resume unstage status),也可以进一步执行git commit
提交缓存操作到本地git仓库生效。
Rename files and folders with git
mv oldfolder newfolder
git add newfolder
git remove oldfolder
本质上就是备份重命名,然后 remove 旧的,add 新的,实现替换重命名。
执行完以上命令后,可以进一步执行 git commit
提交缓存操作到本地git仓库生效。
前面我们本地 git 初始化了 resizableImageWithCapInsets 项目,并新增提交了 README.md 文件,所有改动已经提交到了本地仓库的 HEAD,但是还没到提交到 git 远程仓库。
执行 git status
命令可查看当前状态:
➜ resizableImageWithCapInsets git:(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 directory clean
Your branch is ahead of 'origin/master' by 1 commit
:提示我们的git本地仓库已经超过远程仓库一个版本。use "git push" to publish your local commits
:建议我们使用**git push
**命令发布本地仓库上提交的修改。git 是分布式版本控制系统。对于一个分布式节点来说,其它节点的 git 仓库都可以作为本地仓库的 远程仓库,可理解为 “git 服务器”。
当项目进行到一定的阶段时,要同别人分享目前的成果,可以使用 git push
命令将本地仓库中的数据推送到远程仓库。
在当前 Working tree 执行 git remote -v
查看其对应的远程仓库。
➜ resizableImageWithCapInsets git:(master) ✗ git remote -v
可以看到列出来的结果为空,实际上我们本地演示的git仓库尚未挂接到任何远端仓库。
这里移步github,关于本地通过SSH与github连接请参考《Mac下git通过SSH进行免密码安全连接github》。
由于 Github does not provide shell access
,因此需要去 github 个人主页手动创建仓库。Add a New Repository,名称为 resizableImageWithCapInsets,对应的URL为:
type | URL |
---|---|
SSH clone URL | [email protected]:fan2/resizableImageWithCapInsets.git |
HTTPS clone URL | https://github.com/fan2/resizableImageWithCapInsets.git |
Subversion checkout URL | https://github.com/fan2/resizableImageWithCapInsets |
由上可知 github 也提供了 subversion 支持,实际上 git 也可以与通过git-svn子命令与已有的SVN中心库进行同步。
git 对远程仓库的操作主要是基于 git remote
命令:
➜ ~ git remote --help
NAME
git-remote - Manage set of tracked repositories
DESCRIPTION
Manage the set of repositories ("remotes") whose branches you track.
COMMANDS
add
Adds a remote named <name> for the repository at <url>.
remove, rm
Remove the remote named <name>. All remote-tracking branches and
configuration settings for the remote are removed.
set-url
Changes URLs for the remote.
Adds a remote named for the repository at .
下面执行 git remote add
命令将当前本地git仓库挂接到指定的远程仓库(即追踪远程仓库):
➜ resizableImageWithCapInsets git:(master) ✗ git remote add origin [email protected]:fan2/resizableImageWithCapInsets.git
这里将 github 远端仓库地址保存到 origin
变量中,后面 push、fetch、merge 等操作可直接引用 origin 变量指代远端地址。
此时再执行执行 git remote -v
(–verbose:Be a little more verbose and show remote url after name),可查看 origin 具体代表的 fetch/push 远端地址:
➜ resizableImageWithCapInsets git:(master) ✗ git remote -v
origin [email protected]:fan2/resizableImageWithCapInsets.git (fetch)
origin [email protected]:fan2/resizableImageWithCapInsets.git (push)
如果执行 git remote add
命令时提示 fatal: remote origin already exists.
,或者想更改挂接的远端地址(比如远程仓库重命名了或移动了),可以按照以下步骤操作:
先执行命令:
git remote rm origin
再执行命令:git remote add origin
git remote set-url
(Changes URLs for the remote)相当于 rm+add:
Changing a remote’s URL
How can I change the remote/target repository URL
Change the URI (URL) for a remote Git repository
一般公司可能会屏蔽掉 SSH 协议,此时可以 rm & add
切换为 HTTPS clone URL,但是每次 git push 时都会提示输入用户名和密码。
在 OS X 上可以使用 keychain 来缓存密码:
git config --global credential.helper osxkeychain
我们前面使用 git commit
命令将本地工作目录的变更提交(合并)到本地仓库,git 使用 git push
命令来将本地仓库的变更提交(合并)到它所追踪的远程仓库:
➜ ~ git push --help
NAME
git-push - Update remote refs along with associated objects
DESCRIPTION
Updates remote refs using local refs, while sending objects necessary to
complete the given refs.
OPTIONS
-u, --set-upstream
For every branch that is up to date or successfully pushed, add upstream
(tracking) reference, used by argument-less git-pull(1) and other commands.
For more information, see branch..merge in git-config(1).
执行以下命令可以将本地仓库变更提交(合并)到它所追踪的远程仓库 origin 的 master 分支:
➜ resizableImageWithCapInsets git:(master) ✗ git push -u origin master
当本地仓库跟踪的远程仓库发生变更时,需要rebase(merge from remote to local)。
git fetch
取得两个版本的差异:➜ ~ git fetch --help
NAME
git-fetch - Download objects and refs from another repository
DESCRIPTION
Fetch branches and/or tags (collectively, "refs") from one or more other
repositories.
调用 git fetch origin
取得 remote 仓库 origin(master分支)相对 local repository HEAD 的变动 diff,可手工 merge。
➜ resizableImageWithCapInsets git:(master) ✗ git fetch origin
git merge
命令合并两个版本:➜ ~ git merge --help
NAME
git-merge - Join two or more development histories together
DESCRIPTION
Incorporates changes from the named commits (since the time their histories
diverged from the current branch) into the current branch. This command is used
by git pull to incorporate changes from another repository and can be used by
hand to merge changes from one branch into another.
调用 git merge origin/master
把更新(远程origin/master相对local repository的diff)合并(patch)到本地分支HEAD。
➜ resizableImageWithCapInsets git:(master) ✗ git merge origin/master
如有多个分支,可调用 git branch
命令查看当前分支。
当我们在本地修改了文件准备 push 推送提交时,有人已经 push 改动过远程仓库,此时 git 会提示 failed,需要执行 pull before push:
git pull = fetch + merge
➜ ~ git pull --help
NAME
git-pull - Fetch from and integrate with another repository or a local branch
DESCRIPTION
Incorporates changes from a remote repository into the current branch. In its
default mode, git pull is shorthand for git fetch followed by git merge
FETCH_HEAD.
More precisely, git pull runs git fetch with the given parameters and calls git
merge to merge the retrieved branch heads into the current branch. With
--rebase, it runs git rebase instead of git merge.
执行 git pull
之后,重新执行 git push
成功提交。
有时候,别人和自己改动了同一个文件,当自己 pull 时会提示 conflict:
Automatic merge failed
,此时,需要我们手动解决冲突再重新push提交(fix conflicts and then commit the result)。
《写给Git初学者的7个建议》
《我也用github》《git/github初级运用自如》
《git - 简明指南》《IBM developerWorks-Git之旅》
《看日记学git》《码农老毕-开发工具之git》《Git Cookbook》
《Git快速使用指南》《Git进阶教程》
《Git远程操作详解》《Git分支管理策略》
《廖雪峰-Git教程》《Git版本控制系統》
《OPEN经验库 - Git起步 & Git基础》
《Git权威指南》《GotGitHub》
《Git Reference》《Git参考手册》
《Git Community Book 中文版》《Git历险记》
《Git Book/Pro Git: en & cn》《progit2 on GitHub》
《Git Guys》《Atlassian Git Tutorial》
《git中文入门教学视频1》 《git中文入门教学视频2》
《git-flow 备忘清单》《Git工作流》《Git 使用规范流程》
《Git思维导图》《msysGit思维导图》
《托管项目到GitHub》《上传本地项目到github》
《如何高效利用GitHub》《Git的深入理解与GitHub托管服务的使用》