git版本控制

之前梳理介绍过subversion版本控制,本文承接《Mac下git通过SSH进行免密码安全连接github》,基于一个初级的git版本控制流程贯串示例讲解git日常操作,备忘查阅。

git版本控制_第1张图片

git版本控制_第2张图片

Mac/Xcode git

whereis git

在Mac 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 versiongit --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

upgrade git

可从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
  • 可在bash下运行 setup git PATH for non-terminal programs.sh 脚本设置新版 git 为非命令行程序的默认 git。
  • 可参照Mac下升级subversion工具包升级方法,直接软链新版binUtils的 git* 到/Applications/Xcode.app/Contents/Developer/usr/bin下即可。

git manual

  1. 输入 gitgit --help 可以查看git usage,一览most commonly used git commands要义:
  2. 针对具体commands,可以求助“男人”(man),以下示例查看git add帮助的两种方式:
➜  ~  git --help add(git help add

➜  ~  man git add

按下Q键退出manual。

git config

git配置分为系统级别、用户级别和项目级别,--global选项指定用户级别的配置。

➜  ~  git config --global user.name fan2
➜  ~  git config --global user.email xxx@qq.com

配置完成后,可以输入git config --list命令查看当前配置。
后面该用户的 git 提交信息中将自动嵌入用户信息,即git log查看到的每条log的Author信息。
也可针对具体项目(cd到 .git 所在目录)执行git config命令,而无需指定--system--global选项,配置适用于独立项目的作者信息或代理信息(http.proxy)。

git init

cd进入本地项目目录

➜  ~  cd Projects/Xcode/resizableImageWithCapInsets

查看当前目录:

➜  ~  pwd
/Users/faner/Projects/Xcode/resizableImageWithCapInsets

当前目录为空文件夹,lsls -a列举无内容。

查看当前项目(目录)的git状态

使用 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版本库,需要使用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等远程仓库克隆项目到本地,则默认即是一个追踪了远程仓库的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操作都是基于当前工作目录,即包含 .gitWorking directory/Working Tree

git add to Index

创建第一个文件——README.md

1.执行touch README.md命令新建README.md文件:

resizableImageWithCapInsets git:(master) touch README.mdresizableImageWithCapInsets git:(master)ls
README.md

2.执行vi README.md打开vi进行编辑

resizableImageWithCapInsets git:(master)vi README.md  
  • i: insert模式编辑;
  • esc: 退出insert编辑模式;
  • :wq: 保存退出

3.编辑完成执行cat README.md,可查看文件内容:

➜  resizableImageWithCapInsets git:(master) ✗ cat README.md  
README for resizableImageWithCapInsets.  

4.再次执行git status命令可查看当前本地仓库状态:

➜  resizableImageWithCapInsets git:(master) ✗ git status  
On branch master  

Initial commit  

Untracked files:  
  (use "git add <file>..." 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)。

将README.md文件添加到git index

添加本地文件到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的概念
index 有时候也被称作Staging areaCachegit add命令会将文件改动暂存到 index 中(.git/index)。
git版本控制_第3张图片

基本用法:git add <pathspec>

  • <pathspec>可以是.,表示添加当前目录下所有(as a whole)未追踪的文件或修改(unversioned/untracked files or modification)到git索引。
  • 也可以添加指定子目录层级的单个文件或多个文件列表(only part)。

添加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 <file>..." 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 commit to local repository

将暂存区中的变更提交到到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本地仓库

git本地仓库由 git 维护的三棵“树”组成:

  • 第一个是 物理工作目录(Working tree),它持有实际文件;
  • 第二个是 暂存区(Index),它像个缓存区域,临时保存你的改动;
  • 最后是 repository ,HEAD 指向你最后一次提交(commit)的结果。

git版本控制_第4张图片

git add modificaion / rm tracked file

修改文件

将 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 @@  
&nbsp;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 <file>..." to update what will be committed)
  (use "git checkout -- <file>..." 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 checkout – :放弃本地修改,恢复到上次commit完的”干净”版本Index中的文件记录。
  • git add :提交更新到缓存。

若执行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 <file>..." 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 <file>撤销提交到暂存中的修改:
➜  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 <file>..." to unstage)  

    deleted:    README.md  

可执行git reset HEAD <file>撤销提交到暂存中的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 push ( merge local to remote )

前面我们本地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

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 git@github.com: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  git@github.com:fan2/resizableImageWithCapInsets.git (fetch)  
origin  git@github.com: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推送更新到它所追踪的远程仓库

我们前面使用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.<name>.merge in git-config(1).

执行以下命令可以将本地仓库变更提交(合并)到它所追踪的远程仓库origin的master分支:

resizableImageWithCapInsets git:(master)git push -u origin master  

git rebase from remote ( pull = fetch + merge)

当本地仓库跟踪的远程仓库发生变更时,需要rebase(merge from remote to local)。

fetch + merge

  • 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命令查看当前分支。

pull

当我们在本地修改了文件准备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托管服务的使用》

你可能感兴趣的:(git,remove,push,commit,add)