Git官网学习笔记,还是命令行方式操作比较舒服

6 篇文章 0 订阅

Git学习笔记:

官网学习手册参考

文件状态:

官网参考
清楚的要操作的文件的状态和三个区是操作git的关键

  • 未跟踪[Untracked files], 新建的文件,使用git add 变为跟踪

  • 已跟踪[use “git rm --cached <file>…” to unstage]根据提示,可以使用git rm --cached 变为未跟踪,

  • 未修改[nothing to commit, working tree clean] 整个文件都是和仓库一致的

  • 已修改[Changes not staged for commit] 文件已修改,但是未暂存,使用git add 暂存, git checkout – . 可用於取消修改,查看執行git命令後的提示

  • 已暂存[Changes to be committed] 文件已暂存,可以提交,提交后文件状态就变为未修改,同时提示为【use “git reset HEAD <file>…” to unstage】可以使用git reset 变为取消暂存,那么文件会变为修改状态,需求git add重新暂存,才能提交

三个区示意图
在这里插入图片描述

文件状态示意图
在这里插入图片描述

主要的命令有:

开发中常用的已加粗,每个命令可能都有很多的可选参数,具体用时再查
  • git config 常用是配置用户user.name、 user.email、 core.editor 非必须 参考官网
    • git config --global user.name “John Doe”
    • git config --global user.email johndoe@example.com
    • git config --global color.ui true
      个人的一些快捷简短命令配置【配置文件在用户家目录下的 .gitconfig 文件】,仅供参考
[user]
	name = hayashi
	email = xxxx@qq.com
[filter "lfs"]
	clean = git-lfs clean -- %f
	smudge = git-lfs smudge -- %f
	process = git-lfs filter-process
	required = true
[core]
	autocrlf = true
	excludesfile = .gitignoreglobal
[difftool "sourcetree"]
	cmd = '' \"$LOCAL\" \"$REMOTE\"
[mergetool "sourcetree"]
	cmd = "'' "
	trustExitCode = true
[color]
	ui = true
[alias]
	co = checkout
	ci = commit
	cl = clone
	ss = status
	mg = merge
	bh = branch
	pl = pull
	ph = push
	rb = rebase
	ii = init
	rs = reset
	ad = add
	fh = fetch
	sh = stash
	lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
  • git init 在本地初始化一个Git仓库

  • git clone 从远程拉取一个仓库,git clone url localDir 即使localDir目录不存在会自动建立,如果不加目录就是拉取到当前目录,实际上,默认情况下 git clone 命令本质上就是自动创建了本地的 master 分支用于跟踪远程仓库中的 master 分支

  • git status 查看文件状态,很常用,因为要根据文件的状态判断应该执行具体的git命令

  • git add 跟踪文件、暂存文件 git add -i参数可以交互式暂存操作参考

  • git checkout – fileName 抛弃文件修改,这条命令有些危险,所有对文件的修改都没有了,所以在用这条命令前,请务必确定真的不再需要保留刚才的修改, 如果只是想回退版本,同时保留刚才的修改以便将来继续工作,可以用stashing 和分支来处理,应该会更好些,参考git stash命令,任何已经提交到 Git 的都可以被恢复。即便在已经删除的分支中的提交,或者用–amend 重新改写的提交 ,都可以被恢复所以,你可能失去的数据,仅限于没有提交过的,因为对 Git 来说它们就像从未存在过一样,Git没有管理他们所以就有丢失的风险

  • git rm 必须要从已跟踪文件清单中移除, 未跟踪的文件git根本就没有纳入管理,所以就不存在使用git rm能操作未跟踪的文件,如果是-f参数就会删除文件【慎用】,–cached参数文件不会删除但会取消跟踪,如果手动删除文件后,还需要执行git rm filename

  • git reset 将已暂存的取消暂存,在 “Changes to be committed” 下面,括号中有提示,可以使用 git reset HEAD <file>… 的方式取消暂存

  • git commit 提交,加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤,或者撤销提交 参考官网

    • 有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了。想要撤消刚才的提交操作,可以使用 --amend 选项重新提交 git commit --amend
  • git log 查看提交日志, -p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新 官网参考
    一些定制配置:
    + git log --graph --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset" --abbrev-commit --date=relative

      + git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short
      
      + 查看当前目录每个文件的最后提交者。
      git ls-tree -r --name-only HEAD | while read filename; do
        echo "$(git log -1 --format="%an %ae" -- $filename) $filename"
      done
      
      + git log --no-merges --color --stat --graph --date=format:"%Y-%m-%d %H:%M:%S" --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Cblue %s %Cgreen(%cd) %C(bold blue)<%an>%Creset" --abbrev-commit
      
      + git log --no-merges --color --graph --date=format:"%Y-%m-%d %H:%M:%S" --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Cblue %s %Cgreen(%cd) %C(bold blue)<%an>%Creset" --abbrev-commit
      
      + git log --no-merges --color --stat --date=format:"%Y-%m-%d %H:%M:%S" --author="llb" --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Cblue %s %Cgreen(%cd) %C(bold blue)<%an>%Creset" --abbrev-commit
      
      + git log --graph --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset" --abbrev-commit  
      
      + git log --pretty=format:"%C(auto)%h %C(magenta)<%cd> %C(green)[%an] %C(green bold)<%ce> %C(blue normal bold)| %Creset%s%C(auto)%d" --graph --date=short
    
	%H: commit hash
	%h: 缩短的commit hash
	%T: tree hash
	%t: 缩短的 tree hash
	%P: parent hashes
	%p: 缩短的 parent hashes
	%an: 作者名字
	%aN: mailmap的作者名字 (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
	%ae: 作者邮箱
	%aE: 作者邮箱 (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
	%ad: 日期 (--date= 制定的格式)
	%aD: 日期, RFC2822格式
	%ar: 日期, 相对格式(1 day ago)
	%at: 日期, UNIX timestamp
	%ai: 日期, ISO 8601 格式
	%cn: 提交者名字
	%cN: 提交者名字 (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
	%ce: 提交者 email
	%cE: 提交者 email (.mailmap对应,详情参照git-shortlog(1)或者git-blame(1))
	%cd: 提交日期 (--date= 制定的格式)
	%cD: 提交日期, RFC2822格式
	%cr: 提交日期, 相对格式(1 day ago)
	%ct: 提交日期, UNIX timestamp
	%ci: 提交日期, ISO 8601 格式
	%d: ref名称
	%e: encoding
	%s: commit信息标题
	%f: sanitized subject line, suitable for a filename
	%b: commit信息内容
	%N: commit notes
	%gD: reflog selector, e.g., refs/stash@{1}
	%gd: shortened reflog selector, e.g., stash@{1}
	%gs: reflog subject
	%Cred: 切换到红色
	%Cgreen: 切换到绿色
	%Cblue: 切换到蓝色
	%Creset: 重设颜色
	%C(...): 制定颜色, as described in color.branch.* config option
	%m: left, right or boundary mark
	%n: 换行
	%%: a raw %
	%x00: print a byte from a hex code
	%w([[,[,]]]): switch line wrapping, like the -w option of git-shortlog(1).
  • git diff 查看具体修改了什么地方, 有一些需要注意的地方,自行查看官网说明

  • git mv 对文件改名,不过有时候用其他工具批处理改名的话,比如手动改名,要记得在提交前删除老的文件名,再添加新的文件名,即删除原名字文件,在跟踪新文件名的文件,git rm olFileName 然后 git add newFileName

    • 运行 git mv 就相当于运行了下面三条命令:

      1. mv README.txt README
      2. git rm README.txt
      3. git add README
    • 关于mv的一个日志输出问题:

	G:\GitStudy (master)      
		$: git mv Test.java My.java
		
	G:\GitStudy (master)
		$: git status
	On branch master
	Changes to be committed:
	  (use "git reset HEAD <file>..." to unstage)
	           renamed:    Test.java -> My.java 改名后这里显示正确
	  		   new file:   he.txt
	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:   My.java

	G:\GitStudy (master)
		$: git add My.java

	G:\GitStudy (master)
		$: git status
	On branch master
	Changes to be committed:
	  (use "git reset HEAD <file>..." to unstage)
	       new file:   My.java
	   	   renamed:    Test.java -> he.txt 注意这里,上面跟踪修改后的My.java文件后,日志就变成上面这样了,显示Test.java重命名为he.txt了,可能是git的一个bug

:如果在操作是出现如下警告
warning: LF will be replaced by CRLF in Test.java   
参考1  
参考2

  • git remote [-v] 查看当前配置有哪些远程仓库,在克隆完某个项目后,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库 参考官网

    • git remote add [shortname] [url] 添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用
    • git remote show [remote-name] 查看某个远程仓库的详细信息,如: git remote show origin
    • git remote rename oldName newName 修改某个远程仓库在本地的简称,注意,对远程仓库的重命名,也会使对应的分支名称发生变化
    • git remote rm [shortname] 碰到远端仓库服务器迁移,或者原来的克隆镜像不再使用,又或者某个参与者不再贡献代码,那么需要移除对应的远端仓库
  • git fetch [remote-name] 从远程仓库抓取数据到本地,此命令会到远程仓库中拉取所有你本地仓库中还没有的数据,如果是克隆了一个仓库,此命令会自动将远程仓库归于 origin 名下,需要记住,fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,要更新所有分支直接git fetch

  • git merge 合并

  • git pull 自动抓取数据下来,然后将远端分支自动合并到本地仓库中当前分支,它等价于git fetch + git merge

  • git push [remote-name] [branch-name] 将本地仓库中的数据推送到远程仓库, 如果要把本地的 master 分支推送到 origin 服务器上(再次说明下,克隆操作会自动使用默认的 master 和 origin 名字) git push origin master. 只有在所克隆的服务器上有写权限,或者同一时刻没有其他人在推数据,这条命令才会如期完成任务。如果在你推数据前,已经有其他人推送了若干更新,那你的推送操作就会被驳回。你必须先把他们的更新抓取到本地,合并到自己的项目中,然后才可以再次推送,也就是如果本地有修改需要先拉再推【即先pull,在push,一般在项目中就是这么用】

  • git tag 列出现有标签 参考官网

    • git tag -l ‘v1.4.2.*’ 用特定的搜索模式列出符合条件的标签
    • git tag -a|-s 新建标签,不同参数标签不痛,具体遇到再查

忽略一些文件

参考官网

添加不需要提交的文件【即要忽略的文件】 :在.git的同级目录下新建一个名为.gitignore的文件,然后在文件中添加要忽略的文件或者目录,可以使用*号通配符及一些匹配规则来忽略文件.

文件 .gitignore 的格式规范如下:
1. 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
2. 可以使用标准的 glob 模式匹配。
3. 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
4. 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

例如:

  • 要忽略所有的.class文件,那么就可以使用 *.class,

  • *.[oa] 忽略所有以 .o 或 .a 结尾的文件

  • *~ 忽略所有以波浪符(~)结尾的文件

  • 更多例子:

    \# 此为注释 – 将被 Git 忽略
    
    • # 忽略所有 .a 结尾的文件

      *.a

    • # 但 lib.a 除外

      !lib.a

    • # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO

      /TODO

    • # 忽略 build/ 目录下的所有文件

      build/

    • # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

      doc/*.txt

    • # 忽略 doc/ 目录下所有扩展名为 txt 的文件

      doc/**/*.txt

Git使用技巧

参考官网

  • 自动补全脚本, 不及可以提示命令,还可以提示可选参数,需要执行一些操作,官网自行参考,Windows上默认好像就有提示
  • 给字符长的命令起别名,用 git config 为命令设置别名, 如:git config --global alias.co checkout co以后就可以代替checkout使用了这种技术还可以创造出新的命令,比方说取消暂存文件时的输入比较繁琐, 如: git config --global alias.unstage ‘reset HEAD --’, 这样一来,下面的两条命令完全等同:git unstage fileA 和 git reset HEAD fileA;显然,使用别名的方式看起来更清楚。另外,我们还经常设置 last 命令:git config --global alias.last ‘log -1 HEAD’ ,来看最后一次的提交信息

分支模型【重要】

参考官网
Git 鼓励在工作流程中频繁使用分支与合并,理解分支的概念并熟练运用后,你才会意识到为什么 Git 是一个如此强大而独特的工具,并从此真正改变你的开发方式, Git 保存的不是文件差异或者变化量,而只是一系列文件快照

  • git branch 查看所有分支【前面有*号的就是当前分支,实际在命令行,文件路径末尾也会显示当前的工作分支是哪一个】或者创建一个新的分支, 但不会自动切换到这个分支中去,这会在当前 commit 对象上新建一个分支指针

  • git checkout 要切换到其他分支

  • git merge 在当前分支合并指定的其他分支

    实际工作中大体也会用到这样的工作流程:
    1. 开发某个网站。
    2. 为实现某个新的需求,创建一个分支。
    3. 在这个分支上开展工作。

    假设此时,你突然接到一个电话说有个很严重的问题需要紧急修补,那么可以按照下面的方式处理:

    1. 返回到原先已经发布到生产服务器上的分支。
    2. 为这次紧急修补建立一个新分支,并在其中修复问题。
    3. 通过测试后,回到生产服务器所在的分支,将修补分支合并进来,然后再推送到生产服务器上。
    4. 切换到之前实现新需求的分支,继续工作。

首先,我们假设你正在项目中愉快地工作,并且已经提交了几次更新

现在,你决定要修补问题追踪系统上的 #53 问题 。这里为了说明要解决的问题,才把新建的分支取名为 iss53[这里这个分支是保留53问题解决之前的一个分支]。要新建并切换到该分支,运行 git checkout 并加上 -b 参数:

  1. git checkout -b iss53 这相当于执行下面这两条命令:git branch iss53 和 git checkout iss53
    :切换分支之前,留心你当前分支的暂存区或者工作目录里,那些还没有提交的修改,它会和你即将检出的分支产生冲突从而阻止 Git 为你切换分支。切换分支的时候最好保持一个清洁的工作区域,解决方法是:稍后会介绍几个绕过这种问题的办法(分别叫做 stashing 和 commit amending)

    接着开始修复问题,完成后提交【假设我们有个index.html文件,里面的就是 #53 bug存在的文件】

  2. git commit -m "added a new footer [issue 53]"

  3. 目前已经提交了所有的修改,所以接下来可以正常转换到 master 分支: git checkout master
    此时工作目录中的内容和你在解决问题 #53 之前一模一样, 即在master分支上 #53 问题是没有解决的,因为解决是在iss53分支上操作的

  4. 接下来,你得进行紧急修补。我们创建一个紧急修补分支 hotfix 来开展工作
    git checkout -b hotfix
    修复问题,完成后提交【index.html文件中】

  5. 然后回到 master 分支并把它合并进来,然后发布到生产服务器
    git checkout master
    git merge hotfix

  6. 在那个超级重要的修补发布以后,你想要回到被打扰之前的工作。由于当前 hotfix 分支和 master 都指向相同的提交对象,所以 hotfix 已经完成了历史使命,可以删掉了
    使用 git branch 的 -d 选项执行删除操作: git branch -d hotfix

  7. 现在回到之前未完成的 #53 问题修复分支上继续工作: git checkout iss53
    : 值得注意的是之前 hotfix 分支的修改内容尚未包含到 iss53 中来【也就是各个分支直接的操作是互不影响的,彼此隔离,但是他们又有内在的关系,即来自同一个祖先分支master】。如果需要纳入此次修补,可以用 git merge master 把 master 分支合并到 iss53;或者等 iss53 完成之后,再将 iss53 分支中的更新并入 master

  8. 在问题 #53 相关的工作完成之后,可以合并回 master 分支
    git checkout master
    git merge iss53

  9. 既然之前的工作成果已经合并到 master 了,那么 iss53 也就没用了。你可以就此删除它
    git branch -d iss53

遇到冲突时的分支合并

参考官网

有时候合并操作并不会如此顺利。如果在不同的分支中都修改了同一个文件的同一部分,Git 就无法干净地把两者合到一起(译注:逻辑上说,这种问题只能由人来裁决。)即需要人工解决冲突

merge是发生冲突时的日志输出
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git 作了合并,但没有提交,它会停下来等你解决冲突。要看看哪些文件在合并时发生冲突,可以用 git status 查阅:

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:      index.html

no changes added to commit (use "git add" and/or "git commit -a")

任何包含未解决冲突的文件都会以未合并(unmerged)的状态列出。Git 会在有冲突的文件里加入标准的冲突解决标记,可以通过它们来手工定位并解决这些冲突。可以看到此文件包含类似下面这样的部分:

<<<<<<< HEAD
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
  please contact us at support@github.com
</div>
>>>>>>> iss53

可以看到 ======= 隔开的上半部分,是 HEAD(即 master 分支,在运行 merge 命令时所切换到的分支)中的内容,下半部分是在 iss53 分支中的内容。解决冲突的办法无非是二者选其一或者由你亲自整合到一起。比如你可以通过把这段内容替换为下面这样来解决:

<div id="footer">
	please contact us at email.support@github.com
</div>

这个解决方案各采纳了两个分支中的一部分内容,而且还需删除了 <<<<<<<=======>>>>>>> 这些行。在解决了所有文件里的所有冲突后,运行 git add 将把它们标记为已解决状态【git add的另外的一个功能】(译注:实际上就是来一次快照保存到暂存区域。)。因为一旦暂存,就表示冲突已经解决

如果觉得满意了,并且确认所有冲突都已解决,也就是进入了暂存区,就可以用 git commit 来完成这次合并提交

分支管理

参考官网

  • git branch 命令不仅仅能创建和删除分支,如果不加任何参数,它会给出当前所有分支的清单, git branch -r/-a 查看远程分支、本地远程所有的分支
  • 若要查看各个分支最后一个提交对象的信息,运行 git branch -v
  • 要从该清单中筛选出你已经(或尚未)与当前分支合并的分支,可以用 --merged【已被并入当前分支】 和 --no-merged【查看尚未合并的工作】 选项,比如用 git branch --merged 查看哪些分支已被并入当前分支(译注:也就是说哪些分支是当前分支的直接上游。)
  • 分支中如果还包含着尚未合并进来的工作成果,直接简单地用 git branch -d 删除该分支会提示错误,因为那样做会丢失数据

利用分支进行开发的工作流程

参考官网本章
长期分支
可以同时拥有多个开放的分支,每个分支用于完成特定的任务,随着开发的推进,你可以随时把某个特性分支的成果并到其他分支中

​ 使用 Git 的开发者都喜欢用这种方式来开展工作,比如仅在 master 分支中保留完全稳定的代码,即已经发布或即将发布的代码。与此同时,他们还有一个名为 develop 或 next 的平行分支,专门用于后续的开发,或仅用于稳定性测试 — 当然并不是说一定要绝对稳定,不过一旦进入某种稳定状态,便可以把它合并到 master 里。这样,在确保这些已完成的特性分支(短期分支,比如之前的 iss53 分支)能够通过所有测试,并且不会引入更多错误之后,就可以并到主干分支中,等待下一次的发布【稳定分支总是比较老旧】

特性分支
在任何规模的项目中都可以使用特性(Topic)分支。一个特性分支是指一个短期的,用来实现单一特性或与其相关工作的分支

​ 上节的例子里已经见过这种用法了。我们创建了 iss53 和 hotfix 这两个特性分支,在提交了若干更新后,把它们合并到主干分支,然后删除。该技术允许你迅速且完全的进行语境切换 — 因为你的工作分散在不同的流水线里,每个分支里的改变都和它的目标特性相关,浏览代码之类的事情因而变得更简单了。你可以把作出的改变保持在特性分支中几分钟,几天甚至几个月,等它们成熟以后再合并,而不用在乎它们建立的顺序或者进度。

远程分支【重要】

参考官网本章

远程分支(remote branch)是本地对远程仓库中的分支的索引, 我们用 (远程仓库名)/(分支名) 这样的形式表示远程分支

比如我们想看看上次同 origin 仓库通讯时 master 分支的样子,就应该查看 origin/master 分支。如果你和同伴一起修复某个问题,但他们先推送了一个 iss53 分支到远程仓库,虽然你可能也有一个本地的 iss53 分支,但指向服务器上最新更新的却应该是 origin/iss53 分支

举例说明。假设你们团队有个地址为 git.ourcompany.com 的 Git 服务器。如果你从这里克隆,Git 会自动为你将此远程仓库命名为 origin,并下载其中所有的数据,建立一个指向它的 master 分支的指针,在本地命名为 origin/master,但你无法在本地更改其数据。接着,Git 建立一个属于你自己的本地 master 分支,始于 origin 上 master 分支[远程分支]相同的位置,你可以就此开始工作
在这里插入图片描述
如果你在本地 master 分支做了些改动,与此同时,其他人向 git.ourcompany.com 推送了他们的更新,那么服务器上的 master 分支就会向前推进,而与此同时,你在本地的提交历史正朝向不同方向发展。不过只要你不和服务器通讯,你的 origin/master 指针仍然保持原位不会移动
在这里插入图片描述
可以运行 git fetch origin 来同步远程服务器上的数据到本地。该命令首先找到 origin 是哪个服务器(本例为 git.ourcompany.com),从上面获取你尚未拥有的数据,更新你本地的数据库,然后把 origin/master 的指针移到它最新的位置上
在这里插入图片描述

为了演示拥有多个远程分支(在不同的远程服务器上)的项目是如何工作的,我们假设你还有另一个仅供你的敏捷开发小组使用的内部服务器 git.team1.ourcompany.com。可以用 git remote add 命令把它加为当前项目的远程分支之一。我们把它命名为 teamone,以便代替完整的 Git URL 以方便使用
在这里插入图片描述
现在你可以用 git fetch teamone 来获取小组服务器上你还没有的数据了。由于当前该服务器上的内容是你 origin 服务器上的子集,Git 不会下载任何数据,而只是简单地创建一个名为 teamone/master 的远程分支,指向 teamone 服务器上 master 分支所在的提交对象 31b8e
在这里插入图片描述
要想和其他人分享某个本地分支,你需要把它推送到一个你拥有写权限的远程仓库。你创建的本地分支不会因为你的写入操作而被自动同步到你引入的远程服务器上,你需要明确地执行推送分支的操作。换句话说,对于不想分享的分支,你尽管保留为私人分支好了,而只推送那些协同工作要用到的特性分支。

举例:如果你有个叫 serverfix 的分支需要和他人一起开发,可以运行 git push (远程仓库名) (分支名): git push origin serverfix

也可以运行 git push origin serverfix:serverfix 来实现相同的效果,它的意思是 上传我本地的 serverfix 分支到远程仓库中去,仍旧称它为 serverfix 分支”。通过此语法,你可以把本地分支推送到某个命名不同的远程分支:若想把远程分支叫作 awesomebranch,可以用 git push origin serverfix:awesomebranch 来推送数据

从远程分支 checkout 出来的本地分支,称为 跟踪分支 (tracking branch)。跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入 git push,Git 会自行推断应该向哪个服务器的哪个分支推送数据。同样,在这些分支里运行 git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来

在克隆仓库时,Git 通常会自动创建一个名为 master 的分支来跟踪 origin/master。这正是 git push 和 git pull 一开始就能正常工作的原因。当然,你可以随心所欲地设定为其它跟踪分支,比如 origin 上除了 master 之外的其它分支。刚才我们已经看到了这样的一个例子:git checkout -b [分支名] [远程名]/[分支名] 还可以用 --track 选项简化: git checkout --track origin/serverfix
要为本地分支设定不同于远程分支的名字,只需在第一个版本的命令里换个名字: git checkout -b sf origin/serverfix

如果不再需要某个远程分支了,比如搞定了某个特性并把它合并进了远程的 master 分支(或任何其他存放稳定代码的分支),可以用这个非常无厘头的语法来删除它:git push [远程名] :[分支名]。如果想在服务器上删除 serverfix 分支,运行下面的命令: git push origin :serverfix

分支的变基

官网本章参考V2

把一个分支中的修改整合到另一个分支的办法有两种:merge 和 rebase

回顾之前有关合并见下图,你会看到开发进程分叉到两个不同分支,又各自提交了更新
在这里插入图片描述
最容易的整合分支的方法是 merge 命令,它会把两个分支最新的快照(C3 和 C4)以及二者最新的共同祖先(C2)进行三方合并,合并的结果是产生一个新的提交对象(C5)
在这里插入图片描述

其实,还有另外一个选择:你可以把在 C3 里产生的变化补丁在 C4 的基础上重新打一遍。在 Git 里,这种操作叫做变基(rebase)。有了 rebase 命令,就可以把在一个分支里提交的改变移到另一个分支里重放一遍。

在上面这个例子中,运行:
git checkout experiment
git rebase master

它的原理是回到两个分支最近的共同祖先,根据当前分支(也就是要进行变基的分支 experiment)后续的历次提交对象(这里只有一个 C3),生成一系列文件补丁,然后以基底分支(也就是主干分支 master)最后一个提交对象(C4)为新的出发点,逐个应用之前准备好的补丁文件,最后会生成一个新的合并提交对象(C3’),从而改写 experiment 的提交历史,使它成为 master 分支的直接下游
在这里插入图片描述

现在回到 master 分支,进行一次快进合并

在这里插入图片描述
变基能产生一个更为整洁的提交历史, 一般我们使用变基的目的,是想要得到一个能在远程分支上干净应用的补丁 — 比如某些项目你不是维护者,但想帮点忙的话,最好用变基:先在自己的一个分支里进行开发,当准备向主项目提交补丁的时候,根据最新的 origin/master 进行一次变基操作然后再提交,这样维护者就不需要做任何整合工作(译注:实际上是把解决分支补丁同最新主干代码之间冲突的责任,化转为由提交补丁的人来解决。),只需根据你提供的仓库地址作一次快进合并,或者直接采纳你提交的补丁,请注意,合并结果中最后一次提交所指向的快照,无论是通过变基,还是三方合并,都会得到相同的快照内容,只不过提交历史不同罢了。变基是按照每行的修改次序重演一遍修改,而合并是把最终结果合在一起

变基举例:
变基也可以放到其他分支进行,并不一定非得根据分化之前的分支。以图 3-31 的历史为例,我们为了给服务器端代码添加一些功能而创建了特性分支 server,然后提交 C3 和 C4。然后又从 C3 的地方再增加一个 client 分支来对客户端代码进行一些相应修改,所以提交了 C8 和 C9。最后,又回到 server 分支提交了 C10
在这里插入图片描述

假设在接下来的一次软件发布中,我们决定先把客户端的修改并到主线中,而暂缓并入服务端软件的修改(因为还需要进一步测试)。这个时候,我们就可以把基于 client 分支而非 server 分支的改变(即 C8 和 C9),跳过 server 直接放到 master 分支中重演一遍,但这需要用 git rebase 的 --onto 选项指定新的基底分支 master: git rebase --onto master server client

这好比在说:“取出 client 分支,找出 client 分支和 server 分支的共同祖先之后的变化,然后把它们在 master 上重演一遍”。是不是有点复杂?不过它的结果如图 3-32 所示,非常酷(译注:虽然 client 里的 C8, C9 在 C3 之后,但这仅表明时间上的先后,而非在 C3 修改的基础上进一步改动,因为 server 和 client 这两个分支对应的代码应该是两套文件,虽然这么说不是很严格,但应理解为在 C3 时间点之后,对另外的文件所做的 C8,C9 修改,放到主干重演。):
在这里插入图片描述
现在可以快进 master 分支了
git checkout master
git merge client

在这里插入图片描述

现在我们决定把 server 分支的变化也包含进来。我们可以直接把 server 分支变基到 master,而不用手工切换到 server 分支后再执行变基操作 — git rebase [主分支] [特性分支] 命令会先取出特性分支 server,然后在主分支 master 上重演:git rebase master server

于是,server 的进度应用到 master 的基础上
在这里插入图片描述
然后就可以快进主干分支 master 了
git checkout master
git merge server

现在 client 和 server 分支的变化都已经集成到主干分支来了,可以删掉它们了。最终我们的提交历史会变成图 3-35 的样子:
git branch -d client
git branch -d server
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KsVxaiu0-1590383520934)(https://git-scm.com/book/en/v2/images/interesting-rebase-5.png "最终的提交历史")]

变基的风险
用它得遵守一条准则:一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行变基操作[即不要对在你的仓库外有副本的分支执行变基]

变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。 如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase 命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟

  • git stash 经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是git stash命令,git stash list现有的储藏,git stash save “comment”

git stash apply 应用储藏,如果你想应用更早的储藏,你可以通过名字指定它,像这样:git stash apply stash@{2}。如果你不指明,Git 默认使用最近的储藏并尝试应用它,运行 git stash drop,加上你希望移除的储藏的名字,取消之前所应用储藏git stash show -p stash@{0} | git apply -R
,同样的,如果你沒有指定具体的某个储藏,Git 会选择最近的储藏git stash show -p | git apply -R
新建一个別名,在你的 Git 里增加一个 stash-unapply 命令,这样更有效率git config --global alias.stash-unapply '!git stash show -p | git apply -R’

  • git clean 对于工作目录中一些工作或文件,你想做的也许不是储藏而是移除

  • git grep 从提交历史或者工作目录中查找一个字符串或者正则表达式

一般的工作中的Git操作流程博客参考

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值