Git 如何删除远程服务器文件同时保留本地文件


在上传工程到 git 上时,有时候会把本地的一些配置文件传到服务器上,这时你先删除本地,再同步服务器,显然是不合理的。
git 提供了一个好的解决方法,可以直接删除服务器文件,同时不影响本地文件,命令如下:

git rm --cached filename/-r directory
git commit "xxxx"
git push

1.删除服务器文件,本地保留。

git rm --cached useless.log
git commit -m "remove file from remote repository"
git push

此时 github 上已经不存在了

2.删除远程 useless 文件夹,本地保留,一定要注意,删除文件夹要使用 -r 参数。

git rm --cached -r useless
git commit -m "remove directory from remote repository"
git push
阅读全文

Git 提交空目录


目录是空的:
这种情况下只需要在目录下创建 .gitkeep 文件,然后在项目的 .gitignore 中设置不忽略 .gitkeep
.gitkeep 是一个约定俗成的文件名并不会带有特殊规则

目录中已经存在文件
那就需要首先在根目录中设置 !.gitignore,然后在目标目录也创建一个 .gitignore 文件,并在文件中设置

*
!.gitignore

这样就可以在项目中提交空目录了

阅读全文

几种 Git 分支管理模型


单主干
单主干的分支实践(Trunk-based development,TBD)在 SVN 中比较流行。Google 和 Facebook 都使用这种方式。trunk 是 SVN 中主干分支的名称,对应到 Git 中则是 master 分支。TBD 的特点是所有团队成员都在单个主干分支上进行开发。当需要发布时,先考虑使用标签tag,即 tag 某个 commit 来作为发布的版本。如果仅靠 tag 不能满足要求,则从主干分支创建发布分支。bug 修复在主干分支中进行,再 cherry-pick 到发布分支。
git-branch-01.png



阅读全文

Git 回滚合并


假设有如下分支图:
unmerge1.png

注:Git 分支图中的箭头表示依赖关系,并不是分支发展路线。发展路线和箭头是相反的。也就是图中是从C1开始一直发展到C12的。

假设要回滚C10。

第一种解决方案是将 master 回退到C8,然后将两个特性分支 jk/post-checkout 和 db/push-cleanup 合并过来。

git checkout master
git reset --hard [sha_of_C8]
git merge jk/post-checkout
git merge db/push-cleanup

完成之后,分支图如下:
unmerge2.png

接下来就可以继续在新的 master 上工作,然后在适当的时候将 tv/rebase-stat 合并回来。

回滚合并
如果在很久之后才发现要回滚,或者其它人已经在合并之后提交了代码,分支图会是这样:
unmerge3.png

这种情况下要么回退一次合并,要么退回去,再重新合并,然后将新的变更 C9和C10 cherry-pick 过来。后者容易让人迷惑,做起来也不容易,尤其是在合并之后提交很多的情况下。
git revert 能很好地处理合并的回退。你需要指定需要回退的那次合并提交记录,并指定保留合并中的哪一条线parent。假设我们需要回退合并 jk/post-checkout 的记录,则这样做:

git revert -m 1 [sha_of_C8]
Finished one revert.
[master 88edd6d] Revert "Merge branch 'jk/post-checkout'"
 1 files changed, 0 insertions(+), 2 deletions(-)

完成后会产生一个新提交,这个提交回滚了合并过来的内容。其结果和一个包含被合并过来分支改动的 cherry-pick(反向操作,即回滚)差不多。
unmerge4.png

回滚“回滚”
假设在回滚之后,我们需要再次合并这个分支。如果你直接合并的话,什么都不会发生。

git merge jk/post-checkout
Already up-to-date.

更令人困惑的是,如果你回到分支,再做一些修改后再合并,则只有新产生的修改会被合并过来。
unmerge5.png

这种状态是一种非常奇怪的状态,有可能导致冲突或者难以理解的错误。此时你真正想做的事情应该是回滚“上一次对合并的回滚操作”。

git revert 88edd6d
Finished one revert.
[master 268e243] Revert "Revert "Merge branch 'jk/post-checkout'""
 1 files changed, 2 insertions(+), 0 deletions(-)

unmerge6.png

现在我们将分支恢复到了合并之后的情况,如果分支上有新的改动,就可以直接合并了。

git merge jk/post-checkout
Auto-merging test.txt
Merge made by recursive.
 test.txt |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

unmerge7.png

最后,建议使用 git merge --no-ff 合并分支,这样可以保持 分支不是快进的,使它可以回滚。

阅读全文

Git 的 ssh key


生成 ssh key

ssh-keygen -t rsa -C "your name"

这样默认会在本地的 ~/.ssh 目录下生成 id_rsa,id_rsa.pub 两个文件。
id_rsa 是私钥,id_rsa.pub 是公钥。

使用 ssh key
ssh key 方式登录远程服务器
我们需要把 id_rsa.pub 拷贝到远程服务器的 ~/.ssh 下面,并改名为 authorized_keys,这样我们就可以使用 key 的方式登录了。

ssh key 方式使用 git clone 代码
如果我们使用的是 github,只需要把 id_rsa.pub 的内容拷贝出来,在 github 的 setting 里面添加即可, 我们就可以使用 ssh 方式 clone 代码了。

