如何使用Git?(关于本地、远程仓库、分支详解)

  • Git是分布式版本控制系统,客户端是把代码仓库完整地镜像下来。
  • Git中的文件的三种状态:已修改已暂存(对一个已修改文件的当前版本做标记,让它包含在下次快照中)、已提交(完成了一次快照)。这也对应了三个阶段:工作目录、暂存区域、Git仓库。

本地Git仓库

  • 两种获取Git仓库的方式
    1、将尚未进行版本控制的本地目录转化为Git仓库;首先cd进项目目录,然后git init初始化一个仓库,该命令创建了一个名为.git的子目录,这个子目录含有初始化的Git仓库中所有的必须文件。但是,此时项目里的文件还没有被跟踪?:通过git add <filename>来指定所需的文件进行追踪,然后执行git commit进行快照。
    2、从服务器上clone一个已存在的Git仓库:git clone <url>,如果想自定义本地仓库的名字,可以在这行命令后加一个新名字作为参数: git clone <url> <filename>

  • 文件的状态:在之前说到Git文件有三种状态,但这个前提是这个文件已被Git跟踪/已经纳入Git版本控制(Git知道这个文件)。在我们刚刚clone了一个仓库后,所有文件都是被跟踪的。我们可以使用git status来查看文件的状态。
    1、如果我们新添加了一个文件到仓库里,它的状态是 untracked,这时候我们需要用git add <filename>去跟踪这个文件。
    在这里插入图片描述
    2、如果我们新修改了一个被跟踪的文件,它的状态是unstaged,我们仍然是用git add <filename> 暂存这次更新。这次add的意义是将内容添加到下一次提交中。
    3、提交更新: git commit(每次提交更新前最好用git status查看下文件的状态),然后会启动文本编辑器来输入提交说明。当然也可以在commit后加-m,将提交信息与命令放在同一行(如下图所示)。任何一次提交都是对项目做了一次快照,以后可以回到这个状态,或者进行比较。使用git commit -a会自动把所有已经跟踪过的文件暂存起来一起提交,跳过git add
    在这里插入图片描述

  • 查看提交历史: git log,此操作会按时间先后列出所有提交。

  • 撤销操作

远程仓库

  • 查看远程仓库有哪些: git remote ,如果已经clone了自己的仓库,那么至少能看到origin(这是Git给clone的仓库服务器的默认名字),加上参数-v,可以显示独写远程仓库使用的Git保存的简写与其对应的URL。

  • 添加远程仓库git remote add <shortname> <url>,添加一个新的远程Git仓库,同时指定一个方便的简写,所以就可以用这个简写来代替URL。

  • 获取远程仓库的信息git fetch <remote>, 执行完后,会拥有那个远程仓库中所有分支的引用,可以随时合并和查看。fetch只是将数据下载到本地仓库-----并不会自动合并或者修改当前的工作。

  • 推送到远程仓库git push <remote> <branch>,将本地某个分支推送。分享项目的时候必须将其推送到上游。但是命令生效需要两个条件
    1、你拥有所克隆服务器的写入权限。
    2、之前没有人推送过。当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先抓取他们的工作并将其合并进你的工作后才能推送

  • 查看远程仓库的详细信息git remote show <remote> ,它会列出远程仓库的跟踪分支信息,并且说明git pull后会产生哪些效果,最后还会列出拉取到的所有远程引用。

  • 远程仓库的重命名与移除git remote rename <original name> <newname>git remote remove <remote>

分支

  • 分支简介:每次提交,Git会保存一个提交对象,该对象包括一个指向暂存内容快照的指针,文件快照由三个blob对象保存,并有一个树对象保存blob对象索引,所以最后提交对象里保存指向树的指针就好了。最后,提交对象里包含了树的指针,作者信息、提交信息、指向父对象的指针Git分支本质仅仅是指向提交对象的可变指针。
    在这里插入图片描述
    在这里插入图片描述
  • 分支创建git branch <branchname>,它只是创建了一个可以移动的指针。Git通过一个名为HEAD的特殊指针得知目前在哪一个分支上。可以通过git log查看各个分支当前所指的对象
$ git log --oneline --decorate
f30ab (HEAD -> master, testing) add feature #32 - ability to add new formats to the central interface
34ac2 Fixed bug #1328 - stack overflow under certain conditions
98ca9 The initial commit of my project

在这里插入图片描述

  • 分支切换:git checkout ,其实就是改变HEAD指针指向的那个分支。当切换分支之后:1、使HEAD指向指定的分支;2、工作目录恢复成那个分支所指向的快照内容(即最后一个提交的样子)。
  • 查看分查历史:
$ git log --oneline --decorate --graph --all
 - c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
 - f30ab add feature #32 - ability to add new formats to the
 - 34ac2 fixed bug #1328 - stack overflow under certain conditions
 - 98ca9 initial commit of my project

在这里插入图片描述

  • 合并分支: 先将HEAD指向目标分支git checkout master,再选择合并到目前分支的那个分支:git merge <targetbranch>
    1、此时,如果想要合并的分支targetBranch所指向的提交是你分支master指向的提交的直接后继,那么Git会直接将master这个指针向后移动。—这个过程就叫快进(fast-forward)
    在这里插入图片描述
    2、如果开发历史从一个更早的地方开始分叉开来,Git会使用两个分支的末端所指的快照以及两个分支的公共祖先,做一个三方合并,并做了一个新的快照,自动创建一个新的提交指向它,它有不止一个父提交。
    在这里插入图片描述
    3、此时,这个iss53分支已被合并,就可以被删除了: git branch -d <branchname>

  • 分支管理: 直接用git branch可以得到所有分支的一个列表,前面带 * 的代表现在检出的一个分支;如果需要查看每一个分支的最后一次提交,可以运行git branch -v;在git branch后面加上--merged--no-merged可以过滤这个列表中已经合并或尚未合并到当前分支的分支。当使用–merged时,出来的没带 * 的分支就可以剪掉了,因为它已经合并到了当前分支。

  • 远程分支: 远程引用是对远程仓库的引用,包括分支、标签等。

  • 远程跟踪分支: 远程跟踪分支是远程分支状态的引用。它们是你无法移动的本地引用。一旦你进行了网络通信, Git 就会为你移动它们以精确反映远程仓库的状态。请将它们看做书签, 这样可以提醒你该分支在远程仓库中的位置就是你最后一次连接到它们的位置
    它们以 <remote>/<branch> 的形式命名。
    假设你的网络里有一个在 git.ourcompany.com 的 Git 服务器。 如果你从这里克隆,Git 的 clone 命令会为你自动将其命名为 origin,拉取它的所有数据, 创建一个指向它的 master 分支的指针,并且在本地将其命名为 origin/master。 Git 也会给你一个与 originmaster 分支在指向同一个地方的本地 master 分支,这样你就有工作的基础。
    在这里插入图片描述
    只要保持不与origin服务器连接并拉取数据,那么这个origin/master指针就不会移动。
    如果想要与远程仓库同步数据,运行git fetch <remote>,这样origin/master指针就会移动到更新之后的位置。
    在这里插入图片描述

  • 推送: 当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。 本地的分支并不会自动与远程仓库同步——你必须显式地推送想要分享的分支。1、假如想要推送到的远程仓库的分支(即使未被创建)和本地的分支名字一样,运行git push <remote> <branch>。2、假如分支名字不一样,可以通过运行git push <remote> <localBranchName>:<remoteBranchName>指定名字,将本地的<localBranchName>分支推送到远程仓库(必须要有写入权限)上的<remoteBranchName>分支。3、如果目前检出的分支已经设置了上游分支,直接git push

  • 下一次其他协作者从服务器上fetch的时候,他们会在本地生成一个远程分支origin/abc,指向服务器的abc分支的引用。要注意:抓取到新的远程跟踪分支后,本地不会自动生成一份可编辑的副本。也就是说,本地不会有一个新的abc分支,只有一个不可以修改的origin/abc指针。现在有两种方案可以获得刚刚fetch的新分支:
    1、直接合并,将这个分支合并到本地仓库的某个分支:先git checkout <localBranch>,再git merge origin/abc
    2、重新创立一个本地分支(这个名字可以自己取),起点位于origin/abcgit checkout -b <branch> <romote>/<branch>

