公司的 SEO与网站建设,电子商务网站开发工具,淘宝怎么做引流和推广,电商网站的功能#x1f384;欢迎来到边境矢梦的csdn博文#x1f384; #x1f384;本文主要梳理在git和GitHub时的笔记与感言 #x1f384; #x1f308;我是边境矢梦#xff0c;一个正在为秋招和算法竞赛做准备的学生#x1f308; #x1f386;喜欢的朋友可以关注一下#x1faf0;欢迎来到边境矢梦°的csdn博文 本文主要梳理在git和GitHub时的笔记与感言 我是边境矢梦°一个正在为秋招和算法竞赛做准备的学生 喜欢的朋友可以关注一下下次更新不迷路 Ps: 月亮越亮说明知识点越重要 (重要性或者难度越大) 目录 git是分布式版本控制软件
注意点
git的优点
安装git
✨创建版本库/仓库
⚙️配置 创建本地空版本库/仓库
文本文件的提交
新建文件添加到本地仓库
改写提交
查看历史提交日志
时光回溯机
版本回退 工作区与缓存区
管理修改
撤销修改
删除文件
远程仓库
github的使用
将本地仓库关联到远程仓库
从远程库克隆
分支管理 ️创建与合并分支
️解决冲突
️分支管理策略
️Bug分支
️Feature分支
️多人协作
️Rebase
️标签管理
创建标签
操作标签
git总结
文件状态 学习廖雪峰的官方网站的学习笔记 git是分布式版本控制软件 分布式版本控制软件自动帮我记录每次文件的改动还可以让同事协作编辑这样就不用自己管理一堆类似的文件了也不需要把文件传来传去。如果想查看某次改动只需要在软件里瞄一眼就可以岂不是很方便 分布式的区别在于每个人的电脑都是服务器当你从主仓库拉取一份代码下来后你的电脑就是服务器无需担心主仓库被删或者找不到的情况你可以自由在本地回滚提交当你想把自己的代码提交到主仓库时只需要合并推送到主仓库就可以了同时你可以把自己的代码新建一份仓库分享给其它人。
像集中式它们都有一个主版本号所有的版本迭代都以这个版本号为主而分布式因为每个客户端都是服务器git没有固定的版本号但是有一个由哈希算法算出的id用来回滚用的同时也有一个master仓库这个仓库是一切分支仓库的主仓库我们可以推送提交到master并合并到主仓库上主仓库的版本号会迭代一次我们客户端上的git版本号无论迭代多少次都跟master无关只有合并时master才会迭代一次。
注意点
首先这里再明确一下所有的版本控制系统其实只能跟踪文本文件的改动比如TXT文件网页所有的程序代码等等Git也不例外。版本控制系统可以告诉你每次的改动比如在第5行加了一个单词“Linux”在第8行删了一个单词“Windows”。而图片、视频这些二进制文件虽然也能由版本控制系统管理但没法跟踪文件的变化只能把二进制文件每次改动串起来也就是只知道图片从100KB改成了120KB但到底改了啥版本控制系统不知道也没法知道。
不幸的是Microsoft的Word格式是二进制格式因此版本控制系统是没法跟踪Word文件的改动的前面我们举的例子只是为了演示如果要真正使用版本控制系统就要以纯文本方式编写文件。
因为文本是有编码的比如中文有常用的GBK编码日文有Shift_JIS编码如果没有历史遗留问题强烈建议使用标准的UTF-8编码所有语言使用同一种编码既没有冲突又被所有平台所支持。 使用Windows的童鞋要特别注意 千万不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件他们自作聪明地在每个文件开头添加了0xefbbbf十六进制的字符你会遇到很多不可思议的问题比如网页第一行可能会显示一个“?”明明正确的程序一编译就报语法错误等等都是由记事本的弱智行为带来的。建议你下载Visual Studio Code代替记事本不但功能强大而且免费 git的优点 离线工作能力在分布式系统中每个开发者都有完整的代码仓库副本这使得他们可以在没有网络连接的情况下继续工作。这意味着你可以在飞机上、火车上或任何没有网络的地方进行编码和版本控制。 灵活的分支和合并分布式系统使得分支和合并操作变得非常容易和灵活。开发者可以轻松地创建新分支进行实验然后将更改合并回主分支而不会对其他人的工作产生影响。这促进了更高效的协作和并行开发。 去中心化分布式系统中没有单一的中央服务器这意味着没有单一的故障点。即使某个仓库出现问题你仍然可以从其他开发者的仓库中恢复。这增加了数据的安全性和可靠性。 强大的分布式协作分布式系统使得协作跨越不同地理位置的开发者变得更容易。开发者可以克隆仓库进行本地开发然后将更改推送回远程仓库这使得全球分布的开发团队协作更加便捷。 更快的性能由于每个开发者都可以在本地执行版本控制操作分布式系统通常可以提供更快的性能因为不需要频繁地与中央服务器通信。
安装git
在Windows上安装Git
在Windows上使用Git可以从Git官网直接下载安装程序然后按默认选项安装即可。
安装完成后在开始菜单里找到“Git”-“Git Bash”蹦出一个类似命令行窗口的东西就说明Git安装成功 ✨创建版本库/仓库
⚙️配置
参数讲解 config参数是用来配置git环境的 --global长命令表示配置整个git环境 初次使用git需要设置你的用户名以及邮箱这将作为当前机器git的标识如果你用它来下载远程仓库一些需要登录权限的仓库会要求登录git默认使用配置邮箱以及用户名登入但会要求你手动输入密码
1. 用户名配置 user代表用户.name代表配置用户的名称 git config --global user.name 你的用户名
2. 邮箱配置 user代表用户.email代表配置用户的邮箱 git config --global user.email 你的邮箱 创建本地空版本库/仓库
什么是版本库呢版本库又名仓库英文名repository你可以简单理解成一个目录这个目录里面的所有文件都可以被Git管理起来每个文件的修改、删除Git都能跟踪以便任何时刻都可以追踪历史或者在将来某个时刻可以“还原”。 创建本地仓库的条件是需要一个空目录然后在空目录中初始化你的项目 初始化后会生成git的配置文件目录普通的ls命令是看不到的我们需要使用ls -ah查看隐藏目录
也不一定必须在空目录下创建Git仓库选择一个已经有东西的目录也是可以的。不过不建议你使用自己正在开发的公司项目来学习Git否则造成的一切后果概不负责。
文本文件的提交
新建文件添加到本地仓库
新建一个文件到刚才新的版本库 add将文件添加到缓存区 commit提交到本地仓库 第一步用命令git add告诉Git把文件添加到仓库
$ git add readme.txt执行上面的命令没有任何显示这就对了Unix的哲学是“没有消息就是好消息”说明添加成功。
第二步用命令git commit告诉Git把文件提交到仓库
$ git commit -m wrote a readme file
[master (root-commit) eaadf4e] wrote a readme file1 file changed, 2 insertions()create mode 100644 readme.txt
简单解释一下git commit命令-m后面输入的是本次提交的说明可以输入任意内容当然最好是有意义的这样你就能从历史记录里方便地找到改动记录。
git commit 会为我们生成40位的哈希值用于作为id并把刚刚用git add添加到提交缓存区里的文件提交到本地仓库中便于我们回滚至此这个文件就已经添加到本地仓库中了同时本地仓库也迭代了一个版本。(往后看会慢慢理解)
改写提交 --amend重写上一次的提交信息 就像刚刚的列子里一样我们提交了仓库但是发现注释写错了我们可以使用 --amend长命令选项来改写提交
git commit --amend 查看历史提交日志 log查看日志 正如刚刚改写提交的想要确定是否改写成功我们可以使用git log查看一下
git log commit 41198acbdeb241bbedfa8792eb090d97cf1d1a80 (HEAD - main)
Author: luoxiongbo 3160821850qq.com
Date: Thu Sep 14 19:01:20 2023 0800test\test.txt\
这里来解释一下上面提交的信息是什么意思
第一行的commit是哈希算法算出的id正如一开始所说分布式是没有一个主版本号的它们都是用id来做标志的同时用master作为主仓库其它的分支怎么迭代都不会影响到master后面我会介绍如何使用分支
目前我们的仓库就是master因为我们没有拉取分支是直接用git init创建的就是master。
后面的head是指向的意思表示这次提交到哪儿head-master代表这次提交到master主仓库如果是head-分支仓库则代表提交到分支仓库
Author是提交者是谁的意思显示格式是用户名 邮箱
Date的意思是提交时间后面的0800这个是格林尼治时间代表当前是以哪儿的时间地作为基准这是世界时间用它来作为基数与当前所在地时差进行计算包括地球自转等公式。
最下面的就是注释了
如果嫌输出信息太多看得眼花缭乱的可以试试加上--prettyoneline参数
$ git log --prettyoneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD - master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file 时光回溯机
版本回退
执行git log
git log
$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD - master)
Author: Michael Liao askxuefenggmail.com
Date: Fri May 18 21:06:15 2018 0800append GPLcommit e475afc93c209a690c39c13a46716e8fa000c366
Author: Michael Liao askxuefenggmail.com
Date: Fri May 18 21:03:36 2018 0800add distributedcommit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao askxuefenggmail.com
Date: Fri May 18 20:59:18 2018 0800wrote a readme file
git log命令显示从最近到最远的提交日志我们可以看到3次提交最近的一次是append GPL上一次是add distributed最早的一次是wrote a readme file。
如果要进行版本回退
首先Git必须知道当前版本是哪个版本在Git中用HEAD表示当前版本也就是最新的提交1094adb...注意我的提交ID和你的肯定不一样上一个版本就是HEAD^上上一个版本就是HEAD^^当然往上100个版本写100个^比较容易数不过来所以写成HEAD~100。
现在我们要把当前版本append GPL回退到上一个版本add distributed就可以使用git reset命令
$ git reset --hard HEAD^
HEAD is now at e475afc add distributed reset参数是重置命令 --hard是重置代码仓库版本 看看readme.txt的内容是不是版本add distributed
$ cat readme.txt
Git is a distributed version control system.
Git is free software.果然被还原了。
还可以继续回退到上一个版本wrote a readme file不过且慢让我们用git log再看看现在版本库的状态
$ git log
commit e475afc93c209a690c39c13a46716e8fa000c366 (HEAD - master)
Author: Michael Liao askxuefenggmail.com
Date: Fri May 18 21:03:36 2018 0800add distributedcommit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao askxuefenggmail.com
Date: Fri May 18 20:59:18 2018 0800wrote a readme file最新的那个版本append GPL已经看不到了
如果你想重做的话
只要上面的命令行窗口还没有被关掉你就可以顺着往上找啊找啊找到那个append GPL的commit id是1094adb...于是就可以指定回到未来的某个版本
$ git reset --hard 1094a
HEAD is now at 83b0afe append GPL版本号没必要写全前几位就可以了Git会自动去找。当然也不能只写前一两位因为Git可能会找到多个版本号就无法确定是哪一个了。
再小心翼翼地看看readme.txt的内容
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.果然又回来了。
Git的版本回退速度非常快因为Git在内部有个指向当前版本的HEAD指针当你回退版本的时候Git仅仅是把HEAD从指向append GPL
┌────┐
│HEAD│
└────┘│└──▶ ○ append GPL│○ add distributed│○ wrote a readme file改为指向add distributed
┌────┐
│HEAD│
└────┘││ ○ append GPL│ │└──▶ ○ add distributed│○ wrote a readme file然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号你就把当前版本定位在哪。
现在你回退到了某个版本关掉了电脑第二天早上就后悔了想恢复到新版本怎么办找不到新版本的commit id怎么办
在Git中总是有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到add distributed版本时再想恢复到append GPL就必须找到append GPL的commit id。Git提供了一个命令git reflog用来记录你的每一次命令
$ git reflog
e475afc HEAD{1}: reset: moving to HEAD^
1094adb (HEAD - master) HEAD{2}: commit: append GPL
e475afc HEAD{3}: commit: add distributed
eaadf4e HEAD{4}: commit (initial): wrote a readme file终于舒了口气从输出可知append GPL的commit id是1094adb现在你又可以回到未来了。 工作区与缓存区
在git下有一个概念是缓存区这是其它集中式版本控制系统没有的
工作区工作区就是你当前的工作目录
缓存区这里存放了你使用git add命令提交的文件描述信息它位于.git目录下的index文件中, 这些文件中存储了我们一些提交的缓存数据git会解析它们HEAD文件就是指向当前的仓库
最后使用git commit提交时git会提交到当前仓库中当前的工作区也就成为了最新一次提交的仓库版本。 工作区有一个隐藏目录.git这个不算工作区而是Git的版本库。 Git的版本库里存了很多东西其中最重要的就是称为stage或者叫index的暂存区还有Git为我们自动创建的第一个分支master以及指向master的一个指针叫HEAD。 图片来自 : 工作区和暂存区 - 廖雪峰的官方网站 (liaoxuefeng.com)
分支和HEAD的概念我们以后再讲。
前面讲了我们把文件往Git版本库里添加的时候是分两步执行的
第一步是用git add把文件添加进去实际上就是把文件修改添加到暂存区
第二步是用git commit提交更改实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时Git自动为我们创建了唯一一个master分支所以现在git commit就是往master分支上提交更改。
你可以简单理解为需要提交的文件修改通通放到暂存区然后一次性提交暂存区的所有修改。
俗话说实践出真知。现在我们再练习一遍先对readme.txt做个修改比如加上一行内容
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.然后在工作区新增一个LICENSE文本文件内容随便写。
先用git status查看一下状态 status查看当前仓库状态 我们在提交完成之后有时候可能自己不小心改动了某个文件或者别人我们可以使用git status查看文件是否被改动 $ 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: readme.txtUntracked files:(use git add file... to include in what will be committed)LICENSEno changes added to commit (use git add and/or git commit -a)Git非常清楚地告诉我们readme.txt被修改了而LICENSE还从来没有被添加过所以它的状态是Untracked。
现在使用两次命令git add把readme.txt和LICENSE都添加后用git status再查看一下
$ git status
On branch master
Changes to be committed:(use git reset HEAD file... to unstage)new file: LICENSEmodified: readme.txt现在暂存区的状态就变成这样了 所以git add命令实际上就是把要提交的所有修改放到暂存区Stage然后执行git commit就可以一次性把暂存区的所有修改提交到分支。
$ git commit -m understand how stage works
[master e43a48b] understand how stage works2 files changed, 2 insertions()create mode 100644 LICENSE一旦提交后如果你又没有对工作区做任何修改那么工作区就是“干净”的
$ git status
On branch master
nothing to commit, working tree clean 现在版本库变成了这样暂存区就没有任何内容了 管理修改
什么是修改比如你新增了一行这就是一个修改删除了一行也是一个修改更改了某些字符也是一个修改删了一些又加了一些也是一个修改甚至创建一个新文件也算一个修改。
为什么说Git管理的是修改而不是文件呢我们还是做实验。第一步对readme.txt做一个修改比如加一行内容
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.然后添加
$ git add readme.txt
$ git status
# On branch master
# Changes to be committed:
# (use git reset HEAD file... to unstage)
#
# modified: readme.txt
#然后再修改readme.txt
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.提交
$ git commit -m git tracks changes
[master 519219b] git tracks changes1 file changed, 1 insertion()提交后再看看状态
$ 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: readme.txtno changes added to commit (use git add and/or git commit -a)咦怎么第二次的修改没有被提交
别激动我们回顾一下操作过程
第一次修改 - git add - 第二次修改 - git commit
你看我们前面讲了Git管理的是修改当你用git add命令后在工作区的第一次修改被放入暂存区准备提交但是在工作区的第二次修改并没有放入暂存区所以git commit只负责把暂存区的修改提交了也就是第一次的修改被提交了第二次的修改不会被提交。
提交后用git diff HEAD -- readme.txt命令可以查看工作区和版本库里面最新版本的区别
$ git diff HEAD -- readme.txt
diff --git a/readme.txt b/readme.txt
index 76d770f..a9c5755 100644
--- a/readme.txtb/readme.txt-1,4 1,4 Git is a distributed version control system.Git is free software distributed under the GPL.Git has a mutable index called stage.
-Git tracks changes.
Git tracks changes of files.可见第二次修改确实没有被提交。
那怎么提交第二次修改呢你可以继续git add再git commit也可以别着急提交第一次修改先git add第二次修改再git commit就相当于把两次修改合并后一块提交了
第一次修改 - git add - 第二次修改 - git add - git commit
好现在把第二次修改提交了
撤销修改 查看readme.txt文件
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
My stupid boss still prefers SVN.发现了错误可以很容易地纠正它。你可以删掉最后一行手动把文件恢复到上一个版本的状态。如果用git status查看一下
$ 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: readme.txtno changes added to commit (use git add and/or git commit -a)你可以发现Git会告诉你git checkout -- file可以丢弃工作区的修改
$ git checkout -- readme.txt命令git checkout -- readme.txt意思就是把readme.txt文件在工作区的修改全部撤销这里有两种情况
一种是readme.txt自修改后还没有被放到暂存区现在撤销修改就回到和版本库一模一样的状态(清空工作区回到和版本库一模一样的状态)
一种是readme.txt已经添加到暂存区后又作了修改现在撤销修改就回到添加到暂存区后的状态。
总之就是让这个文件回到最近一次git commit或git add时的状态。
现在看看readme.txt的文件内容
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
文件内容果然复原了。
git checkout -- file命令中的--很重要没有--就变成了“切换到另一个分支”的命令我们在后面的分支管理中会再次遇到git checkout命令。
现在假定是凌晨3点你不但写了一些胡话还git add到暂存区了
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
My stupid boss still prefers SVN.$ git add readme.txt庆幸的是在commit之前你发现了这个问题。用git status查看一下修改只是添加到了暂存区还没有提交
$ git status
On branch master
Changes to be committed:(use git reset HEAD file... to unstage)modified: readme.txtGit同样告诉我们用命令git reset HEAD file可以把暂存区的修改撤销掉unstage重新放回工作区
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txtgit reset命令既可以回退版本也可以把暂存区的修改回退到工作区。当我们用HEAD时表示最新的版本。
再用git status查看一下现在暂存区是干净的工作区有修改
$ 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: readme.txt还记得如何丢弃工作区的修改吗
$ git checkout -- readme.txt$ git status
On branch master
nothing to commit, working tree clean整个世界终于清静了
现在假设你不但改错了东西还从暂存区提交到了版本库怎么办呢还记得版本回退一节吗可以回退到上一个版本。不过这是有条件的就是你还没有把自己的本地版本库推送到远程。还记得Git是分布式版本控制系统吗我们后面会讲到远程版本库一旦你把stupid boss提交推送到远程版本库你就真的惨了……
查看单个文件可回滚版本git log filename
当我们想回滚指定文件到指定版本时需要查看该文件有多少个版本可以回滚时可以使用git log filename命令
git log test.txt git reset --hard HEAD 和 git reset --hard 41198acbdeb241bbedfa8792eb090d97cf1d1a80的区别是什么 git reset --hard HEAD 将分支重置到当前分支的最新提交取消未提交的更改。git reset --hard commit 将分支重置到指定的提交可能会丢弃一些提交历史。 删除文件
在Git中删除也是一个修改操作我们实战一下先添加一个新文件test.txt到Git并且提交
$ git add test.txt$ git commit -m add test.txt
[master b84166e] add test.txt1 file changed, 1 insertion()create mode 100644 test.txt一般情况下你通常直接在文件管理器中把没用的文件删了或者用rm命令删了
$ rm test.txt这个时候Git知道你删除了文件因此工作区和版本库就不一致了git status命令会立刻告诉你哪些文件被删除了
$ 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.txtno changes added to commit (use git add and/or git commit -a)现在你有两个选择一是确实要从版本库中删除该文件那就用命令git rm删掉并且git commit
$ git rm test.txt
rm test.txt$ git commit -m remove test.txt
[master d46f35e] remove test.txt1 file changed, 1 deletion(-)delete mode 100644 test.txt现在文件就从版本库中被删除了。 小提示先手动删除文件然后使用git addfile和git rm file效果是一样的。
另一种情况是删错了因为版本库里还有呢所以可以很轻松地把误删的文件恢复到最新版本
$ git checkout -- test.txtgit checkout其实是用版本库里的版本替换工作区的版本无论工作区是修改还是删除都可以“一键还原”。 注意从来没有被添加到版本库就被删除的文件是无法恢复的
查看提交历史git reflog
git reflog可以查看当前版本库的提交历史凡是对仓库版本进行迭代的都会出现在这个里面包括你回滚版本都会出现在这个历史中 git rm后恢复文件git rm、git reset、git checkout
git rm 必须在commit之后才能删除那个文件, 不然删除不了
此方法仅限git rm因为git rm会先将文件放入缓存区,且没有使用commit提交的情况下
首先使用git rm删除一个文件
git rm d.c
在使用git reset重置所有缓存区操作
git reset
重置完成之后在使用git checkout命令将文件取消操作
git checkout d.c 远程仓库
github的使用
github是一款使用git命令作为基础框架的网站它是一款开源分享网站你开源把你的源代码放到github上然后让人来start给你小星星小星星越多代表你的项目越具有影响力很多公司面试如果你有一个很多星星的项目会大大提升你的录取率。
你也可以把你的一些项目分享到github上保存github上是无限制代码的。
1.首先到github上注册一个你的账号
2.在本地创建一个ssh的key因为github是使用ssh服务进行通讯的
ssh-keygen -t rsa -C your_emailexample.com
-t 指定密钥类型默认是 rsa 可以省略。 -C 设置注释文字比如邮箱。 -f 指定密钥文件存储文件名一般我们默认让存储到默认路径以及默认文件名
它会要求输入Enter file in which to save the key (/home/stephenzhou/.ssh/id_rsa)
这里是生成的sshkey文件名我们可以回车使用默认文件名
然后根据具体信息输入密钥文件名和密码即可
然后将你生成的包复制到以下目录并给config文件配置信息 紧接着讲公钥放到GitHub中, 将.pub文件中的信息复制到下图中的key中 如果正常使用的话就是绿色的钥匙, 否则不然 你可以添加如很多个ssh比如你有多台电脑在每个电脑上都配置ssh然后添加进来就可以了git需要这个是要确定你是主人确定是主人的机器推送的才可以推送到仓库中但是你可以创建公开仓库别人只能拉取不能推送到这个仓库中你可以给其它人权限。
找到你要开放的仓库选择Manage access然后使用invite a cikkaborator添加成员就可以了。 将本地仓库关联到远程仓库
我们本地有一个仓库我们想把它推送到远程上去很简单我们只需要使用git remote add origin命令就可以了ongin是github上的仓库名称意思是远程仓库的意思。
首先选择仓库的code找到github生成的远程仓库链接 然后关联
git remote add origin gitgithub.com:beiszhihao/test.git
然后使用git push推送到远程
git push -u origin master
这里我来解释一下 push将本地仓库与远程仓库合并 -u将本地仓库分支与远程仓库分支一起合并就是说将master的分支也提交上去这样你就可以在远程仓库上看到你在本地仓库的master中创建了多少分支不加这个参数只将当前的master与远程的合并没有分支的历史记录也不能切换分支 origin远程仓库的意思如果这个仓库是远程的那么必须使用这个选项 master提交本地matser分支仓库 注意 : 从哪个分支提交的就对应到GitHub里的分支去查看才有相应的信息 从远程库克隆
上次我们讲了先有本地库后有远程库的时候如何关联远程库。
现在假设我们从零开发那么最好的方式是先创建远程库然后从远程库克隆。
首先登陆GitHub创建一个新的仓库名字叫gitskills 我们勾选Initialize this repository with a README这样GitHub会自动为我们创建一个README.md文件。创建完毕后可以看到README.md文件 现在远程库已经准备好了下一步是用命令git clone克隆一个本地库
$ git clone gitgithub.com:michaelliao/gitskills.git
Cloning into gitskills...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3
Receiving objects: 100% (3/3), done.注意把Git库的地址换成你自己的然后进入gitskills目录看看已经有README.md文件了
$ cd gitskills
$ ls
README.md
如果有多个人协作开发那么每个人各自从远程克隆一份就可以了。
你也许还注意到GitHub给出的地址不止一个还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上Git支持多种协议默认的git://使用ssh但也可以使用https等其他协议。
使用https除了速度慢以外还有个最大的麻烦是每次推送都必须输入口令但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
github提交本地仓库到远程仓库git add、git commit、git push 分支管理
分支就是科幻电影里面的平行宇宙当你正在电脑前努力学习Git的时候另一个你正在另一个平行宇宙里努力学习SVN。
如果两个平行宇宙互不干扰那对现在的你也没啥影响。不过在某个时间点两个平行宇宙合并了结果你既学会了Git又学会了SVN 分支在实际中有什么用呢假设你准备开发一个新功能但是需要两周才能完成第一周你写了50%的代码如果立刻提交由于代码还没写完不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交又存在丢失每天进度的巨大风险。
现在有了分支就不用怕了。你创建了一个属于你自己的分支别人看不到还继续在原来的分支上正常工作而你在自己的分支上干活想提交就提交直到开发完毕后再一次性合并到原来的分支上这样既安全又不影响别人工作。
其他版本控制系统如SVN等都有分支管理但是用过之后你会发现这些版本控制系统创建和切换分支比蜗牛还慢简直让人无法忍受结果分支功能成了摆设大家都不去用。
但Git的分支是与众不同的无论创建、切换和删除分支Git在1秒钟之内就能完成无论你的版本库是1个文件还是1万个文件。 ️创建与合并分支
在版本回退里你已经知道每次提交Git都把它们串成一条时间线这条时间线就是一个分支。截止到目前只有一条时间线在Git里这个分支叫主分支即master分支。HEAD严格来说不是指向提交而是指向mastermaster才是指向提交的所以HEAD指向的就是当前分支。
一开始的时候master分支是一条线Git用master指向最新的提交再用HEAD指向master就能确定当前分支以及当前分支的提交点 HEAD││▼master││▼
┌───┐ ┌───┐ ┌───┐
│ │───▶│ │───▶│ │
└───┘ └───┘ └───┘每次提交master分支都会向前移动一步这样随着你不断提交master分支的线也越来越长。
当我们创建新的分支例如dev时Git新建了一个指针叫dev指向master相同的提交再把HEAD指向dev就表示当前分支在dev上 master││▼
┌───┐ ┌───┐ ┌───┐
│ │───▶│ │───▶│ │
└───┘ └───┘ └───┘▲││dev▲││HEAD你看Git创建一个分支很快因为除了增加一个dev指针改改HEAD的指向工作区的文件都没有任何变化
不过从现在开始对工作区的修改和提交就是针对dev分支了比如新提交一次后dev指针往前移动一步而master指针不变 master││▼
┌───┐ ┌───┐ ┌───┐ ┌───┐
│ │───▶│ │───▶│ │───▶│ │
└───┘ └───┘ └───┘ └───┘▲││dev▲││HEAD假如我们在dev上的工作完成了就可以把dev合并到master上。Git怎么合并呢最简单的方法就是直接把master指向dev的当前提交就完成了合并 HEAD││▼master││▼
┌───┐ ┌───┐ ┌───┐ ┌───┐
│ │───▶│ │───▶│ │───▶│ │
└───┘ └───┘ └───┘ └───┘▲││dev所以Git合并分支也很快就改改指针工作区内容也不变
合并完分支后甚至可以删除dev分支。删除dev分支就是把dev指针给删掉删掉后我们就剩下了一条master分支 HEAD││▼master││▼
┌───┐ ┌───┐ ┌───┐ ┌───┐
│ │───▶│ │───▶│ │───▶│ │
└───┘ └───┘ └───┘ └───┘真是太神奇了你看得出来有些提交是通过分支完成的吗
下面开始实战。
首先我们创建dev分支然后切换到dev分支
$ git checkout -b dev
Switched to a new branch devgit checkout命令加上-b参数表示创建并切换相当于以下两条命令
$ git branch dev
$ git checkout dev
Switched to branch dev然后用git branch命令查看当前分支
$ git branch
* devmastergit branch命令会列出所有分支当前分支前面会标一个*号。
然后我们就可以在dev分支上正常提交比如对readme.txt做个修改加上一行
Creating a new branch is quick.然后提交
$ git add readme.txt
$ git commit -m branch test
[dev b17d20e] branch test1 file changed, 1 insertion()现在dev分支的工作完成我们就可以切换回master分支
$ git checkout master
Switched to branch master切换回master分支后再查看一个readme.txt文件刚才添加的内容不见了因为那个提交是在dev分支上而master分支此刻的提交点并没有变 现在我们把dev分支的工作成果合并到master分支上
$ git merge dev
Updating d46f35e..b17d20e
Fast-forwardreadme.txt | 1 1 file changed, 1 insertion()git merge命令用于合并指定分支到当前分支。合并后再查看readme.txt的内容就可以看到和dev分支的最新提交是完全一样的。
注意到上面的Fast-forward信息Git告诉我们这次合并是“快进模式”也就是直接把master指向dev的当前提交所以合并速度非常快。
当然也不是每次合并都能Fast-forward我们后面会讲其他方式的合并。
合并完成后就可以放心地删除dev分支了
$ git branch -d dev
Deleted branch dev (was b17d20e).删除后查看branch就只剩下master分支了
$ git branch
* master因为创建、合并和删除分支非常快所以Git鼓励你使用分支完成某个任务合并后再删掉分支这和直接在master分支上工作效果是一样的但过程更安全。
switch
我们注意到切换分支使用git checkout branch而前面讲过的撤销修改则是git checkout -- file同一个命令有两种作用确实有点令人迷惑。
实际上切换分支这个动作用switch更科学。因此最新版本的Git提供了新的git switch命令来切换分支
创建并切换到新的dev分支可以使用
$ git switch -c dev直接切换到已有的master分支可以使用
$ git switch master使用新的git switch命令比git checkout要更容易理解。
️解决冲突
人生不如意之事十之八九合并分支往往也不是一帆风顺的。
准备新的feature1分支继续我们的新分支开发
$ git switch -c feature1
Switched to a new branch feature1修改readme.txt最后一行改为
Creating a new branch is quick AND simple.在feature1分支上提交
$ git add readme.txt$ git commit -m AND simple
[feature1 14096d0] AND simple1 file changed, 1 insertion(), 1 deletion(-)切换到master分支
$ git switch master
Switched to branch master
Your branch is ahead of origin/master by 1 commit.(use git push to publish your local commits)Git还会自动提示我们当前master分支比远程的master分支要超前1个提交。
在master分支上把readme.txt文件的最后一行改为
Creating a new branch is quick simple.提交
$ git add readme.txt
$ git commit -m simple
[master 5dc6824] simple1 file changed, 1 insertion(), 1 deletion(-)现在master分支和feature1分支各自都分别有新的提交变成了这样 HEAD││▼master││▼┌───┐┌─▶│ │
┌───┐ ┌───┐ ┌───┐ │ └───┘
│ │───▶│ │───▶│ │──┤
└───┘ └───┘ └───┘ │ ┌───┐└─▶│ │└───┘▲││feature1这种情况下Git无法执行“快速合并”只能试图把各自的修改合并起来但这种合并就可能会有冲突我们试试看
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.果然冲突了Git告诉我们readme.txt文件存在冲突必须手动解决冲突后再提交。git status也可以告诉我们冲突的文件
$ git status
On branch master
Your branch is ahead of origin/master by 2 commits.(use git push to publish your local commits)You have unmerged paths.(fix conflicts and run git commit)(use git merge --abort to abort the merge)Unmerged paths:(use git add file... to mark resolution)both modified: readme.txtno changes added to commit (use git add and/or git commit -a)我们可以直接查看readme.txt的内容
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.HEAD
Creating a new branch is quick simple.Creating a new branch is quick AND simple.feature1Git用标记出不同分支的内容我们修改如下后保存
Creating a new branch is quick and simple.再提交
$ git add readme.txt
$ git commit -m conflict fixed
[master cf810e4] conflict fixed现在master分支和feature1分支变成了下图所示 HEAD││▼master││▼┌───┐ ┌───┐┌─▶│ │───▶│ │
┌───┐ ┌───┐ ┌───┐ │ └───┘ └───┘
│ │───▶│ │───▶│ │──┤ ▲
└───┘ └───┘ └───┘ │ ┌───┐ │└─▶│ │──────┘└───┘▲││feature1用带参数的git log也可以看到分支的合并情况
$ git log --graph --prettyoneline --abbrev-commit
* cf810e4 (HEAD - master) conflict fixed
|\
| * 14096d0 (feature1) AND simple
* | 5dc6824 simple
|/
* b17d20e branch test
* d46f35e (origin/master) remove test.txt
* b84166e add test.txt
* 519219b git tracks changes
* e43a48b understand how stage works
* 1094adb append GPL
* e475afc add distributed
* eaadf4e wrote a readme file最后删除feature1分支
$ git branch -d feature1
Deleted branch feature1 (was 14096d0).
️分支管理策略
通常合并分支时如果可能Git会用Fast forward模式但这种模式下删除分支后会丢掉分支信息。
如果要强制禁用Fast forward模式Git就会在merge时生成一个新的commit这样从分支历史上就可以看出分支信息。
下面我们实战一下--no-ff方式的git merge
首先仍然创建并切换dev分支
$ git switch -c dev
Switched to a new branch dev修改readme.txt文件并提交一个新的commit
$ git add readme.txt
$ git commit -m add merge
[dev f52c633] add merge1 file changed, 1 insertion()现在我们切换回master
$ git switch master
Switched to branch master准备合并dev分支请注意--no-ff参数表示禁用Fast forward
$ git merge --no-ff -m merge with no-ff dev
Merge made by the recursive strategy.readme.txt | 1 1 file changed, 1 insertion()因为本次合并要创建一个新的commit所以加上-m参数把commit描述写进去。
合并后我们用git log看看分支历史
$ git log --graph --prettyoneline --abbrev-commit
* e1e9c68 (HEAD - master) merge with no-ff
|\
| * f52c633 (dev) add merge
|/
* cf810e4 conflict fixed
...可以看到不使用Fast forward模式merge后就像这样 分支策略
在实际开发中我们应该按照几个基本原则进行分支管理
首先master分支应该是非常稳定的也就是仅用来发布新版本平时不能在上面干活
那在哪干活呢干活都在dev分支上也就是说dev分支是不稳定的到某个时候比如1.0版本发布时再把dev分支合并到master上在master分支发布1.0版本
你和你的小伙伴们每个人都在dev分支上干活每个人都有自己的分支时不时地往dev分支上合并就可以了。
所以团队合作的分支看起来就像这样 ️Bug分支
软件开发中bug就像家常便饭一样。有了bug就需要修复在Git中由于分支是如此的强大所以每个bug都可以通过一个新的临时分支来修复修复后合并分支然后将临时分支删除。
当你接到一个修复一个代号101的bug的任务时很自然地你想创建一个分支issue-101来修复它但是等等当前正在dev上进行的工作还没有提交
$ git status
On branch dev
Changes to be committed:(use git reset HEAD file... to unstage)new file: hello.pyChanges 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: readme.txt并不是你不想提交而是工作只进行到一半还没法提交预计完成还需1天时间。但是必须在两个小时内修复该bug怎么办
幸好Git还提供了一个stash功能可以把当前工作现场“储藏”起来等以后恢复现场后继续工作
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge现在用git status查看工作区就是干净的除非有没有被Git管理的文件因此可以放心地创建分支来修复bug。
首先确定要在哪个分支上修复bug假定需要在master分支上修复就从master创建临时分支
$ git checkout master
Switched to branch master
Your branch is ahead of origin/master by 6 commits.(use git push to publish your local commits)$ git checkout -b issue-101
Switched to a new branch issue-101现在修复bug需要把“Git is free software ...”改为“Git is a free software ...”然后提交
$ git add readme.txt
$ git commit -m fix bug 101
[issue-101 4c805e2] fix bug 1011 file changed, 1 insertion(), 1 deletion(-)修复完成后切换到master分支并完成合并最后删除issue-101分支
$ git switch master
Switched to branch master
Your branch is ahead of origin/master by 6 commits.(use git push to publish your local commits)$ git merge --no-ff -m merged bug fix 101 issue-101
Merge made by the recursive strategy.readme.txt | 2 -1 file changed, 1 insertion(), 1 deletion(-)太棒了原计划两个小时的bug修复只花了5分钟现在是时候接着回到dev分支干活了
$ git switch dev
Switched to branch dev$ git status
On branch dev
nothing to commit, working tree clean工作区是干净的刚才的工作现场存到哪去了用git stash list命令看看
$ git stash list
stash{0}: WIP on dev: f52c633 add merge工作现场还在Git把stash内容存在某个地方了但是需要恢复一下有两个办法
一是用git stash apply恢复但是恢复后stash内容并不删除你需要用git stash drop来删除
另一种方式是用git stash pop恢复的同时把stash内容也删了
$ git stash pop
On branch dev
Changes to be committed:(use git reset HEAD file... to unstage)new file: hello.pyChanges 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: readme.txtDropped refs/stash{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)再用git stash list查看就看不到任何stash内容了
$ git stash list你可以多次stash恢复的时候先用git stash list查看然后恢复指定的stash用命令
$ git stash apply stash{0} 在master分支上修复了bug后我们要想一想dev分支是早期从master分支分出来的所以这个bug其实在当前dev分支上也存在。
那怎么在dev分支上修复同样的bug重复操作一次提交不就行了
有木有更简单的方法
有
同样的bug要在dev上修复我们只需要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。注意我们只想复制4c805e2 fix bug 101这个提交所做的修改并不是把整个master分支merge过来。
为了方便操作Git专门提供了一个cherry-pick命令让我们能复制一个特定的提交到当前分支
$ git branch
* devmaster
$ git cherry-pick 4c805e2
[master 1d4b803] fix bug 1011 file changed, 1 insertion(), 1 deletion(-)Git自动给dev分支做了一次提交注意这次提交的commit是1d4b803它并不同于master的4c805e2因为这两个commit只是改动相同但确实是两个不同的commit。用git cherry-pick我们就不需要在dev分支上手动再把修bug的过程重复一遍。
有些聪明的童鞋会想了既然可以在master分支上修复bug后在dev分支上可以“重放”这个修复过程那么直接在dev分支上修复bug然后在master分支上“重放”行不行当然可以不过你仍然需要git stash命令保存现场才能从dev分支切换到master分支。
️Feature分支
软件开发中总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时你肯定不希望因为一些实验性质的代码把主分支搞乱了所以每添加一个新功能最好新建一个feature分支在上面开发完成后合并最后删除该feature分支。
现在你终于接到了一个新任务开发代号为Vulcan的新功能该功能计划用于下一代星际飞船。
于是准备开发
$ git switch -c feature-vulcan
Switched to a new branch feature-vulcan5分钟后开发完毕
$ git add vulcan.py$ git status
On branch feature-vulcan
Changes to be committed:(use git reset HEAD file... to unstage)new file: vulcan.py$ git commit -m add feature vulcan
[feature-vulcan 287773e] add feature vulcan1 file changed, 2 insertions()create mode 100644 vulcan.py切回dev准备合并
$ git switch dev一切顺利的话feature分支和bug分支是类似的合并然后删除。
但是
就在此时接到上级命令因经费不足新功能必须取消
虽然白干了但是这个包含机密资料的分支还是必须就地销毁
$ git branch -d feature-vulcan
error: The branch feature-vulcan is not fully merged.
If you are sure you want to delete it, run git branch -D feature-vulcan.销毁失败。Git友情提醒feature-vulcan分支还没有被合并如果删除将丢失掉修改如果要强行删除需要使用大写的-D参数。。
现在我们强行删除
$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 287773e).
️多人协作
当你从远程仓库克隆时实际上Git自动把本地的master分支和远程的master分支对应起来了并且远程仓库的默认名称是origin。
要查看远程库的信息用git remote
$ git remote
origin或者用git remote -v显示更详细的信息
$ git remote -v
origin gitgithub.com:michaelliao/learngit.git (fetch)
origin gitgithub.com:michaelliao/learngit.git (push)上面显示了可以抓取和推送的origin的地址。如果没有推送权限就看不到push的地址。
推送分支
推送分支就是把该分支上的所有本地提交推送到远程库。推送时要指定本地分支这样Git就会把该分支推送到远程库对应的远程分支上
$ git push origin master如果要推送其他分支比如dev就改成
$ git push origin dev但是并不是一定要把本地分支往远程推送那么哪些分支需要推送哪些不需要呢 master分支是主分支因此要时刻与远程同步 dev分支是开发分支团队所有成员都需要在上面工作所以也需要与远程同步 bug分支只用于在本地修复bug就没必要推到远程了除非老板要看看你每周到底修复了几个bug feature分支是否推到远程取决于你是否和你的小伙伴合作在上面开发。
总之就是在Git中分支完全可以在本地自己藏着玩是否推送视你的心情而定 抓取分支
多人协作时大家都会往master和dev分支上推送各自的修改。
现在模拟一个你的小伙伴可以在另一台电脑注意要把SSH Key添加到GitHub或者同一台电脑的另一个目录下克隆
$ git clone gitgithub.com:michaelliao/learngit.git
Cloning into learngit...
remote: Counting objects: 40, done.
remote: Compressing objects: 100% (21/21), done.
remote: Total 40 (delta 14), reused 40 (delta 14), pack-reused 0
Receiving objects: 100% (40/40), done.
Resolving deltas: 100% (14/14), done.当你的小伙伴从远程库clone时默认情况下你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看
$ git branch
* master现在你的小伙伴要在dev分支上开发就必须创建远程origin的dev分支到本地于是他用这个命令创建本地dev分支
$ git checkout -b dev origin/dev现在他就可以在dev上继续修改然后时不时地把dev分支push到远程
$ git add env.txt$ git commit -m add env
[dev 7a5e5dd] add env1 file changed, 1 insertion()create mode 100644 env.txt$ git push origin dev
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 308 bytes | 308.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.gitf52c633..7a5e5dd dev - dev
你的小伙伴已经向origin/dev分支推送了他的提交而碰巧你也对同样的文件作了修改并试图推送
$ cat env.txt
env$ git add env.txt$ git commit -m add new env
[dev 7bd91f1] add new env1 file changed, 1 insertion()create mode 100644 env.txt$ git push origin dev
To github.com:michaelliao/learngit.git! [rejected] dev - dev (non-fast-forward)
error: failed to push some refs to gitgithub.com:michaelliao/learngit.git
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: git pull ...) before pushing again.
hint: See the Note about fast-forwards in git push --help for details.推送失败因为你的小伙伴的最新提交和你试图推送的提交有冲突解决办法也很简单Git已经提示我们先用git pull把最新的提交从origin/dev抓下来然后在本地合并解决冲突再推送
$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.git pull remote branchIf you wish to set tracking information for this branch you can do so with:git branch --set-upstream-toorigin/branch devgit pull也失败了原因是没有指定本地dev分支与远程origin/dev分支的链接根据提示设置dev和origin/dev的链接
$ git branch --set-upstream-toorigin/dev dev
Branch dev set up to track remote branch dev from origin.再pull
$ git pull
Auto-merging env.txt
CONFLICT (add/add): Merge conflict in env.txt
Automatic merge failed; fix conflicts and then commit the result.这回git pull成功但是合并有冲突需要手动解决解决的方法和分支管理中的解决冲突完全一样。解决后提交再push
$ git commit -m fix env conflict
[dev 57c53ab] fix env conflict$ git push origin dev
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 621 bytes | 621.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git7a5e5dd..57c53ab dev - dev 因此多人协作的工作模式通常是这样 首先可以试图用git push origin branch-name推送自己的修改 如果推送失败则因为远程分支比你的本地更新需要先用git pull试图合并 如果合并有冲突则解决冲突并在本地提交 没有冲突或者解决掉冲突后再用git push origin branch-name推送就能成功
如果git pull提示no tracking information则说明本地分支和远程分支的链接关系没有创建用命令git branch --set-upstream-to branch-name origin/branch-name。
这就是多人协作的工作模式一旦熟悉了就非常简单。
️Rebase
在上一节我们看到了多人在同一个分支上协作时很容易出现冲突。即使没有冲突后push的童鞋不得不先pull在本地合并然后才能push成功。
每次合并再push后分支变成了这样
$ git log --graph --prettyoneline --abbrev-commit
* d1be385 (HEAD - master, origin/master) init hello
* e5e69f1 Merge branch dev
|\
| * 57c53ab (origin/dev, dev) fix env conflict
| |\
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
| |/
* | 12a631b merged bug fix 101
|\ \
| * | 4c805e2 fix bug 101
|/ /
* | e1e9c68 merge with no-ff
|\ \
| |/
| * f52c633 add merge
|/
* cf810e4 conflict fixed总之看上去很乱有强迫症的童鞋会问为什么Git的提交历史不能是一条干净的直线
其实是可以做到的
Git有一种称为rebase的操作有人把它翻译成“变基”。 先不要随意展开想象。我们还是从实际问题出发看看怎么把分叉的提交变成直线。
在和远程分支同步后我们对hello.py这个文件做了两次提交。用git log命令看看
$ git log --graph --prettyoneline --abbrev-commit
* 582d922 (HEAD - master) add author
* 8875536 add comment
* d1be385 (origin/master) init hello
* e5e69f1 Merge branch dev
|\
| * 57c53ab (origin/dev, dev) fix env conflict
| |\
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
...注意到Git用(HEAD - master)和(origin/master)标识出当前分支的HEAD和远程origin的位置分别是582d922 add author和d1be385 init hello本地分支比远程分支快两个提交。
现在我们尝试推送本地分支
$ git push origin master
To github.com:michaelliao/learngit.git! [rejected] master - master (fetch first)
error: failed to push some refs to gitgithub.com:michaelliao/learngit.git
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., git pull ...) before pushing again.
hint: See the Note about fast-forwards in git push --help for details.很不幸失败了这说明有人先于我们推送了远程分支。按照经验先pull一下
$ git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngitd1be385..f005ed4 master - origin/master* [new tag] v1.0 - v1.0
Auto-merging hello.py
Merge made by the recursive strategy.hello.py | 1 1 file changed, 1 insertion()再用git status看看状态
$ git status
On branch master
Your branch is ahead of origin/master by 3 commits.(use git push to publish your local commits)nothing to commit, working tree clean加上刚才合并的提交现在我们本地分支比远程分支超前3个提交。
用git log看看
$ git log --graph --prettyoneline --abbrev-commit
* e0ea545 (HEAD - master) Merge branch master of github.com:michaelliao/learngit
|\
| * f005ed4 (origin/master) set exit1
* | 582d922 add author
* | 8875536 add comment
|/
* d1be385 init hello
...对强迫症童鞋来说现在事情有点不对头提交历史分叉了。如果现在把本地分支push到远程有没有问题
有
什么问题
不好看
有没有解决方法
有
这个时候rebase就派上了用场。我们输入命令git rebase试试
$ git rebase
First, rewinding head to replay your work on top of it...
Applying: add comment
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py
Applying: add author
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py输出了一大堆操作到底是啥效果再用git log看看
$ git log --graph --prettyoneline --abbrev-commit
* 7e61ed4 (HEAD - master) add author
* 3611cfe add comment
* f005ed4 (origin/master) set exit1
* d1be385 init hello
...原本分叉的提交现在变成一条直线了这种神奇的操作是怎么实现的其实原理非常简单。我们注意观察发现Git把我们本地的提交“挪动”了位置放到了f005ed4 (origin/master) set exit1之后这样整个提交历史就成了一条直线。rebase操作前后最终的提交内容是一致的但是我们本地的commit修改内容已经变化了它们的修改不再基于d1be385 init hello而是基于f005ed4 (origin/master) set exit1但最后的提交7e61ed4内容是一致的。
这就是rebase操作的特点把分叉的提交历史“整理”成一条直线看上去更直观。缺点是本地的分叉提交已经被修改过了。
最后通过push操作把本地分支推送到远程
Mac:~/learngit michael$ git push origin master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 576 bytes | 576.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To github.com:michaelliao/learngit.gitf005ed4..7e61ed4 master - master再用git log看看效果
$ git log --graph --prettyoneline --abbrev-commit
* 7e61ed4 (HEAD - master, origin/master) add author
* 3611cfe add comment
* f005ed4 set exit1
* d1be385 init hello
...
⚙️️️
️标签管理
发布一个版本时我们通常先在版本库中打一个标签tag这样就唯一确定了打标签时刻的版本。将来无论什么时候取某个标签的版本就是把那个打标签的时刻的历史版本取出来。所以标签也是版本库的一个快照。
Git的标签虽然是版本库的快照但其实它就是指向某个commit的指针跟分支很像对不对但是分支可以移动标签不能移动所以创建和删除标签都是瞬间完成的。
Git有commit为什么还要引入tag
“请把上周一的那个版本打包发布commit号是6a5819e...”
“一串乱七八糟的数字不好找”
如果换一个办法
“请把上周一的那个版本打包发布版本号是v1.2”
“好的按照tag v1.2查找commit就行”
所以tag就是一个让人容易记住的有意义的名字它跟某个commit绑在一起。
创建标签
在Git中打标签非常简单首先切换到需要打标签的分支上
$ git branch
* devmaster
$ git checkout master
Switched to branch master然后敲命令git tag name就可以打一个新标签
$ git tag v1.0可以用命令git tag查看所有标签
$ git tag
v1.0默认标签是打在最新提交的commit上的。有时候如果忘了打标签比如现在已经是周五了但应该在周一打的标签没有打怎么办
方法是找到历史提交的commit id然后打上就可以了
$ git log --prettyoneline --abbrev-commit
12a631b (HEAD - master, tag: v1.0, origin/master) merged bug fix 101
4c805e2 fix bug 101
e1e9c68 merge with no-ff
f52c633 add merge
cf810e4 conflict fixed
5dc6824 simple
14096d0 AND simple
b17d20e branch test
d46f35e remove test.txt
b84166e add test.txt
519219b git tracks changes
e43a48b understand how stage works
1094adb append GPL
e475afc add distributed
eaadf4e wrote a readme file比方说要对add merge这次提交打标签它对应的commit id是f52c633敲入命令
$ git tag v0.9 f52c633再用命令git tag查看标签
$ git tag
v0.9
v1.0注意标签不是按时间顺序列出而是按字母排序的。可以用git show tagname查看标签信息
$ git show v0.9
commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9)
Author: Michael Liao askxuefenggmail.com
Date: Fri May 18 21:56:54 2018 0800add mergediff --git a/readme.txt b/readme.txt
...可以看到v0.9确实打在add merge这次提交上。
还可以创建带有说明的标签用-a指定标签名-m指定说明文字
$ git tag -a v0.1 -m version 0.1 released 1094adb用命令git show tagname可以看到说明文字
$ git show v0.1
tag v0.1
Tagger: Michael Liao askxuefenggmail.com
Date: Fri May 18 22:48:43 2018 0800version 0.1 releasedcommit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (tag: v0.1)
Author: Michael Liao askxuefenggmail.com
Date: Fri May 18 21:06:15 2018 0800append GPLdiff --git a/readme.txt b/readme.txt
...注意标签总是和某个commit挂钩。如果这个commit既出现在master分支又出现在dev分支那么在这两个分支上都可以看到这个标签。
操作标签
如果标签打错了也可以删除
$ git tag -d v0.1
Deleted tag v0.1 (was f15b0dd)因为创建的标签都只存储在本地不会自动推送到远程。所以打错的标签可以在本地安全删除。
如果要推送某个标签到远程使用命令git push origin tagname
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git* [new tag] v1.0 - v1.0或者一次性推送全部尚未推送到远程的本地标签
$ git push origin --tags
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git* [new tag] v0.9 - v0.9如果标签已经推送到远程要删除远程标签就麻烦一点先从本地删除
$ git tag -d v0.9
Deleted tag v0.9 (was f52c633)然后从远程删除。删除命令也是push但是格式如下
$ git push origin :refs/tags/v0.9
To github.com:michaelliao/learngit.git- [deleted] v0.9要看看是否真的从远程库删除了标签可以登陆GitHub查看。
git总结 初始化一个Git仓库使用git init命令。 添加文件到Git仓库分两步 使用命令git add file注意可反复多次使用添加多个文件使用命令git commit -m message完成。 HEAD指向的版本就是当前版本因此Git允许我们在版本的历史之间穿梭使用命令git reset --hard commit_id。 穿梭前用git log可以查看提交历史以便确定要回退到哪个版本。 要重返未来用git reflog查看命令历史以便确定要回到未来的哪个版本。 场景1当你改乱了工作区某个文件的内容想直接丢弃工作区的修改时用命令git checkout -- file。 场景2当你不但改乱了工作区某个文件的内容还添加到了暂存区时想丢弃修改分两步第一步用命令git reset HEAD file就回到了场景1第二步按场景1操作。 场景3已经提交了不合适的修改到版本库时想要撤销本次提交参考版本回退一节不过前提是没有推送到远程库。 命令git rm用于删除一个文件。如果一个文件已经被提交到版本库那么你永远不用担心误删但是要小心你只能恢复文件到最新版本你会丢失最近一次提交后你修改的内容。 要关联一个远程库使用命令git remote add origin gitserver-name:path/repo-name.git 关联一个远程库时必须给远程库指定一个名字origin是默认习惯命名 关联后使用命令git push -u origin master第一次推送master分支的所有内容 此后每次本地提交后只要有必要就可以使用命令git push origin master推送最新修改 要克隆一个仓库首先必须知道仓库的地址然后使用git clone命令克隆。 Git支持多种协议包括https但ssh协议速度最快。 Git鼓励大量使用分支 查看分支git branch 创建分支git branch name 切换分支git checkout name或者git switch name 创建切换分支git checkout -b name或者git switch -c name 合并某分支到当前分支git merge name 删除分支git branch -d name 当Git无法自动合并分支时就必须首先解决冲突。解决冲突后再提交合并完成。 解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容再提交。 用git log --graph命令可以看到分支合并图。 Git分支十分强大在团队开发中应该充分应用。 合并分支时加上--no-ff参数就可以用普通模式合并合并后的历史有分支能看出来曾经做过合并而fast forward合并就看不出来曾经做过合并。 修复bug时我们会通过创建新的bug分支进行修复然后合并最后删除 当手头工作没有完成时先把工作现场git stash一下然后去修复bug修复后再git stash pop回到工作现场 在master分支上修复的bug想要合并到当前dev分支可以用git cherry-pick commit命令把bug提交的修改“复制”到当前分支避免重复劳动。 开发一个新feature最好新建一个分支 如果要丢弃一个没有被合并过的分支可以通过git branch -D name强行删除。 查看远程库信息使用git remote -v 本地新建的分支如果不推送到远程对其他人就是不可见的 从本地推送分支使用git push origin branch-name如果推送失败先用git pull抓取远程的新提交 在本地创建和远程分支对应的分支使用git checkout -b branch-name origin/branch-name本地和远程分支的名称最好一致 建立本地分支和远程分支的关联使用git branch --set-upstream branch-name origin/branch-name 从远程抓取分支使用git pull如果有冲突要先处理冲突。 rebase操作可以把本地未push的分叉提交历史整理成直线 rebase的目的是使得我们在查看历史提交的变化时更容易因为分叉的提交需要三方对比。 命令git tag tagname用于新建一个标签默认为HEAD也可以指定一个commit id 命令git tag -a tagname -m blablabla...可以指定标签信息 命令git tag可以查看所有标签。 命令git push origin tagname可以推送一个本地标签 命令git push origin --tags可以推送全部未推送过的本地标签 命令git tag -d tagname可以删除一个本地标签 命令git push origin :refs/tags/tagname可以删除一个远程标签。 文件状态 文件状态 在 Git 中文件的状态通常有三种主要状态这是指文件在版本控制系统中的不同阶段和状态。这三种主要状态是 已修改Modified 这表示文件在工作目录中被修改了但还没有被提交到 Git 仓库。这意味着你对文件进行了更改但这些更改还没有被记录。 已暂存Staged 这表示你已将文件的修改添加到 Git 的暂存区也称为索引。暂存区是一个缓冲区用于存储你要包含在下一次提交中的更改。一旦文件被添加到暂存区它就处于已暂存状态。 已提交Committed 这表示文件的更改已经被成功提交到 Git 仓库中它们成为了仓库的一部分被永久保存在历史记录中。
这些状态之间的转换如下
当你修改了工作目录中的文件它的状态变为“已修改”。如果你希望将这些更改包含在下一次提交中你需要使用 git add 命令将它们添加到暂存区从而将它们的状态变为“已暂存”。最后使用 git commit 命令提交暂存区中的更改将它们的状态变为“已提交”。
此外还有一些其他文件状态如 未跟踪Untracked 这表示文件不在 Git 的版本控制下它既没有被提交也没有被添加到暂存区。通常新创建的文件处于这个状态。 已忽略Ignored 这表示 Git 忽略了这个文件通常是因为在 .gitignore 文件中配置了要忽略的文件或目录。 已删除Deleted 这表示文件已从工作目录中删除但它仍然存在于 Git 的历史记录中因为它曾经被提交过。使用 git rm 命令可以将已删除的文件从 Git 仓库中移除。
这些状态和状态转换是 Git 版本控制中的核心概念帮助你管理文件的更改并记录项目的历史。理解这些状态可以让你更好地使用 Git 进行版本控制和协作开发。