// 请修改为你自己的git地址
git clone git@github.70data/test.git

多站点使用不同的 ssh key
默认 ssh 登录时使用的是 id_rsa 文件,我们也可以指定其他文件;
首先我们生成不同的 key:

ssh-keygen -t rsa -C "user1" -f user1
ssh-keygen -t rsa -C "user2" -f user2

我们生成 user1,user2 两个不同的 ssh key,然后我们在 .ssh 下创建 config 文件。
输入:

Host company
  HostName company.com
  User git
  IdentityFile ~/.ssh/user1
Host github
  HostName github.com
  User git
  IdentityFile ~/.ssh/user2

这样访问 company.com 就会使用 user1,访问 github.com 就会使用user2。

同一站点使用不同的 ssh key
我们有时候需要在同一站点使用不同的 ssh key,比如使用 pages 服务,想要创建两个站点,但是 pages 上不允许不同的用户使用同一个 ssh key,我们在 config 文件里做相应的修改。

Host git-site1
  HostName github.com
  User git
  IdentityFile ~/.ssh/user1
Host git-site2
  HostName github.com
  User git
  IdentityFile ~/.ssh/user2

然后我们更改 git 仓库的远程地址

# site1
$ git remote remove origin 
$ git remote add origin git@git-site1:user1/user1.git
# site2
$ git remote remove origin 
$ git remote add origin git@git-site2:user2/user2.git

关键是把 github.com 改为 git-site1 和 git-site2。

测试 ssh key 是否配置成功

ssh -T git@github.com

成功的话会显示:

Welcome to github, username!
阅读全文

Git 撤销修改


Git 里共有5种状态:
未修改(Origin)
已修改(Modified)
已暂存(Staged)
已提交(Committed)
已推送(Pushed)

已修改,未暂存
如果我们只是在编辑器里修改了文件,但还没有执行 git add .,这时候我们的文件还在工作区,并没有进入暂存区,我们可以用:

git checkout .

或者

git reset --hard

来进行撤销操作。

已暂存,未提交
你已经执行了 git add .,但还没有执行 git commit -m "comment"。这时候你意识到了错误,想要撤销,你可以执行:

git reset
git checkout .

或者

git reset --hard

git reset 只是把修改退回到了 git add . 之前的状态,也就是说文件本身还处于已修改未暂存状态,你如果想退回未修改状态,还需要执行 git checkout .。

已提交,未推送
你的手太快,你既执行了 git add .,又执行了 git commit,这时候你的代码已经进入了你的本地仓库,然而你后悔了,怎么办?不要着急,还有办法。

git reset --hard origin/master

还是这个 git reset --hard 命令,只不过这次多了一个参数 origin/master,正如我们上面讲过的,origin/master 代表远程仓库,既然你已经污染了你的本地仓库,那么就从远程仓库把代码取回来吧。

已推送
很不幸,你的手实在是太快了,你既 git add 了,又 git commit 了,并且还 git push 了,这时你的代码已经进入远程仓库。如果你想恢复的话,还好,由于你的本地仓库和远程仓库是等价的,你只需要先恢复本地仓库,再强制 push 到远程仓库就好了:

git reset --hard HEAD^
git push -f
阅读全文

Git Rebase


分支合并,有两个选择,一个是 merge,另一个是 rebase。

  1. merge 和 rebase 合并后的结果是一模一样的,形象的说,二者是殊途同归。
  2. 使用 rebase 后的 commit 与之前的 commit,它们的 SHA-1 值不同,Git 会把它们看成两次提交。

现在社区中推荐的主流 Git 合作方法,也是利用 Rebase 命令,即 Fork 一个代码库后,保留一个 remote 分支用来跟近主库进度,另开一个 feature 分支来打 patch,当 patch 打好后,在本地同步一下 remote 分支上的代码,保持与主库一致,如果在你打 patch 这段时间,主库发生了变化,那么你就需要在本地预先做一次 rebase 操作,以保证你的改动是构建在主库最新代码之上的。这其实相当与你帮助作者在本地处理好了冲突,这样作者再合并你的代码时候,也就能比较轻松了。换个角度,其实使用
rebase 这个过程也是一个自我检查的过程,可以强制你对改动进行 Review,从而减轻贡献者和所有者之间的工作量。因为没有人比你更熟悉你的代码。

git pull —rebase,这个命令在实际使用中的出场率还是很高的。
我们先从 git pull 说起,git pull 完整的应该是 git fetch + git merge FETCH_HEAD,默认时候 git pull 会先拉取代码,再进行 merge,上面说了使用 merge 会多出一条合并的 commit 以及一条分支线来,如果 commit 和 merge 频繁的话,可能会出现下图这样的情况,但是 rebase 则不同,其会保持线性,这样提交记录看起来就会整洁许多,使用 —rebase 就是这个意思用 git rebase 取代。
git-rebase-1.png

阅读全文

Git 删除分支


查看已有的本地及远程分支:

git branch -a

删除远程分支:

git push origin --delete Su-modify

删除后,可再次查看分支情况:

git branch -a

删除本地分支:

git branch -d Su-modify

若分支有修改还未合并,会提示你还没合并。
强行删除本地分支:

git branch -D Su-modify
阅读全文