$ git checkout -b abc origin/abc
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
  • 跟踪分支:从一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”(它跟踪的分支叫做“上游分支”)。 跟踪分支是与远程分支有直接关系的本地分支。 如果在一个跟踪分支上输入 git pull,Git 能自动地识别去哪个服务器上抓取、合并到哪个分支。(git pull不要乱用)
    当克隆一个仓库时,它通常会自动地创建一个跟踪 origin/mastermaster 分支。
    设置一个已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者想要修改正在跟踪的上游分支, 你可以在任意时间使用 -u 或 --set-upstream-to 选项运行 git branch 来显式地设置:
    ( 但是这个远程(上游)分支必须是已经存在的)
$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
  • 如果远程仓库不存在对应的上游分支,可以直接先切到那个想push的本地分支,然后git push -u origin <remotebranch>,但是这个操作会直接push。如果只想设置一个上游跟踪分支:git push --set-upstream origin <remotebranch>
  • 如果想要查看设置的所有跟踪分支,可以使用git branch-vv选项。这会将本地分支列出来,并且包含每一个分支正在跟踪哪一个远程分支、本地分支落后或领先:
$ git branch -vv
  iss53     7e424c3 [origin/iss53: ahead 2] forgot the brackets
  master    1ae2a45 [origin/master] deploying index fix
 * serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
  testing   5ea463a trying something new
  • 这些数字的值来自于从每个服务器最后一次抓取的数据。这个命令并没有连接服务器,它只会告诉你关于本地缓存的服务器数据。
    如果想要统计最新的领先与落后数字,需要在运行此命令前抓取所有的远程仓库。 可以像这样做:
$ git fetch --all; git branch -vv
  • 拉取: git pull = git fetch + git mergegit pull会查找当前分支所跟踪的服务器与分支,从服务器上抓取数据然后尝试合并那个远程分支。(git pull最好不好乱用,单独地显式使用fetchmerge会更好)

  • 删除远程分支: 假设你已经通过远程分支做完所有的工作了——也就是说你和你的协作者已经完成了一个特性, 并且将其合并到了远程仓库的 master 分支(或任何其他稳定代码分支)。 可以运行带有 --delete 选项的 git push 命令来删除一个远程分支(基本上这个命令做的只是从服务器上移除这个指针):

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 * [deleted]         serverfix
  • 变基(rebase): rebase是除了merge外另一种整合来自不同分支地修改方式。merge是这样的:
    在这里插入图片描述
    而rebase是将提交到某一个分支的所有修改都移至另一分支(原理:首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。)但是,merge和rebase整合方式最终结果没有任何区别,但是rebase会使得提交历式更加整洁。
    在这里插入图片描述
    先检出experiment分支,然后将其换基到master分支上,相当于C4被放弃,然后我们回到master分支,进行一次fast-forward合并:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
$ git checkout master
$ git merge experiment
  • 变基的风险: 变基的操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交(提交时间、哈希值等等都不同)。如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase 命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。
    一开始远程仓库和本地仓库是这样:
    在这里插入图片描述
    某人又提交了一些修改(包括一个合并),你抓取了这些在远程分支上的修改,并将其合并到你本地的开发分支,然后你的提交历史就会变成这样:
    在这里插入图片描述
    接下来,这个人又决定把合并操作回滚,改用变基;继而又用 git push --force 命令覆盖了服务器上的提交历史。 之后你从服务器抓取更新,会发现多出来一些新的提交:
    在这里插入图片描述
    如果你执行 git pull 命令,你将合并来自两条提交历史的内容,生成一个新的合并提交,最终仓库会如图所示:
    在这里插入图片描述
    此时如果你执行 git log 命令,你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。 此外,如果你将这一堆又推送到服务器上,你实际上是将那些已经被变基抛弃的提交又找了回来,这会令人感到更加混乱。 很明显对方并不想在提交历史中看到 C4 和 C6,因为之前就是他把这两个提交通过变基丢弃的。
  • rebase VS merge: 总的原则是,只对尚未推送或分享给别人的本地修改值行变基操作清理历史,从不对已推送至别处的提交值行rebase(否则会出现上面的问题)。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值