一半君的总结纸

听话只听一半君

git 如何才能只checkout一个文件(以及repo太大太慢怎么办)?

备忘录

如何解决repo太大速度慢的问题

如果是第一次clone很慢,官方建议使用shallow clone,只clone一个branch,以及使用sparse checkout功能
How to handle big repositories with git – Atlassian Blogs

常用命令:

# --depth 1表示shallow clone只clone最近的1次histroy,只clone一个branch,-n表示clone完成之后不要checkout HEAD
git clone -n git://path/to/the_repo.git --depth 1 --branch branch_name --single-branch

# cd the_repo
git checkout HEAD /path/to/name_of_file

# 改好以后
git commit path/to/name_of_file -m "some comment"

git push

http://stackoverflow.com/questions/2466735/how-to-checkout-only-one-file-from-git-repository
如果clone的源 不是一个bare repo, push的时候会看到如下错误提示

error: refusing to update checked out branch: refs/heads/master

github上clone之前可以先看看repo有多大

syntax: /repos/:user/:repo [GET]
example: https://api.github.com/repos/git/git

找到size property,单位是kb

测试和举例

qt4.8大概633mb,用下面命令尽量少下历史,大概1分钟,clone出来的目录164mb

git clone -n https://github.com/qtproject/qt.git --depth 1 --branch 4.8 --single-branch

# 比如你只想改util/lexgen文件夹下的文件
git checkout HEAD util/lexgen

# 这个时候如果你用git status,你会看到一大堆deleted xxx, 这是当然的,因为你的文件夹现在
# 基本是空的, 如果看不清你要的文件 你可以用 
git status | grep modified:
或者
git ls-files -m

# 好了现在最好你建个本地branch用于你的修改 比如
git checkout -b iss9527

# 然后你可以开始测试修改了,改的过程中,你随便commit多少次都可以,这是你本地的修改
# 当然你最好只加你改过的文件,不要git add --all,因为你文件夹里其他文件都没有,不然
# git以为你要删掉所有文件
git add modified-files

# 改好以后,你可能会想把修改上传,假设你想上传到master branch
git checkout master

# 此时你也许应该pull一下,因为可能有人改过网上的最新版了,就算你merge了你的iss9527,
# 你还是得手动和网上的新版merge,当然不pull也行,你可以先merge你的iss9527
git pull

# merge你修改的到master,如果运气好的话,不用手改,下一步就能push了
# 如果运气不好,有人改了网上的,和你的iss9527冲突,那可能要手改 
# 如果你还要继续改,你也可以把master merge到iss9527
git merge iss9527

# 其他技巧

# 如果你装了kdiff3 你就可以git difftool 或者 
git mergetool

# 如果你把repo搞乱了,想彻底恢复本地repo成服务器上repo的样子,
# 或者你想从服务器上拿最新版,放弃本地所有修改,你可以先fetch再reset
# 当然保险起见,最好把你改的拷一份到别的地方,当然如果你git用的超熟,用stash也行
git fetch
git reset --hard origin/branch-name

简化版举例

如果改的文件很少,不想新开本地branch,上面的操作可以简化为如下操作,假设你已经clone过了,再怎样乱搞也用不着再clone,clone只需要一次就好,就算你搞乱了也可以恢复,不需要再次clone了
假设你到了公司,今天需要改一些文件

# 那首先第一步你得从网上拿最新的版本(这是因为如果现在你拿了最新,然后到你改好之前,如果你
# 运气好的话,网上没人改你这个branch,那你直接push就好了,如果你现在不拿最新版,很可能你本地
# 的已经是旧的,等你改好以后,发现push不上去,你还得拷出去,拿最新版,再弄回来,这样不是麻烦么)
# 假设这个branch里没有你想保留的文件(如果有你改过但是没有commit的文件,你最好先拷去别的地方
# 虽然你可以用local branch的commit或者stash功能来避免手动操作,但是这里的目的是简化的非程序员
# 的做法,所以暂不讨论"正确的推荐"用法)
git fetch
git reset --hard origin/branch-name

# 然后假设你只想改util/lexgen文件夹下的文件
git checkout HEAD util/lexgen

# 这个时候如果你用git status,你会看到一大堆deleted xxx, 这是当然的,因为你的文件夹
# 现在基本是空的, 如果看不清你要的文件 你可以用 
git status | grep modified:
或者
git ls-files -m

# 然后你可以开始测试修改了
# 你最好只加你改过的文件,不要git add --all,因为你文件夹里其他文件都没有,不然
# git以为你要删掉所有文件. 你可以明确的把所有文件一个一个贴上去,也可以用下面的
# add . 下面有个图里有介绍
git add .

# 注意 push 之前最好 git status 查看一下那些改变被加到staging area了(哪些改变是git认为你想push的)
# 因为有时候你可能不小心加错了,没问题的话你就可以git push了
# 但是如果这时候你push不上去,提示你说网上的版本比你的新,你得先merge新的内容以后才能push
# 那此时你应该pull一下,但是如果有些文件比如.xlsx不是文本的,他不能自动merge,所以pull不会
# 自己帮你merge,推荐的做法是先fetch, 然后用diff看清楚改了哪些,然后再git merge
# 假设不想搞太复杂,不用stash,也不在local branch里commit,那非技术男艺术家的手动做法是
# 先把所有你改的地方拷出去,然后用网上的最新版覆盖本地所有文件,再把你拷出去的拷回来
#(这很手动,但是对于没有多人改一个文件的时候,以及公司不给你用kdiff3类似的gui方式的工具的时候也行)
git fetch  # will fetch the latest changes on the remote
git reset --hard origin/master # will set your local branch to match the representation of the remote just pulled down.

# 然后你本地的master branch里的文件全被网上最新版的master branch覆盖了
# 你可以把文件拷回去,然后add,在status检查一下,然后commit,最后push

Tips:

  • 如果需要查看diff和merge,在windos上的话推荐用 kdiff3
    可以把下面的内容加进你的.gitconfig

    [merge]
            tool = kdiff3
    [mergetool "kdiff3"]
            path = c:/Program Files/KDiff3/kdiff3.exe
    [diff]
            tool = kdiff3
            guitool = kdiff3
    [difftool "kdiff3"]
            path = c:/Program Files/KDiff3/kdiff3.exe
    

    如果想对所有repo都做以上配置,可以用

    git config --global --edit
    
  • Git Version 1.x
    YfLUZGit Version 2.x
    git add
  • 可以打开file system cache看会不会快点
    git config core.fscache true
    

此外,如果只clone一个branch/tag想要快,可以

# 这样是带所有到这个HEAD的历史的
git clone <repo_url> --branch <tag_name> --single-branch

# 这样是不带历史的,更小
git clone <repo_url> --branch <tag_name> --depth 1

参考:
Git push error ‘[remote rejected] master -> master (branch is currently checked out)’
Git Push error: refusing to update checked out branch
Push to a non-bare Git repository
git-clone – Documentation
See the size of a github repo before cloning it?
The Difference Between MiB and MB
Why Perforce is more scalable than Git
Keeping Commit Histories Clean
git remote – Atlassin git tutorials
Merging vs. Rebasing
Difference between “git add -A” and “git add .”
How to git clone a specific tag

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: