Git学习笔记

 

Git使用中遇到的需求与解决方案记录, 不定期更新。

关键概念

origin

origin是remote组中的默认成员, 在git clone时自动创建, 其值为远程repo的url(url以.git结尾)。

git remote

git remote是管理远程repo的指令, 当每一个项目独立成repo的情况下似乎不需要常使用该指令1。以下罗列可能的使用场景:

  • 检查远程repo与本地的差异
git remote [-v | --verbose] update

该指令将比对所有remote组中的远程repo各个branch与本地repo相应branch的差异, 一般对个人(现阶段的我)而言, remote组中只有一个成员, 即origin

  • 查看远程repo的全部信息
git remote -v

该指令将罗列出当前git环境下所有的远程repo信息, 以<remote_name, url>对的形式显示, 一般而言即显示类似如下内容:

origin  https://github.com/zouyu4524/RL-market.git (fetch)
origin  https://github.com/zouyu4524/RL-market.git (push)

常用操作

在Commit前撤销已add的修改

git reset <file>

或者如下

git reset 

撤销所有的已add但未commit的修改。

: 如果repo还没有任何的commit, 也可以通过如下的命令撤销2

git rm [-r] --cached <added_file_to_undo>

其中-r是可选项, 表示递归式操作, 当需要撤回的文件包含文件夹时需要设置该选项。
原理在于git ret是将HEAD撤销至上一次commit状态, 而若还没有任何的commit, 则HEAD无法解析。其中2给出了很有趣的解释。

在Push前撤销已commit的修改

git reset <commit_id>

HEAD指针☞回commit_id所标识的commit, 而查找相应的commit id可以通过git log <-no.>完成。其中no.为commit的编号, 从新到旧递增, 当前的commit编号为1, 所以可以通过

git log -2

查看目标commit, 可以进一步比对commit内容确认。明确commit id后, 执行git reset <commit_id>即可。
: 以上操作将完全撤销至上一次commit后的状态, 但不会撤回已经修改的代码。

创建新的Branch

Branch管理原则3:

In your github fork, you need to keep your master branch clean, by clean I mean without any changes, like that you can create at any time a branch from your master. Each time that you want to commit a bug or a feature, you need to create a branch for it, which will be a copy of your master branch.

将远程的repo(origin/master)同步至本地

git pull

然后, 以此创建新的branch

git checkout -b [name_of_new_branch]

将新的branch推送至远程repo

git push -u origin [name_of_new_branch]

在新创建的branch上进行修改, 所有的commit在该branch上开展, 直至达到阶段性的进展再考虑将其同步至master branch。

在新的branch上commit前务必确认当前处于新的branch, 如下命令查看当前branch

git branch --list

当前branch将会用*标注。

如果当前branch中的修改到达一个阶段, 可以将其合并至master branch中, 操作如下

git checkout master
git merge origin/[name_of_new_branch]

首先切换回master branch, 再执行merge命令, 将修改发生的branch合并至master branch中。

修改branch名称

修改本地的branch名称, 首先定位到需要修改名称的branch, 然后4

git branch -m new_name

删除旧名称的branch并将新名称推送至远程repo

git push origin :old_name new_name

为本地的branch重新创建上传的通道

git push origin -u new_name

删除branch

git push --delete <remote_name> <branch_name>
git branch -d <branch_name>

第一条删除远程的分支, 第二条删除本地分支5

git免密push

  • 添加SSH密钥6

可以首先通过ls ~/.ssh/查看当前系统中是否存在SSH密钥, 如果显示没有以.pub为后缀的文件, 则还没有SSH。

  • 通过以下命令创建SSH密钥:
ssh-keygen -t rsa -C "any comments"

顺次会提示确认密钥存放地址, 设置查看密钥的密码/确认密码, 可以按照默认流程按三次回车则生成的密钥将存放于~/.ssh目录下, 且无需密码查看。其中-t是制定加密方式, 一般用rsa, -C用于添加注释。

  • 更改remoteurl为git格式

默认情况下, 从github的远程repo克隆时会提供https的地址, 在这种情况下, 即便在Github的Settings/SSH keys中添加本机的秘钥也仍然需要每次push时提供账户和密码7。实际上需要通过git的链接克隆就不会有这个问题了。如果当前的本机repo已经是通过https地址克隆而来, 那么可以修改remote地址为git格式即可, 如下:

git remote set-url origin git@github.com:USERNAME/REPOSITORY.git

保存进度

某些情况下需要暂时存储部分修改, 而优先改动并生效其他修改: 例如正在编辑一篇博客文章, 而博客结构需要即时做出调整, 此时, 可以首先将编辑中的博客文章推至进度, 而优先修改博客结构相关代码。实现此需求可以用到stash指令。示例如下:

git stash push -m "message"

以上命令会将当前所有已产生的修改全部推至进度, 并打上”message”信息; 此后再执行git status可以获得一个“干净”的工作区。但是以上并非适用所有的情形, 更多的时候可能是同时进行了多个不同目的的修改, 例如: 既有博客内容相关的修改, 又有博客结构相关的修改, 此时需要摘出需要暂存的改动, 可以通过--patch参数(简写为-p)对照逐条改动决定是否需要加入进度。用例如下:

git stash push -p -m "message"

git将会逐条显示改动, 并提示针对当前改动如何选择, 如下:

Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]?

其中各个字母的含义如下8:

y - stash this hunk
n - do not stash this hunk
q - quit; do not stash this hunk or any of the remaining ones
a - stash this hunk and all later hunks in the file
d - do not stash this hunk or any of the later hunks in the file
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
g - select a hunk to go to
/ - search for a hunk matching the given regex
e - manually edit the current hunk
? - print help

常用的选择即: y, n, 分别表示将当前改动加入/不加入进度

注意到, 较早的教程中经常提及另一个命令实现以上需求, 即: git stash save -p "message"。在较新版本的git中已建议弃用该方式, 两者的差别在于: git stash push可以指定路径以更好的控制哪些文件需要添加至进度, 而git stash save不具备该功能9。此外, git stash save接收一个预留的参数位, 以接收”message”, 而git stash push需要通过-m指定, 相比之下, git stash pushgit commit类似, 指令上具有更好的一致性。

从进度恢复

以上给出了选择部分修改保存至进度的方式, 相应地, 以下给出从进度恢复的方式:

git stash pop

对于简单的项目, 进度一般至多存放一次修改, 那么使用以上命令就可以实现需求, 以上面的例子而言: 在完成了博客结构相关代码的修改后, 现在需要继续博客文章的写作, 上述命令即可将进度中的修改恢复至工作区; 如果有多个进度, 也可通过git stash list查看进度, 确认要恢复的进度id, 并通过git stash pop stash@{id}恢复10; 更多的用法可以参考这里