98 KiB
Flight rules for Git
ð English â Español â Ð ÑÑÑкОй â ç®äœäžæâ íêµìŽ â Tiếng Viá»t â Français
What are "flight rules"?
A guide for astronauts (now, programmers using Git) about what to do when things go wrong.
Flight Rules are the hard-earned body of knowledge recorded in manuals that list, step-by-step, what to do if X occurs, and why. Essentially, they are extremely detailed, scenario-specific standard operating procedures. [...]
NASA has been capturing our missteps, disasters and solutions since the early 1960s, when Mercury-era ground teams first started gathering "lessons learned" into a compendium that now lists thousands of problematic situations, from engine failure to busted hatch handles to computer glitches, and their solutions.
â Chris Hadfield, An Astronaut's Guide to Life.
Conventions for this document
For clarity's sake all examples in this document use a customized bash prompt in order to indicate the current branch and whether or not there are staged changes. The branch is enclosed in parentheses, and a *
next to the branch name indicates staged changes.
All commands should work for at least git version 2.13.0. See the git website to update your local git version.
Table of Contents generated with DocToc
- Repositories
- Editing Commits
- What did I just commit?
- I wrote the wrong thing in a commit message
- I committed with the wrong name and email configured
- I want to remove a file from the previous commit
- I want to delete or remove my last commit
- Delete/remove arbitrary commit
- I tried to push my amended commit to a remote, but I got an error message
- I accidentally did a hard reset, and I want my changes back
- I accidentally committed and pushed a merge
- I accidentally committed and pushed files containing sensitive data
- I want to remove a large file from ever existing in repo history
- I need to change the content of a commit which is not my last
- Staging
- I want to stage all tracked files and leave untracked files
- I need to add staged changes to the previous commit
- I want to stage part of a new file, but not the whole file
- I want to add changes in one file to two different commits
- I staged too many edits, and I want to break them out into a separate commit
- I want to stage my unstaged edits, and unstage my staged edits
- Unstaged Edits
- I want to move my unstaged edits to a new branch
- I want to move my unstaged edits to a different, existing branch
- I want to discard my local uncommitted changes (staged and unstaged)
- I want to discard specific unstaged changes
- I want to discard specific unstaged files
- I want to discard only my unstaged local changes
- I want to discard all of my untracked files
- I want to unstage a specific staged file
- Branches
- I want to list all branches
- Create a branch from a commit
- I pulled from/into the wrong branch
- I want to discard local commits so my branch is the same as one on the server
- I committed to master instead of a new branch
- I want to keep the whole file from another ref-ish
- I made several commits on a single branch that should be on different branches
- I want to delete local branches that were deleted upstream
- I accidentally deleted my branch
- I want to delete a branch
- I want to delete multiple branches
- I want to rename a branch
- I want to checkout to a remote branch that someone else is working on
- I want to create a new remote branch from current local one
- I want to set a remote branch as the upstream for a local branch
- I want to set my HEAD to track the default remote branch
- I made changes on the wrong branch
- Rebasing and Merging
- Stash
- Finding
- Submodules
- Miscellaneous Objects
- Tracking Files
- I want to change a file name's capitalization, without changing the contents of the file
- I want to overwrite local files when doing a git pull
- I want to remove a file from Git but keep the file
- I want to revert a file to a specific revision
- I want to list changes of a specific file between commits or branches
- I want Git to ignore changes to a specific file
- Debugging with Git
- Configuration
- I've no idea what I did wrong
- Git Shortcuts
- Other Resources
ãªããžããª
ããŒã«ã«ãªããžããªãåæåããã
æ¢åã®ãã£ã¬ã¯ããªã Git ãªããžããªãšããŠåæåããã«ã¯ã次ãå®è¡ããŸãïŒ
(my-folder) $ git init
ãªã¢ãŒããªããžããªãã¯ããŒã³ããã
ãªã¢ãŒããªããžããªãã¯ããŒã³ïŒã³ããŒïŒããããšãã¯ããªããžããªã® URL ãã³ããŒãã次ãå®è¡ããŸãïŒ
$ git clone [url]
ãããšããªã¢ãŒããªããžããªãšååã®ãã©ã«ãã«ãªããžããªã®å 容ãä¿åãããŸãã ãªã¢ãŒããªããžããªã®ãããµãŒãã«æ¥ç¶ã§ããå¿ èŠããããŸãã倧æµã®å Žåã€ã³ã¿ãŒãããæ¥ç¶ãããã°å€§äžå€«ã§ãã
ãªã¢ãŒããªããžããªãšç°ãªãååã®ãã©ã«ãã«ã¯ããŒã³ããããšãã¯ã次ã®ããã«ããŸãïŒ
$ git clone [url] name-of-new-folder
ééã£ããªã¢ãŒããªããžããªãèšå®ããŠããŸã£ã
åé¡ã¯ããã€ãã®å Žåã«åããããŸãã
ééã£ããªããžããªãã¯ããŒã³ããŠããŸã£ããšãã¯ãgit clone
ã§äœã£ããã£ã¬ã¯ããªãåé€ããŠãæ£ãããªããžããªãã¯ããŒã³ãçŽãã°ããã§ãã
ééã£ããªããžããªãæ¢åã®ããŒã«ã«ãªããžããªã® origin ã«èšå®ããŠããŸã£ããšãã¯ã次ã®ããã« origin ã® URL ãå€æŽããŸãããïŒ
$ git remote set-url origin [url of the actual repo]
ã»ãã®åé¡ã®å Žåã¯ããã® StackOverflow ãããã¯ãåç §ããŠã¿ãŠãã ããã
ä»ã®äººã®ãªããžããªã«ã³ãŒããæžãå ããã
Git ã§ã¯ãã¢ã¯ã»ã¹æš©ããªããšä»ã®äººã®ãªããžããªã«æžã蟌ãããšã¯ã§ããŸãããGitHub 㯠Git ãªããžããªã®ãã¹ãã£ã³ã°ãµãŒãã¹ã§ãã£ãŠ Git èªäœãšã¯ç°ãªããã®ã§ãããGitHub ã§ããã¯ãåæ§ã§ãããããããããã«ãã£ãŠã³ãŒããææ¡ããããšãã§ããŸããGitHub ãªããã©ãŒã¯ãšãã«ãªã¯ãšã¹ãã®æ©èœãããã«ããããŸãã
ãŸãã¯ãã©ãŒã¯ã«ã€ããŠèª¬æããŸãããããã©ãŒã¯ã¯ãªããžããªã®ã³ããŒã§ããGit èªäœã®æ©èœã§ã¯ãªããã®ã®ãGitHub, BitBucket, GitLab ããã®ä»ã®ãã¹ãã£ã³ã°ãµãŒãã¹ã«ã¯ãã®æ©èœããããåãµãŒãã¹ã® UI ãéããŠå®è¡ã§ããŸãã
ãã«ãªã¯ãšã¹ãã§ã³ãŒããææ¡ããã«ã¯
ãªããžããªããã©ãŒã¯ããããããŒã«ã«ãã·ã³ã«ã¯ããŒã³ããŠç·šéããŸããããã¡ãã£ãšããç·šéãªã GitHub äžã§ãã§ããã§ããããããã®ææžã¯ GitHub ãã©ã€ãã«ãŒã«ã§ã¯ãªãã®ã§ãããŒã«ã«ã§ç·šéããæ¹æ³ã説æããŸãã
# ssh ã䜿ãå Žå
$ git clone git@github.com:k88hudson/git-flight-rules.git
# https ã䜿ãå Žå
$ git clone https://github.com/k88hudson/git-flight-rules.git
ã§ãããã£ã¬ã¯ããªã« cd
ã§ç§»åããgit remote
ãå®è¡ããŠãã ããããªã¢ãŒãã®ãªã¹ãã衚瀺ãããã¯ãã§ãã
ãã ããããã衚瀺ãããã®ã¯ k88hudson/git-flight-rules
ãåç
§ãã origin
ã ããªã®ã§ãèªåããã©ãŒã¯ããŠäœã£ãæ¹ã®ãªã¢ãŒããçšæããå¿
èŠããããŸãã
Git ã§ã¯ãèªåèªèº«ã®ãªããžããªã®ãªã¢ãŒãã«ã¯ origin
ããã©ãŒã¯ããå
ã®ãªããžããªã¯ upstream
ãšåä»ããã®ãäžè¬çã§ããããã«ãªãã£ãŠããŸãããªã¢ãŒã origin
ã®ååã upstream
ã«å€æŽããŸãããïŒ
$ git remote rename origin upstream
å®ã¯ git remote set-url
ã§ãåãããšãã§ããŸãããæéãšæéãäœèšã«ããããŸãã
次ã«ãèªåã®ãããžã§ã¯ããåç §ããæ°ãããªã¢ãŒããäœæããŸãã
$ git remote add origin git@github.com:YourName/git-flight-rules.git
ãã®æç¹ã§ãªã¢ãŒãã¯äºã€ã§ãïŒ
origin
ã¯èªåã®ãªããžããªãåç §ããŠããŸããupstream
ã¯å ã®ãªããžããªãåç §ããŠããŸãã
origin
ã¯èªã¿åãã»æžã蟌ã¿ã®äž¡æ¹ãã§ããupstream
ã¯èªã¿åãå°çšã§ãã
ç·šéãæžãã ããç·šéå
容ãïŒéåžžã¯ãã©ã³ãå
ããïŒãªã¢ãŒã origin
ã«ããã·ã¥ããŸãããã
ãã©ã³ãå
ã«ããå Žåã次ã®ããã« --set-upstream
ã䜿ããšã次åããåããã©ã³ãããããã·ã¥ããéã«ãªã¢ãŒããæå®ããã«æžã¿ãŸãïŒ
$ (feature/my-feature) git push --set-upstream origin feature/my-feature
Git 㧠CLI ãããã«ãªã¯ãšã¹ããéãæ¹æ³ã¯ãããŸããïŒhub ã®ãããªããŒã«ã䜿ãã°å¥ã§ããïŒã ãã«ãªã¯ãšã¹ããéããããšãã¯ãGitHubïŒãããã¯ä»ã®ãã¹ãã£ã³ã°ãµãŒãã¹ïŒäžã§ãã«ãªã¯ãšã¹ããäœæããŠãã ãããå ã®ãªããžããªãšãã©ãŒã¯ãããªããžããªãé¢é£ä»ããã®ã¯ãã¹ãã£ã³ã°ãµãŒãã¹ãèªåçã«ããŠãããŸãã
ãã«ãªã¯ãšã¹ãã®åŸãã³ãŒãã¬ãã¥ãŒã®ãã£ãŒãããã¯ã«å¯Ÿå¿ããã®ãå¿ããªãããã«ããŸãããã
ãã©ãŒã¯ãããªããžããªããå ã®ãªããžããªã®ææ°çã«åãããŠæŽæ°ããã
ãã®ãã¡ upstream
ãªããžããªãæŽæ°ãããèªåã® origin
ã«ãã«ããããªããããããŸããã
èªåã ãã§ãªãä»ã®äººãå
±åäœæ¥ããŠããããšãå¿ããªãããã«ããŠãã ããã
èªåã®ãã£ãŒãã£ãŒãã©ã³ãã«ããŠããããå
ã®ãªããžããªã«åãããŠæŽæ°ãããå Žåãæ³å®ããŸãã
å
ã®ãããžã§ã¯ããåç
§ãããªã¢ãŒãã¯èšå®ããŠãããŸããïŒããŸã ãªãä»ãã£ãŠããŸããŸããããéåžžã¯ãªã¢ãŒãã®ååã« upstream
ã䜿ããŸãïŒ
$ (master) git remote add upstream <link-to-original-repository>
# $ (master) git remote add upstream git@github.com:k88hudson/git-flight-rules.git
ãã㧠upstream
ããææ°çããã§ããã§ããããã«ãªããŸããã
$ (master) git fetch upstream
$ (master) git merge upstream/master
# ã³ãã³ãäžã€ã§ãã§ãã
$ (master) git pull upstream master
ã³ãããã®ç·šé
äœãã³ããããããããããªããªã£ã
äœãèãã git commit -a
ã§ç·šéãã³ãããããŠããŸãããã®å
容ãããããªããšããŸãã
çŸåšã® HEAD ã®ææ°ã®ã³ãããå
容ã¯æ¬¡ã®ããã«è¡šç€ºã§ããŸãïŒ
(master)$ git show
ãããã¯ïŒ
$ git log -n1 -p
ç¹å®ã®ã³ãããã«ããããã¡ã€ã«ã®äžèº«ãèŠãããšãã¯æ¬¡ã®ããã«ããŸãïŒ<commitid>
ã¯èŠããã³ãããïŒïŒ
$ git show <commitid>:filename
ã³ãããã¡ãã»ãŒãžã«ééã£ãå 容ãæžããŠããŸã£ã
ã³ãããã¡ãã»ãŒãžã«ééã£ãå 容ãæžããŠããŸã£ããšããŸãã ã³ãããããŸã ããã·ã¥ãããŠããªãå Žåã¯ã次ã®ããã«ããŠç·šéå 容ã¯å€ããã«ã³ãããã¡ãã»ãŒãžãç·šéã§ããŸãïŒ
$ git commit --amend --only
ããã©ã«ãã®ããã¹ããšãã£ã¿ãéããã³ãããã¡ãã»ãŒãžãç·šéã§ããŸããããããäžã€ã®ã³ãã³ãã§ãã£ãºãã«ããããšãã§ããŸãïŒ
$ git commit --amend --only -m 'xxxxxxx'
æ¢ã«ã³ããããããã·ã¥ããŠããŸã£ãå Žåãã³ããããä¿®æ£ããŠåŒ·å¶ããã·ã¥ããããšã¯ã§ããŸãããããããããŸããã
ééã£ãååã»ã¡ãŒã«ã¢ãã¬ã¹ã®èšå®ã§ã³ãããããŠããŸã£ã
ã³ããããäžã€ã ããªãã次ã®ããã«ä¿®æ£ããŸãã
$ git commit --amend --no-edit --author "New Authorname <authoremail@mydomain.com>"
ãããã¯ãååãšã¡ãŒã«ã¢ãã¬ã¹ã git config --global author.(name|email)
ã§æ£ããèšå®ããŠããã次ã®ããã«ããŸãïŒ
$ git commit --amend --reset-author --no-edit
å±¥æŽãã¹ãŠã«ã€ããŠå€æŽãããå Žåã¯ãgit filter-branch
ã® man ããŒãžãåç
§ããŠãã ããã
çŽåã®ã³ããããããã¡ã€ã«ãåé€ããã
çŽåã®ã³ãããããç¹å®ã®ãã¡ã€ã«ã®ç·šéå 容ãåé€ããã«ã¯æ¬¡ã®ããã«ããŸãã
$ git checkout HEAD^ myfile
$ git add myfile
$ git commit --amend --no-edit
çŽåã®ã³ãããã§æ°ãã«è¿œå ãããã¡ã€ã«ãïŒGit ã®ã¿ããïŒåé€ããããšãã¯æ¬¡ã®éãã§ãã
$ git rm --cached myfile
$ git commit --amend --no-edit
ãã®ã³ãã³ãã¯ããããã«äžèŠãªãã¡ã€ã«ãã³ãããããŠããŸãã匷å¶ããã·ã¥ã§ãªã¢ãŒãã®ããããæŽæ°ããããšãã«ç¹ã«äŸ¿å©ã§ãã
ãªãã·ã§ã³ --no-edit
ã¯æ¢ã«ããã³ãããã¡ãã»ãŒãžãå€æŽããªãããã«ããããã®ãã®ã§ãã
çŽåã®ã³ããããåé€ããã
æ¢ã«ããã·ã¥ããã³ããããåé€ããã«ã¯æ¬¡ã®ããã«ããŸãã ãã ããç·šéå±¥æŽãäžå¯éçã«å€æŽããããªããžããªããå€æŽå 容ããã«ããŠããŸã£ãä»ã®äººã®ç·šéå±¥æŽã¯æ» è¶èŠè¶ã«ãªããŸãã èŠããã«ãããããããªãå Žåã¯çµ¶å¯Ÿã«ããªãã§ãã ããã
$ git reset HEAD^ --hard
$ git push --force-with-lease [remote] [branch]
ãŸã ã³ããããããã·ã¥ããŠããªãå Žåã¯ã次ã®ããã«ããŠïŒã¹ããŒãžãããç·šéã¯ãã®ãŸãŸã§ïŒçŽåã®ã³ããããããåã®ç¶æ ã« Git ããªã»ããã§ããŸãã
(my-branch*)$ git reset --soft HEAD@{1}
ããã¯ããã·ã¥ããŠããªãå Žåã«ã®ã¿æå¹ãªæ¹æ³ã§ãã
ããã·ã¥ããŠããŸã£ãå Žåãæ¬åœã«å®å
šãªæ¹æ³ã¯ git revert SHAofBadCommit
ã ãã§ãã
ãã®ã³ãã³ãã¯ãçŽåã®ã³ããããåãæ¶ããããªã³ããããæ°ãã«äœæããŸãã
ããã·ã¥ãããã©ã³ãããªããŒã¹ã«ã€ããŠå®å
šã§ããå ŽåïŒã€ãŸããä»ã®éçºè
ããã«ããããšãæ³å®ããŠããªãå ŽåïŒã¯ãgit push --force-with-lease
ã䜿ã£ãŠã倧äžå€«ã§ãã
ä»»æã®ã³ããããåé€ããã
äžã§è¿°ã¹ãã®ãšåæ§ã«ããããåŸãªãå Žå以å€çµ¶å¯Ÿã«è¡ããªãã§ãã ããã
$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT
$ git push --force-with-lease [remote] [branch]
ããã㯠察話ç rebase ã§åé€ãããã³ãããã«å¯Ÿå¿ããè¡ãéžæããŠåé€ããŸãã
ä¿®æ£ããã³ãããããªã¢ãŒãã«ããã·ã¥ããããšãããããšã©ãŒã¡ãã»ãŒãžãåºã
To https://github.com/yourusername/repo.git
! [rejected] mybranch -> mybranch (non-fast-forward)
error: failed to push some refs to 'https://github.com/tanay1337/webmaker.org.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.
amend ã«ããä¿®æ£ã¯ãrebase ãšåæ§ã«ïŒåŸè¿°ïŒãå€ãã³ããããæ°ããªã³ãããã§çœ®ãæããŸãããããããä¿®æ£åã®ã³ããããæ¢ã«ãªã¢ãŒãã«ããã·ã¥ããŠããŸã£ãŠããå Žåã¯ã匷å¶ããã·ã¥ (--force-with-lease
) ããªããã°ãããŸããã
匷å¶ããã·ã¥ã«ã¯çŽ°å¿ã®æ³šæãå¿
èŠã§ããå¿
ããã©ã³ããæå®ããããã«ïŒ
(my-branch)$ git push origin mybranch --force-with-lease
äžè¬è«ãšããŠã匷å¶ããã·ã¥ã¯é¿ããŸããããä¿®æ£ããã³ãããã匷å¶ããã·ã¥ããããã¯ãæ°ããªã³ããããäœã£ãŠããã·ã¥ããã®ããã¹ãã§ãã
匷å¶ããã·ã¥ã¯ã察象ã®ãã©ã³ãããã®åãã©ã³ãã§äœæ¥ããä»ã®éçºè
ã®ãœãŒã¹å±¥æŽã«éœéœ¬ãããããŠããŸããŸãã
誰ããåããã©ã³ãã§äœæ¥ããŠããŠã匷å¶ããã·ã¥ããã®äººã®ç·šéãäžæžãããŠããŸãå Žåã«ã¯ã--force-with-lease
ã倱æããŸãã
ä»ã®èª°ãåããã©ã³ãã§äœæ¥ããŠããªãããšã絶察ã«ç¢ºå®ãªå Žåããããã¯ãã©ã³ãã®äžéšãç¡æ¡ä»¶ã§æŽæ°ãããå Žå㯠--force
(-f
) ã§è¡ãããšãã§ããŸãããããã¯ååçã«é¿ããã¹ãã§ãã
ééã㊠hard reset ããŠããŸããå ã«æ»ããã
ééã㊠git reset --hard
ãããŠããŸã£ãå Žåã§ãã倧æµã¯ã³ãããã埩å
ã§ããŸããGit ã¯æ°æ¥éã®ãã°ãå
šãŠæ®ããŠãããŠããããã§ãã
泚æïŒããã¯äœæ¥ãããã¯ã¢ãããããŠããå Žåãã€ãŸãã³ããããã¹ã¿ãã·ã¥ãããŠããå Žåã®ã¿ã§ããgit reset --hard
ã¯ã³ããããããŠããªãå€æŽã_åé€_ããŠããŸãã®ã§ã泚æããŠäœ¿ã£ãŠãã ãããïŒå®å
šãªã®ã¯ git reset --keep
ã䜿ãããšã§ããïŒ
(master)$ git reflog
éå»ã®ã³ããããšãªã»ããã®ã³ãããã衚瀺ãããã®ã§ã埩å ãããã³ãããã® SHA ãéžãã§ãªã»ããããŸãïŒ
(master)$ git reset --hard SHA1234
ããã§å€§äžå€«ã§ãã
ééããŠããŒãžãã³ãããããŠããã·ã¥ããŠããŸã£ã
ãã£ãŒãã£ãŒãã©ã³ããããŒãžã®æºåãæŽãåã«ééããŠã¡ã€ã³ã®ãã©ã³ãã«ããŒãžããŠããŸã£ãå ŽåãããŒãžãåãæ¶ãããšãã§ããŸãã ãã ãèœãšãç©ŽããããŸãïŒããŒãžã³ãããã«ã¯è€æ°ïŒéåžžã¯äºã€ïŒã®èŠªããããŸãã
次ã®ã³ãã³ããå®è¡ããŸãã
(feature-branch)$ git revert -m 1 <commit>
ããã§ãªãã·ã§ã³ -m 1
ã¯èŠª 1ïŒããŒãžããå
ã®ãã©ã³ãïŒãå·®ãæ»ãå
ã®èŠªã«æå®ãããã®ã§ãã
泚æïŒèŠªã®çªå·ã¯ã³ããã ID ã§ã¯ãããŸãããããŒãžã³ãããã®è¡ã«ã¯ Merge: 8e2ce2d 86ac2e7
ã®ããã«æžãããŠããŸãã芪çªå·ã¯ãã®ã³ãããã«ãããŠèŠªãæå®ããããã® 1 ããå§ãŸãçªå·ã§ãæåã®çªå·ã¯ 1 çªã次㯠2 çªãã®ããã«æ¯ãããŸãã
ééããŠæ©å¯æ å ±ãå«ããã¡ã€ã«ãã³ããããããã·ã¥ããŠããŸã£ã
æ©å¯æ å ±ããã©ã€ããŒããªæ å ±ïŒãã¹ã¯ãŒããããŒçïŒãå«ãããŒã¿ã誀ã£ãŠããã·ã¥ããŠããŸã£ãå Žåãã³ããããä¿®æ£ããããšãã§ããŸãã ãã ããã²ãšãã³ããŒã¿ãã³ãããããŠããã·ã¥ããŠããŸã£ããããã®å 容ã¯çã¿åãããæããããããšã«çæããŠãã ããã 以äžã®æé ã§ãããªãã¯ãªããžããªãããŒã«ã«ããããŒã¿ãåé€ããããšã¯ã§ããŸãããä»ã®èª°ããæ¢ã«ãã«ããŠããŸã£ãããŒã¿ãåé€ããããšã¯äžå¯èœã§ãã ãã¹ã¯ãŒããã³ãããããŠããŸã£ãå Žåã¯çŽã¡ã«å€æŽããŠãã ãããããŒãã³ãããããŠããŸã£ãå Žåã¯çŽã¡ã«åçæããŸãããã 誰ããæ¢ã«æ©å¯æ å ±ããã«ããŠããŸã£ãå¯èœæ§ãããéããããã·ã¥ããã³ããããä¿®æ£ããã ãã§ã¯äžååã§ãã
ãã¡ã€ã«ãç·šéããŠæ©å¯æ å ±ãåé€ããããšã次ãå®è¡ããŸãã
(feature-branch)$ git add edited_file
(feature-branch)$ git commit --amend --no-edit
(feature-branch)$ git push --force-with-lease origin [branch]
ãã¡ã€ã«ããšåé€ããããããŒã«ã«ã«ã¯æ®ããŠããããå Žåã次ãå®è¡ããŸãã
(feature-branch)$ git rm --cached sensitive_file
echo sensitive_file >> .gitignore
(feature-branch)$ git add .gitignore
(feature-branch)$ git commit --amend --no-edit
(feature-branch)$ git push --force-with-lease origin [branch]
ãããã¯ãæ©å¯æ å ±ãããŒã«ã«ã®ç°å¢å€æ°ã«ä¿åããŠãããŸãããã
ãã¡ã€ã«ããšåé€ããäžã§ããŒã«ã«ãããåé€ãããå Žåã¯ã次ãå®è¡ããŸãã
(feature-branch)$ git rm sensitive_file
(feature-branch)$ git commit --amend --no-edit
(feature-branch)$ git push --force-with-lease origin [branch]
ä»ã®ã³ããããæ¢ã«ããŠããŸã£ãŠããå ŽåïŒã€ãŸããæ©å¯æ å ±ã®ã³ããããçŽåã®ã³ãããããã以åã§ããå ŽåïŒã¯ããªããŒã¹ããå¿ èŠããããŸãã
倧容éã®ãã¡ã€ã«ã«é¢ããå±¥æŽãå®å šã«åé€ããã
åé€ããããã¡ã€ã«ãæ©å¯æ å ±ã§ããå Žåã¯æ©å¯æ å ±ãåé€ããæ¹æ³ãåç §ããŠãã ããã
æè¿ã®ã³ãããã§å€§å®¹éã®ãã¡ã€ã«ãäžèŠãªãã¡ã€ã«ãåé€ããŠãã.git
ãã©ã«ãã«ãã Git ã®å±¥æŽã«ã¯æ®ã®ã§ãgit clone
ãããšãã«äœèšãªãã¡ã€ã«ãŸã§ããŠã³ããŒãããŠããŸãããšã«ãªããŸãã
Even if you delete a large or unwanted file in a recent commit, it still exists in git history, in your repo's .git
folder, and will make git clone
download unneeded files.
ããã§èª¬æããæé ã«ã¯åŒ·å¶ããã·ã¥ãå¿ èŠãšãããªããžããªå±¥æŽã倧ããå€æŽããŠããŸããŸãããªã¢ãŒãã§å ±åäœæ¥ããŠãã人ãããå Žåã¯ãå šå¡ã®ããŒã«ã«ãªç·šéå±¥æŽãããã·ã¥ãããŠããããšããŸã確èªããŠãããŠãã ããã
The actions in this part of the guide will require a force push, and rewrite large sections of repo history, so if you are working with remote collaborators, check first that any local work of theirs is pushed.
å±¥æŽãæžãæããã®ã«ã¯äºã€ã®æ¹æ³ããããŸãããã«ãã€ã³ã® git-filter-branch
ãš bfg-repo-cleaner
ã§ãã
bfg
ã¯ãšã¬ã¬ã³ãã§æ§èœãããäžæ¹ããµãŒãããŒãã£è£œã®ãœãããããŠã³ããŒãããªããã°ãªãããJava ãå¿
èŠã§ãã
ããã§ã¯äž¡æ¹ã®æ¹æ³ã説æããŸãã
æåŸã®ã¹ãããã§ã¯åŒ·å¶ããã·ã¥ãããŸããããªããžããªã®å±¥æŽã®å€§éšåãæ°žä¹
ã«å€æŽããŠããŸããããéåžžã®åŒ·å¶ããã·ã¥ããããªãç¹æ®ãªé
æ
®ãå¿
èŠã«ãªããŸãã
ããããã®æ¹æ³ïŒãµãŒãããŒãã£è£œã® bfg ã䜿ã
bfg-repo-cleaner ã䜿ãã«ã¯ Java ãå¿
èŠã§ãããããã bfg ã® jar ãã¡ã€ã«ãããŠã³ããŒãããŠãã ããã
以äžã®äŸã§ã¯ bfg.jar
ã䜿ããŸãããããŠã³ããŒããããã®ã«ã¯ bfg-1.13.0.jar
ã®ããã«ããŒãžã§ã³çªå·ãã€ããŠãããããããŸããã
ç¹å®ã®ãã¡ã€ã«ãåé€ããå Žåã¯æ¬¡ã®ããã«ããŸãã
(master)$ git rm path/to/filetoremove
(master)$ git commit -m "Commit removing filetoremove"
(master)$ java -jar ~/Downloads/bfg.jar --delete-files filetoremove
bfg ã䜿ããšãã¯ããã¡ã€ã«ããµããã£ã¬ã¯ããªã«ãããšãããã®ãŸãŸã®ãã¡ã€ã«åãå ¥åããããšã«æ³šæããŠãã ããã
ãã¿ãŒã³ãããã¡ã€ã«ãåé€ããããšãã§ããŸããäŸãã°ïŒ
(master)$ git rm *.jpg
(master)$ git commit -m "Commit removing *.jpg"
(master)$ java -jar ~/Downloads/bfg.jar --delete-files *.jpg
bfg ã¯ææ°ã®ã³ãããã«ãããã¡ã€ã«ã«ã¯åœ±é¿ããŸãããäŸãã°ããªããžããªã«è€æ°ãã£ã倧容éã® .tga ãã¡ã€ã«ã®ãã¡äžéšã以åã®ã³ãããã§åé€ãããšããŠãbfg ãå®è¡ããŠãææ°ã®ã³ãããã«ãããã¡ã€ã«ã¯ãã®ãŸãŸã§ãã
ãªããã³ãããã§ãã¡ã€ã«åãå€æŽããå ŽåãäŸãã°ããšããš LargeFileFirstName.mp4
ã ã£ããã¡ã€ã«ãåŸã®ã³ããã㧠LargeFileSecondName.mp4
ã«å€æŽãããŠããå Žåã¯ãjava -jar ~/Downloads/bfg.jar --delete-files LargeFileSecondName.mp4
ãå®è¡ããŠã Git ã®å±¥æŽããã¯åé€ãããŸãããäž¡æ¹ã®ãã¡ã€ã«åããããã«ã€ã㊠--delete-files
ãå®è¡ãããããã¿ãŒã³ãããã§äž¡æ¹åé€ããŠãã ããã
ãã«ãã€ã³ã®æ¹æ³ïŒgit-filter-branch ã䜿ã
git-filter-branch
ã¯ããããããŠæ©èœã貧匱ã§ãããbfg
ã®ã€ã³ã¹ããŒã«ãå®è¡ãã§ããªããŠã䜿ããŸãã
以äžã§ã¯ãfilepattern
ãååããã¿ãŒã³ïŒ*.jpg
ãªã©ïŒã«çœ®ãæããŠãã ããããã¿ãŒã³ã«ããããããã¡ã€ã«ã®å±¥æŽãå
šãŠã®å±¥æŽãšãã©ã³ãããåé€ãããŸãã
(master)$ git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch filepattern' --prune-empty --tag-name-filter cat -- --all
äœãããŠããã®ãïŒ
--tag-name-filter cat
ã¯ç
©éã§ããããããæãç°¡åã«å
ã®ã¿ã°ãæ°ããã³ãããã«ã€ãã cat
ã䜿ã£ãæ¹æ³ã§ãã
--prune-empty
ã¯çŸåšç©ºã®ã³ããããå
šãŠåé€ããŸãã
æåŸã®ã¹ããã: å€æŽããå±¥æŽãããã·ã¥ãã
ãã¡ã€ã«ãåé€ãããããªããžããªã®ãã®ãå£ããŠããŸã£ãŠããªããæ éã«ç¢ºèªããŠãã ããã äœãå£ããŠããŸã£ãå Žåã¯ããªããžããªãå床ã¯ããŒã³ããŠããçŽãã®ãæãç°¡åã§ãã æåŸã®ã¹ããããšããŠãå¿ èŠã«å¿ã㊠Git ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã§ .git ãã©ã«ãã®å®¹éãæå°åããŠããã匷å¶ããã·ã¥ããŸãã
(master)$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
(master)$ git push origin --force --tags
ãªããžããªã®å±¥æŽããã¹ãŠæžãæããŠããã®ã§ãgit push
ã®éãèšå€§ãã㊠âThe remote end hung up unexpectedlyâ
ãšãããšã©ãŒãè¿ããããããŸããããã®å Žå㯠Git ã® post buffer ãå¢ãããŠã¿ãŸãã
(master)$ git config http.postBuffer 524288000
(master)$ git push --force
ããŸããããªãå Žåã¯ãã³ããããæäœæ¥ã§å°åãã«ããŠããã·ã¥ããŸãã
ããã·ã¥ãæåãããŸã§ã<number>
ãå¢ãããªãã次ã®ã³ãã³ããè©ŠããŠãã ããã
(master)$ git push -u origin HEAD~<number>:refs/head/master --force
ããã·ã¥ãæåã«æåããããéåžžã®git push
ã æåãããŸã§ <number>
ãåŸã
ã«æžãããŠãã ããã
çŽè¿ã§ãªãã³ãããã®å 容ãç·šéããã
è€æ°ïŒããšãã°äžä»¶ïŒã®ã³ããããè¡ã£ãããšãæèçã«æåã®ã³ãããã«å±ããäœæ¥ããå¿ããããšã«æ°ã¥ãããšããŸãã
ãã®äœæ¥ãæ°ããªã³ããããšããŠè¡ãã°ã³ãŒãããŒã¹ã¯ç¶ºéºã«ä¿ãŠããã®ã®ãã³ããããã¢ãããã¯ã§ãªããªã£ãŠããŸãïŒåãæèã®äœæ¥ãåãã³ãããã«å±ããªãïŒã®ã§ããã®ç¶æ³ã¯åä»ã§ãã
ãå¿ããäœæ¥ãå±ããã¹ãã³ããããç·šéããäœæ¥ãåãå
¥ãã€ã€ããã®åŸã®ã³ãããã«ã¯æãã€ããªãããã«ããããšããgit rebase
ã圹ã«ç«ã¡ãŸãã
æåŸããäžä»¶ç®ã®ã³ããããç·šéããããšããŸãã
(your-branch)$ git rebase -i HEAD~4
äžã®ã³ãã³ãã§å¯Ÿè©±çãªããŒã¹ã¢ãŒãã«å ¥ããçŽè¿äžä»¶ã®ã³ããããç·šéã§ããããã«ãªããŸãã ããã¹ããšãã£ã¿ãéãã次ã®ãããªå 容ã衚瀺ãããŸãã
pick 9e1d264 The third last commit
pick 4b6e19a The second to last commit
pick f4037ec The last commit
ããã次ã®ããã«ç·šéããŸãã
edit 9e1d264 The third last commit
pick 4b6e19a The second to last commit
pick f4037ec The last commit
ããã¯æåŸããäžä»¶ç®ã®ã³ããããç·šéãã€ã€ãä»ã®äºä»¶ã¯ãã®ãŸãŸã«ãããã rebase
ã«æ瀺ããŠããŸãã
ããã¹ããšãã£ã¿ãä¿åããŠçµäºããããGit ããªããŒã¹ãå§ããŸããæå®ããã³ãããã§æ¢ãŸãããã®ã³ããããç·šéã§ããããã«ãªããŸãã
ããã§æåã«ã³ããããããšãã«ãå¿ããäœæ¥ãé©çšã§ããŸããç·šéãšã¹ããŒãžã«ãã£ãŠé©çšããŸãããã
ãã®åŸã次ãå®è¡ããŸãã
(your-branch)$ git commit --amend
ããã¯ã³ãããã¡ãã»ãŒãžã¯ãã®ãŸãŸã§ã³ããããäœãçŽããã Git ã«æ瀺ããŠããŸãã ããã§é¢åãªäœæ¥ã¯çµããã§ãã
>(your-branch)$ git rebase --continue
ããšã¯äžãå®è¡ããã°å®äºã§ãã
ã¹ããŒãžã³ã°
ããŒãžã§ã³ç®¡çãããŠãããã¡ã€ã«ãå šéšã¹ããŒãžããã
$ git add -u
ããŒãžã§ã³ç®¡çãããŠãããã¡ã€ã«ã®äžéšãã¹ããŒãžããã«ã¯
# æ¡åŒµåã .txt ã®ãã¡ã€ã«ãã¹ããŒãžãã
$ git add -u *.txt
# src ãã£ã¬ã¯ããªå
ã®å
šãã¡ã€ã«ãã¹ããŒãžãã
$ git add -u src/
ã¹ããŒãžãããç·šéå 容ãçŽåã®ã³ãããã«è¿œå ããã
(my-branch*)$ git commit --amend
ã³ãããã¡ãã»ãŒãžãå€æŽããããªããšãã¯ãã³ãããã¡ãã»ãŒãžãåå©çšãããã Git ã«æ瀺ããŸãïŒ
(my-branch*)$ git commit --amend -C HEAD
æ°ãããã¡ã€ã«ã®å šéšã§ã¯ãªãäžéšãã¹ããŒãžããã
éåžžããã¡ã€ã«ã®äžéšãã¹ããŒãžããã«ã¯æ¬¡ãå®è¡ããŸãïŒ
$ git add --patch filename.x
ç瞮圢㯠-p
ã§ããããã«ãã察話ã¢ãŒããéããŸãã
ãªãã·ã§ã³ s
ãã€ãããšã³ããããåå² (split) ã§ããŸãããã ããæ°ããäœã£ããã¡ã€ã«ã®å Žåãã®ãªãã·ã§ã³ã¯äœ¿ããŸããã
ãã¡ã€ã«ãæ°ãã«è¿œå ããã«ã¯ã次ãå®è¡ããŸãïŒ
$ git add -N filename.x
ãªãã·ã§ã³ e
ã䜿ããšãã©ã®è¡ãè¿œå ãããæåã§éžæããããšãã§ããŸãã
git diff --cached
ããã㯠git diff --staged
ãå®è¡ãããšãã¹ããŒãžããè¡ãããŒã«ã«ã«ä¿åããããã®ãšæ¯èŒããŠè¡šç€ºãããŸãã
äžã€ã®ãã¡ã€ã«ã«å ããç·šéãäºã€ã®ç°ãªãã³ãããã«è¿œå ããã
git add
ã¯ãã¡ã€ã«å
šäœãã³ãããã«è¿œå ããŸãã
git add -p
ã䜿ããšãã©ã®ç·šéå
容ãè¿œå ããã察話çã«éžæã§ããŸãã
ã¹ããŒãžããç·šéå 容ãå€ãããã®ã§ãããã€ãã®ã³ãããã«åå²ããã
git reset -p
ãå®è¡ãããšããããã¢ãŒãã®ãªã»ãããã€ã¢ãã°ãéããŸãã
git add -p
ãšäŒŒãŠããŸããã"yes" ãã¹ããŒãžãåãæ¶ããŠæ¬¡ã®ã³ãããããé€å»ããããšãæå³ããç¹ã§ç°ãªããŸãã
ã¹ããŒãžãããŠããªãç·šéå 容ãã¹ããŒãžããã¹ããŒãžãããç·šéå 容ã®ã¹ããŒãžãåãæ¶ããã
éåžžã¯ãã¹ããŒãžããããã¡ã€ã«ã®ã¹ããŒãžã³ã°ãäžæŠå šéšåãæ¶ããããšãã³ãããããããã®ãããã¯ããã¹ãã§ãã ã¹ããŒãžãããŠããç·šéãšãããŠããªãç·šéãåãæ¿ããããšãã¯ãã¹ããŒãžãããç·šéãèšé²ããŠããä»®ã®ã³ããããäœæããã¹ããŒãžãããŠããªããã¡ã€ã«ãã¹ããŒãžããŠã¹ã¿ãã·ã¥ããŸããããããä»®ã®ã³ãããããªã»ããããŠãã¹ã¿ãã·ã¥ã pop ããŸãã
$ git commit -m "WIP"
$ git add . # ããŒãžã§ã³ç®¡çãããŠããªããã¡ã€ã«ãè¿œå ããã
$ git stash
$ git reset HEAD^
$ git stash pop --index 0
泚æ 1ïŒãã㧠pop
ã䜿ãã®ã¯ãæäœãè€æ°åè¡ã£ãŠãçµæããªãã¹ãå€ãããªãããã«ããããã§ãã
泚æ 2ïŒãã㧠--index
ãæå®ããªããšãã¹ããŒãžããããã¡ã€ã«ã¯ã¹ããŒãžãããŠããªãæ±ãã«ãªããŸãïŒçç±ã¯ãã®ãªã³ã¯ãåç
§ããŠãã ããïŒã
ã¹ããŒãžãããŠããªãç·šé
ã¹ããŒãžãããŠããªãç·šéå 容ãæ°ãããã©ã³ãã«ç§»ããã
$ git checkout -b my-branch
ã¹ããŒãžãããŠããªãç·šéå 容ãå¥ã®æ¢åã®ãã©ã³ãã«ç§»ããã
$ git stash
$ git checkout my-branch
$ git stash pop
ã³ããããããŠããªãããŒã«ã«ã®ç·šéå 容ãç Žæ£ãããïŒã¹ããŒãžãããŠããå Žåã»ãããŠããªãå ŽåïŒ
ã¹ããŒãžãããŠããç·šéå 容ãšã¹ããŒãžãããŠããªãç·šéå 容ã®äž¡æ¹ãå šãŠç Žæ£ããããšãã¯ã次ã®ããã«ããŸãïŒ
(my-branch)$ git reset --hard
# ãŸãã¯
(master)$ git checkout -f
ãã㯠git add
ã§ã¹ããŒãžããå
šãã¡ã€ã«ã®ã¹ããŒãžã³ã°ãåãæ¶ããŸãïŒ
$ git reset
ããã¯ã³ããããããŠããªãããŒã«ã«ã®ç·šéå 容ãå šãŠå·®ãæ»ããŸãïŒãªããžããªã®ã«ãŒãã§å®è¡ããå¿ èŠããããŸãïŒïŒ
$ git checkout .
ç¹å®ã®ãã¡ã€ã«ããã£ã¬ã¯ããªã«ã€ããŠã³ããããããŠããªãç·šéãå·®ãæ»ãããšãã§ããŸãïŒ
$ git checkout [some_dir|file.txt]
ã³ããããããŠããªãå šç·šéå 容ãå·®ãæ»ãã®ã«ã¯æ¬¡ã®æ¹æ³ããããŸãïŒã³ãã³ããé·ãã§ãããä»»æã®ãµããã£ã¬ã¯ããªããå®è¡ã§ããŸãïŒïŒ
$ git reset --hard HEAD
次ãå®è¡ãããšããŒã«ã«ã®ããŒãžã§ã³ç®¡çãããŠããªããã¡ã€ã«ãå šãŠåé€ãããŸããã€ãŸã Git ã«ãã£ãŠç®¡çãããŠãããã¡ã€ã«ã ãæ®ããŸãïŒ
$ git clean -fd
Git ã«ç¡èŠããããã¡ã€ã«ãå
šãŠåãé€ãã«ã¯ -x
ãæå®ããŸãã
ã¹ããŒãžãããŠããªãç¹å®ã®ç·šéå 容ãç Žæ£ããã
ã¯ãŒã¯ããªãŒäžã®ç·šéå 容ã®å šéšã§ã¯ãªãäžéšã ããç Žæ£ãããå Žåã§ãã
æ®ãããç·šéå 容ã ããæ®ããæ®ããããªãç·šéããã§ãã¯ã¢ãŠãããŸãã
$ git checkout -p
# ç Žæ£ãããã³ãŒããã¹ãŠã«ã€ã㊠y ãšçãã
ããäžã€ã®æ¹æ³ã¯ stash
ã䜿ããŸããæ®ãããç·šéå
容ãã¹ã¿ãã·ã¥ããã¯ãŒã¯ããªãŒããªã»ããããŠãæ®ãããç·šéå
容ãé©çšããŸãã
$ git stash -p
# æ®ãããã³ãŒããå
šãŠéžã¶
$ git reset --hard
$ git stash pop
ãããã¯ãæ®ããããªãç·šéå 容ãã¹ã¿ãã·ã¥ããŠãã¹ã¿ãã·ã¥å 容ãç Žæ£ããŠãããã§ãã
$ git stash -p
# æ®ããããªãã³ãŒããå
šãŠéžã¶
$ git stash drop
ã¹ããŒãžãããŠããªãç¹å®ã®ãã¡ã€ã«ãç Žæ£ããã
ã¯ãŒã¯ããªãŒã®ç¹å®ã®ãã¡ã€ã«äžã€ãåãé€ããããšãã§ãã
$ git checkout myFile
ã¯ãŒã¯ããªãŒäžã®è€æ°ã®ãã¡ã€ã«ãç Žæ£ããããšãã¯ãããããåæããŸãã
$ git checkout myFirstFile mySecondFile
ã¹ããŒãžãããŠããªãããŒã«ã«ãªç·šéå 容ã ããç Žæ£ããã
ã³ããããã¹ããŒãžããããŠããªãããŒã«ã«ã®ç·šéå 容ãå šãŠç Žæ£ãããå Žåã¯ã次ãå®è¡ããŸãã
$ git checkout .
ããŒãžã§ã³ç®¡çãããŠããªããã¡ã€ã«ãå šãŠç Žæ£ããã
ããŒãžã§ã³ç®¡çãããŠããªããã¡ã€ã«ãå šãŠç Žæ£ããããšãã¯ã次ãå®è¡ããŸãã
$ git clean -f
ç¹å®ã®ã¹ããŒãžããããã¡ã€ã«ã®ã¹ããŒãžã³ã°ãåãæ¶ããã
ééããŠã¹ããŒãžãããŠããŸã£ããã¡ã€ã«ãäžã€ãŸãã¯è€æ°ãã£ãŠããŸã ã³ããããããŠããªãå Žåã§ãã ãã®ã¹ããŒãžã³ã°ãåãæ¶ãã«ã¯æ¬¡ã®ããã«ããŸãïŒ
$ git reset -- <filename>
ãã¡ã€ã«ã®ã¹ããŒãžã³ã°ãåãæ¶ãããããŒãžã§ã³ç®¡çãããŠããªããã®ãšã¿ãªãããŸãã
ãã©ã³ã
å šãã©ã³ãã®äžèŠ§ã衚瀺ããã
ããŒã«ã«ãã©ã³ãã®äžèŠ§ã衚瀺ãã
$ git branch
ãªã¢ãŒããã©ã³ãã®äžèŠ§ã衚瀺ãã
$ git branch -r
ããŒã«ã«ãšãªã¢ãŒãäž¡æ¹ã®ãã©ã³ãã®äžèŠ§ã衚瀺ãã
$ git branch -a
ã³ããããããã©ã³ããäœæãã
$ git checkout -b <branch> <SHA1_OF_COMMIT>
ééã£ããã©ã³ãããããããã¯ééã£ããã©ã³ãã«ãã«ããŠããŸã£ã
åã³ git reflog
ã䜿ãå Žé¢ã§ããééã£ããã«ã®ä»¥åã« HEAD ãåç
§ããŠãããã®ã衚瀺ããŸãã
(master)$ git reflog
ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward
c5bc55a HEAD@{1}: checkout: checkout message goes here
åã«ãã©ã³ããé©åãªã³ãããã«ãªã»ããããã ãã§ãïŒ
$ git reset --hard c5bc55a
ããã§å®äºã§ãã
ããŒã«ã«ã®ã³ããããç Žæ£ããŠããã©ã³ãããµãŒãäžã®ç¶æ ãšåãã«ããã
ãµãŒãã«ç·šéå 容ãããã·ã¥ããŠããªãããšã確èªããŠãã ããã
git status
ãå®è¡ãããšãèªåã origin ã«å¯ŸããŠäœã³ãããåäœæ¥ãé²ããã®ã衚瀺ãããŸãã
(my-branch)$ git status
# On branch my-branch
# Your branch is ahead of 'origin/my-branch' by 2 commits.
# (use "git push" to publish your local commits)
#
origin ãšåãç¶æ ã«ãªã»ããããïŒãªã¢ãŒããšåãç¶æ ã«ããïŒæ¹æ³ã®äžã€ã¯æ¬¡ã®éãã§ãïŒ
(master)$ git reset --hard origin/my-branch
æ°ãããã©ã³ãã§ã¯ãªããã¹ã¿ãŒãã©ã³ãã«ã³ãããããŠããŸã£ã
ãã¹ã¿ãŒãã©ã³ãã«ãããŸãŸãæ°ãããã©ã³ããäœæããŠãã ããïŒ
(master)$ git branch my-branch
ãã¹ã¿ãŒãã©ã³ããçŽåã®ã³ãããã«ãªã»ããããŸãïŒ
(master)$ git reset --hard HEAD^
HEAD^
㯠HEAD^1
ã®ç瞮圢ã§ãHEAD
ã®äžçªç®ã®èŠªãè¡šããŸããåæ§ã« HEAD^2
ã¯äºçªç®ã®èŠªãè¡šããŸãïŒããŒãžã«ã¯èŠªãäºã€ãããŸãïŒã
HEAD^2
㯠HEAD~2
ãšç°ãªãããšã«æ³šæããŠãã ããïŒè©³ããã¯ãã®ãªã³ã¯ãåç
§ããŠãã ããïŒã
ããã㯠HEAD^
ã䜿ããããªããã°ããã¹ã¿ãŒãã©ã³ããå·®ãæ»ãããå
ã®ã³ãããããã·ã¥ãæ¢ããŸãïŒgit log
ã圹ç«ã¡ãŸãïŒã
èŠã€ãããããã®ããã·ã¥ã«ãªã»ããããŸããããšã¯ git push
ããã°ãã®çµæããªã¢ãŒãã«åæ ãããã¯ãã§ãã
äŸãã°ããã¹ã¿ãŒãã©ã³ããå·®ãæ»ãã¹ãã³ãããã®ããã·ã¥ã a13b85e
ã ãšããŠã次ã®ããã«ããŸãïŒ
(master)$ git reset --hard a13b85e
HEAD is now at a13b85e
äœæ¥ã«æ»ããããæ°ãããã©ã³ãã«ãã§ãã¯ã¢ãŠãããŸãããïŒ
(master)$ git checkout my-branch
ãã¡ã€ã«å šãŠããªãã¡ã¬ã³ã¹çãªå Žæã«ä¿åããŠãããã
ã¯ãŒãã³ã°ã¹ãã€ã¯ïŒã¡ã¢ãåç §ïŒã«ããããç·šéå 容ããã£ãŠããã¹ãŠããŸãæ©èœããŠãããã®ãšããŸãã ãã®äœæ¥å 容ãä¿åããŠãããããå¥ã®ãã©ã³ãã«ã³ãããããŸãã
(solution)$ git add -A && git commit -m "Adding all changes from this spike into one big commit."
ãã®å
容ããã©ã³ãïŒãã£ãŒãã£ãŒãã©ã³ãã§ã develop
ã§ãïŒã«é©çšããããšãã¯ããã¡ã€ã«å
šéšãä¿åããŠããããã¯ãã§ãã
倧ããªã³ããããå°ããªã³ãããã«åå²ããŸãã
ããŸã次ã®ãã©ã³ãããããã®ãšããŸãã
solution
ãã©ã³ããã¹ãã€ã¯ã解æ¶ããããã®ãã©ã³ãã§ãdevelop
ãã©ã³ãã«å¯ŸããŠäžã³ãããå ã§ããdevelop
ãã©ã³ããããã«ç·šéå 容ãé©çšããããšããŸãã
ããã¯ç·šéå 容ããã©ã³ãã«é©çšããããšã§å¯èœã§ãã
(develop)$ git checkout solution -- file1.txt
ãã㧠solution
ãã©ã³ãã®å
容ã develop
ãã©ã³ãã«é©çšãããŸãïŒ
# On branch develop
# Your branch is up-to-date with 'origin/develop'.
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: file1.txt
ããšã¯éåžžéãã³ãããããŠãã ããã
ã¡ã¢ïŒã¹ãã€ã¯ã¯åé¡ã解æããã解決ããããã®ãã®ã§ãã解決æ³ã¯å€æã«ãããããããšãå ±åç·šéè ãåé¡ãç解ããæç¹ã§ç Žæ£ãããŸãã~ Wikipedia
å¥ã ã®ãã©ã³ãã«ããã¹ãè€æ°ã®ã³ããããäžã€ã®ãã©ã³ãã«ããŠããŸã£ã
ãã¹ã¿ãŒãã©ã³ãã«ãããšããŠãgit log
ã§ã³ããããäºã€è¡šç€ºããããšããŸãã
(master)$ git log
commit e3851e817c451cc36f2e6f3049db528415e3c114
Author: Alex Lee <alexlee@example.com>
Date: Tue Jul 22 15:39:27 2014 -0400
Bug #21 - Added CSRF protection
commit 5ea51731d150f7ddc4a365437931cd8be3bf3131
Author: Alex Lee <alexlee@example.com>
Date: Tue Jul 22 15:39:12 2014 -0400
Bug #14 - Fixed spacing on title
commit a13b85e984171c6e2a1729bb061994525f626d14
Author: Aki Rose <akirose@example.com>
Date: Tue Jul 21 01:12:48 2014 -0400
First commit
ããããã®ãã°ã«å¯Ÿå¿ããã³ãããããã·ã¥ãã¡ã¢ããŠãããŸãïŒ#21 ã¯e3851e8
ã#14 ã¯5ea5173
ã§ãïŒã
ãŸãããã¹ã¿ãŒãã©ã³ããããã¹ãã³ããã a13b85e
ãŸã§ãªã»ããããŸãïŒ
(master)$ git reset --hard a13b85e
HEAD is now at a13b85e
ããã§ããã° #21 ã«å¯Ÿå¿ããæ°ãããã©ã³ããäœæã§ããŸãïŒ
(master)$ git checkout -b 21
(21)$
ããŠããã®ãã©ã³ãã«ã³ãããããã§ãªãŒããã¯ããŸãããã ã€ãŸããhead ãäœã§ããããšããã«åœè©²ã³ãããã ããé©çšããŸãã
(21)$ git cherry-pick e3851e8
ãã®æç¹ã§ã³ãããã®ã³ã³ããªã¯ããçºçããŠãããããããŸãããã³ã³ããªã¯ãã解æ¶ããæ¹æ³ã¯interactive rebasing section aboveã»ã¯ã·ã§ã³ã®There were conflictsãåç §ããŠãã ããã
次ã«ã#14 ã«å¯Ÿå¿ãããã¹ã¿ãŒã«çŽã¥ãããã©ã³ããäœæããŸãããã
(21)$ git checkout master
(master)$ git checkout -b 14
(14)$
æåŸã«ããã° #14 ã«å¯Ÿå¿ããã³ãããããã§ãªãŒããã¯ããŸãã
(14)$ git cherry-pick 5ea5173
upstream ã§åé€ãããããŒã«ã«ãã©ã³ããåé€ããã
GitHub ã§ãã«ãªã¯ãšã¹ããããŒãžãããšãããŒãžããããã©ã³ããèªåã®ãã©ãŒã¯äžããåé€ããéžæè¢ãåºãŠããŸãã ãã®ãã©ã³ãã§ä»åŸäœæ¥ããã€ããããªããã°ããã¯ã䜿ããªããã©ã³ãã§äœæ¥ç°å¢ãæ£ããããªãããã«åé€ããŠããã»ãã綺éºã§ãã
$ git fetch -p upstream
ãã㧠upstream
ã¯ååŸãããå
ã®ãªã¢ãŒããæããŸãã
ééã£ãŠãã©ã³ããåé€ããŠããŸã£ã
ãã€ããªã¢ãŒãã«ããã·ã¥ããŠãããªããããŠã倧äžå€«ã§ãããã ããã©ã³ããééã£ãŠåé€ããŠããŸãã®ã¯ããããããšã§ãã
æ°ãããã©ã³ããäœãããã¡ã€ã«ãæ°èŠäœæãããšããŸãïŒ
(master)$ git checkout -b my-branch
(my-branch)$ git branch
(my-branch)$ touch foo.txt
(my-branch)$ ls
README.md foo.txt
ãããè¿œå ããŠã³ãããããŸãã
(my-branch)$ git add .
(my-branch)$ git commit -m 'foo.txt added'
(my-branch)$ foo.txt added
1 files changed, 1 insertions(+)
create mode 100644 foo.txt
(my-branch)$ git log
commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012
Author: siemiatj <siemiatj@example.com>
Date: Wed Jul 30 00:34:10 2014 +0200
foo.txt added
commit 69204cdf0acbab201619d95ad8295928e7f411d5
Author: Kate Hudson <katehudson@example.com>
Date: Tue Jul 29 13:14:46 2014 -0400
Fixes #6: Force pushing after amending commits
ãã¹ã¿ãŒã«æ»ã£ãŠããééã£ãŠããã©ã³ããåé€ããŠã¿ãŸãã
(my-branch)$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
(master)$ git branch -D my-branch
Deleted branch my-branch (was 4e3cd85).
(master)$ echo oh noes, deleted my branch!
oh noes, deleted my branch!
ããŠãããã§æ¹è¯ããããã¬ãŒ reflog
ã«ã€ããŠåŠã³ãŸããããããã¯ãªããžããªã®å
šãŠã®æäœå±¥æŽãä¿åããŠããŸãã
(master)$ git reflog
69204cd HEAD@{0}: checkout: moving from my-branch to master
4e3cd85 HEAD@{1}: commit: foo.txt added
69204cd HEAD@{2}: checkout: moving from master to my-branch
ãã®ããã«ãåé€ããŠããŸã£ããã©ã³ãã®ã³ãããã衚瀺ãããŠããŸããåé€ãããã©ã³ãã埩å ããŠã¿ãŸãããã
(master)$ git checkout -b my-branch-help
Switched to a new branch 'my-branch-help'
(my-branch-help)$ git reset --hard 4e3cd85
HEAD is now at 4e3cd85 foo.txt added
(my-branch-help)$ ls
README.md foo.txt
ãã£ãïŒãæ¶ãããã¡ã€ã«ãåãæ»ããŸãããgit reflog
ã¯ãªããŒã¹ãæ»
è¶èŠè¶ã«ãªã£ãŠããŸã£ããšãã«ã䟿å©ã§ãã
ãã©ã³ããåé€ããã
ãªã¢ãŒããã©ã³ããåé€ããã«ã¯ïŒ
(master)$ git push origin --delete my-branch
次ã®ããã«ãã§ããŸãïŒ
(master)$ git push origin :my-branch
ããŒã«ã«ãã©ã³ããåé€ããã«ã¯ïŒ
(master)$ git branch -d my-branch
çŸåšã®ãã©ã³ãã upstream ã«ããŒãžãããŠããªããã©ã³ããåé€ããã«ã¯ïŒ
(master)$ git branch -D my-branch
è€æ°ã®ãã©ã³ããåé€ããã
fix/
ã§å§ãŸããã©ã³ããå
šãŠåé€ããããšãã¯ïŒ
(master)$ git branch | grep 'fix/' | xargs git branch -d
ãã©ã³ãã®ååãå€æŽããã
çŸåšã®ïŒããŒã«ã«ïŒãã©ã³ãã®ååãå€æŽããã«ã¯ïŒ
(master)$ git branch -m new-name
çŸåšãããã©ã³ããšç°ãªãïŒããŒã«ã«ïŒãã©ã³ãã®ååãå€æŽããã«ã¯ïŒ
(master)$ git branch -m old-name new-name
å€ãååïŒold-name
ïŒã®ãªã¢ãŒããã©ã³ããåé€ããæ°ããååïŒnew-name
ïŒã®ãã©ã³ããããã·ã¥ããã«ã¯ïŒ
(master)$ git push origin :old_name new_name
ä»ã®äººãäœæ¥ããŠãããªã¢ãŒããã©ã³ãã«ãã§ãã¯ã¢ãŠãããã
ãŸãããªã¢ãŒãããå šãã©ã³ããååŸããŸãïŒ
(master)$ git fetch --all
ãªã¢ãŒããã©ã³ã daves
ã«ãã§ãã¯ã¢ãŠãããããšããŸãã
(master)$ git checkout --track origin/daves
Branch daves set up to track remote branch daves from origin.
Switched to a new branch 'daves'
ïŒãã㧠--track
㯠git checkout -b [branch] [remotename]/[branch]
ã®ç瞮圢ã§ããïŒ
ãããããšãã©ã³ã daves
ã®ã³ããŒãããŒã«ã«ã«äœæãããããã·ã¥ãããç·šéå
容ããªã¢ãŒãã«åæ ãããŸãã
çŸåšã®ããŒã«ã«ãã©ã³ããããšã«æ°ãããªã¢ãŒããã©ã³ããäœæããã
$ git push <remote> HEAD
åæã«ãã®ãªã¢ãŒããã©ã³ããçŸåšã®ãã©ã³ãã® upstream ã«èšå®ãããå Žåã¯ä»£ããã«æ¬¡ãå®è¡ããŸãã
$ git push -u <remote> HEAD
push.default
èšå®ã upstream
ã¢ãŒãã simple
ã¢ãŒãïŒGit 2.0 ã®ããã©ã«ãïŒã«ãªã£ãŠããå Žåã次ã®ã³ãã³ããå®è¡ãããšã以åã« -u
ã§ç»é²ãããªã¢ãŒããã©ã³ãã«çŸåšã®ãã©ã³ããããã·ã¥ããŸãã
$ git push
ä»ã®ã¢ãŒãã git push
ã§ã©ãæ¯ãèããã¯push.default
ã®ããã¥ã¡ã³ãã§èª¬æãããŠããŸãã
ãªã¢ãŒããã©ã³ããããŒã«ã«ãã©ã³ãã® upstream ã«èšå®ããã
次ã®ããã«ããŠããªã¢ãŒããã©ã³ããçŸåšããããŒã«ã«ãã©ã³ãã® upstream ã«èšå®ã§ããŸãã
$ git branch --set-upstream-to [remotename]/[branch]
# or, using the shorthand:
$ git branch -u [remotename]/[branch]
å¥ã®ããŒã«ã«ãã©ã³ãã® upstream ã«èšå®ããã«ã¯æ¬¡ã®ããã«ããŸãïŒ
$ git branch -u [remotename]/[branch] [local-branch]
èªåã® HEAD ãããã©ã«ãã®ãªã¢ãŒããã©ã³ãã远跡ããããèšå®ããã
ãªã¢ãŒããã©ã³ãã調ã¹ããšãèªåã® HEAD ãã©ã®ãªã¢ãŒããã©ã³ãã远跡ããŠããããããããŸãã ãšãã©ãããã远跡ããããã©ã³ããšç°ãªãããšããããŸãã
$ git branch -r
origin/HEAD -> origin/gh-pages
origin/master
origin/HEAD
ã origin/master
ã远跡ããããèšå®ãçŽãã«ã¯ã次ã®ã³ãã³ããå®è¡ããŸãïŒ
$ git remote set-head origin --auto
origin/HEAD set to master
ééã£ããã©ã³ããç·šéããŠããŸã£ã
ãŸã ã³ãããããŠããªãç·šéãå ããããšãééã£ããã©ã³ãã«ããããšã«æ°ã¥ãããšããŸãã ç·šéå 容ãã¹ã¿ãã·ã¥ããŠãé©åãªãã©ã³ãã«é©çšããã°å€§äžå€«ã§ãïŒ
(wrong_branch)$ git stash
(wrong_branch)$ git checkout <correct_branch>
(correct_branch)$ git stash apply
ãªããŒã¹ãšããŒãž
ãªããŒã¹ãããŒãžãåãæ¶ããã
çŸåšã®ãã©ã³ããééã£ããã©ã³ãã«ãªããŒã¹ãªããããŒãžããŠããŸã£ãããããã¯ãªããŒã¹ãªããããŒãžãåºæ¥ãªããããšæ°ã¥ãããšããŸãããã
Git ã¯å±éºãªæäœã®åã« HEAD ãæããã®ãå€æ° ORIG_HEAD
ã«ä¿åããŠããã®ã§ããã©ã³ãããªããŒã¹ãªããããŒãžã®åã®ç¶æ
ã«å·®ãæ»ãã®ã¯ç°¡åã§ãã
(my-branch)$ git reset --hard ORIG_HEAD
ãªããŒã¹ãããã匷å¶ããã·ã¥ã¯ããããªã
æ®å¿µãªãããç·šéå 容ããªã¢ãŒããã©ã³ãã«åæ ãããã«ã¯åŒ·å¶ããã·ã¥ãããå¿ èŠããããŸããç·šéå±¥æŽãå€ããŠããŸã£ãããã§ãã 匷å¶ããã·ã¥ããªãéããªã¢ãŒããã©ã³ãã¯ç·šéå 容ãåãä»ããŸããã ãããå€ãã®äººããªããŒã¹ã¯ãŒã¯ãããŒã§ã¯ãªãããŒãžã¯ãŒã¯ãããŒã䜿ãäž»ãªçç±ã§ãã ç¹ã«å€§èŠæš¡ãªéçºããŒã ã¯èª°ãã®åŒ·å¶ããã·ã¥ã§ããããããã§ãã ãªããŒã¹ã®åŒ·å¶ããã·ã¥ã¯æ³šæããŠäœ¿ããŸãããã ãªããŒã¹ã䜿ãå®å šãªæ¹æ³ã¯ããªã¢ãŒãã«ã¯ç·šéå 容ãåæ ãããã代ããã«æ¬¡ãå®è¡ããããšã§ãïŒ
(master)$ git checkout my-branch
(my-branch)$ git rebase -i master
(my-branch)$ git checkout master
(master)$ git merge --ff-only my-branch
詳ããã¯ãã® StackOverflow ã¹ã¬ãããåç §ããŠãã ããã
ã³ããããçµ±åããã
master
ãã©ã³ãã«ãã«ãªã¯ãšã¹ããéãããŸãã¯ããããéãã€ããã®ãã©ã³ãã§äœæ¥ããŠãããšããŸãããã
æãåçŽãªã±ãŒã¹ãšããŠãã¿ã€ã ã¹ã¿ã³ããæ°ã«ããå
šéšã®ã³ããããäžã€ã«ãŸãšããŠããŸããããšããŸãããã®å Žåã¯ãªã»ãããšåã³ããããè¡ããŸãã
ãã¹ã¿ãŒãã©ã³ããææ°çã§ãç·šéå
容ããã¹ãŠã³ããããããŠããããšã確èªããäžã§ã次ãå®è¡ããŸãïŒ
(my-branch)$ git reset --soft master
(my-branch)$ git commit -am "New awesome feature"
ãã£ãšçŽ°ããèšå®ããã¿ã€ã ã¹ã¿ã³ããæ®ãããå Žåã¯ã察話çãªããŒã¹ãšåŒã°ãããã®ã䜿ããŸãïŒ
(my-branch)$ git rebase -i master
å¥ã®ãã©ã³ãã§äœæ¥ããŠããããã§ã¯ãªãå Žåã¯ãHEAD
ã«å¯ŸããŠãªããŒã¹ããå¿
èŠããããŸããããšãã°çŽè¿äºä»¶ã®ã³ããããå§çž® (squash) ãããå Žå㯠HEAD~2
ãçŽè¿äžä»¶ãªã HEAD~3
ã§ãã
(master)$ git rebase -i HEAD~2
察話çãªããŒã¹ã®ã³ãã³ããå®è¡ããããããã¹ããšãã£ã¿ã«æ¬¡ã®ããã«è¡šç€ºãããŸãïŒ
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
pick b729ad5 fixup
pick e3851e8 another fix
# Rebase 8074d12..b729ad5 onto 8074d12
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
ãã㧠#
ããå§ãŸãè¡ã¯ã³ã¡ã³ããªã®ã§ããªããŒã¹ã«åœ±é¿ããŸããã
pick
ã³ãã³ãããªã¹ãã«ãã奜ããªã³ãã³ãã§çœ®ãæããã°ããã§ããè¡ãåé€ããã°ã³ããããåé€ã§ããŸãã
äŸãã°ãäžçªå€ãïŒäžçªç®ã®ïŒã³ãããã¯ãã®ãŸãŸæ®ããä»ã®ã³ãããå
šãŠãäºçªç®ã®ã³ãããã«çµ±åãããå Žåã¯ãæåãšäºçªç®ã®ã³ããã以å€ã®ã³ãããã®æšªã«è¡šç€ºãããæåãäŸãã° f
ã«ä¿®æ£ããŸãïŒ
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
f b729ad5 fixup
f e3851e8 another fix
ã³ããããçµ±åããããã«ååãå€æŽãããå Žåã¯ãäºçªç®ã®ã³ãããã®æšªã«ããã« r
ã®æåãè¿œå ãããããããã¯åã« f
ã®ä»£ããã« s
ã䜿ããŸãïŒ
pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
s b729ad5 fixup
s e3851e8 another fix
ãããšããã¹ããšãã£ã¿ãèµ·åããã³ãããã®ååãå€æŽã§ããŸãã
Newer, awesomer features
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# rebase in progress; onto 8074d12
# You are currently editing a commit while rebasing branch 'master' on '8074d12'.
#
# Changes to be committed:
# modified: README.md
#
ããŸããããšæ¬¡ã®ããã«è¡šç€ºãããã¯ãã§ãïŒ
(master)$ Successfully rebased and updated refs/heads/master.
å®å šãªããŒãžã®æ¹æ³
--no-commit
performs the merge but pretends the merge failed and does not autocommit, giving the user a chance to inspect and further tweak the merge result before committing. no-ff
maintains evidence that a feature branch once existed, keeping project history consistent.
(master)$ git merge --no-ff --no-commit my-branch
ãªãã·ã§ã³ --no-commit
ãæå®ãããšãããŒãžãå®è¡ãã€ã€ãããããããŒãžã倱æãããã®ããã«æ±ã£ãŠèªåã³ãããã¯ããŸãããããã«ãããã³ãããã®åã«ããŒãžã®çµæã粟æ»ããã調æŽã§ããŸãããªãã·ã§ã³ no-ff
ã¯ãã£ãŒãã£ãŒãã©ã³ããååšããããšãèšé²ããŠããããããžã§ã¯ãå±¥æŽã®äžè²«æ§ãä¿ã¡ãŸãã
ãã©ã³ããäžã€ã®ã³ãããã«ãŸãšãããå Žå
(master)$ git merge --squash my-branch
ããã·ã¥ãããŠããªãã³ãããã®ã¿ãçµ±åãããå Žå
é²è¡äžã®äœæ¥ã«é¢ããã³ããããããã€ããã£ãŠãupstream ã«ã³ãããããåã«çµ±åããŠããããããšãããã§ãããã ãã§ã« upstream ã«ããã·ã¥ãããã³ãããã¯ã誰ãããããåç §ããã³ããããããŠããå¯èœæ§ãããã®ã§ãããã¯çµ±åããªãã§ãããããšããŸãã
(master)$ git rebase -i @{u}
äžãå®è¡ãããšå¯Ÿè©±çãªããŒã¹ãå§ãŸããŸãããäžèŠ§ã«ã¯ãŸã ããã·ã¥ãããŠããªãã³ãããã ãã衚瀺ãããŸããããã§é çªãå ¥ãæ¿ããããä¿®æ£ããããå§çž® (squash) ãããããŠãå®å šã§ãã
ããŒãžãäžæ¢ããã
ããŒãžããã¡ã€ã«ã«åé¡ããããããšããããŸãã
ãããããšãã¯ãªãã·ã§ã³ abort
ã䜿ããšã³ã³ããªã¯ã解æ¶ã®äœæ¥ãäžæ¢ããããŒãžã®åã®ç¶æ
ã®åŸ©å
ãè©Šã¿ãããšãã§ããŸãã
(my-branch)$ git merge --abort
ãã ãããã®ã³ãã³ãã䜿ããã®ã¯ããŒãžã§ã³ 1.7.4 以äžã® Git ã§ãã
ãã©ã³ãã®èŠªã³ããããæŽæ°ããã
ãã¹ã¿ãŒãã©ã³ããšããããåå²ãã feature-1 ãã©ã³ãããããfeature-1 ããããã«åå²ãã feature-2 ãã©ã³ãããããšããŸãã
ä» feature-1 ãã©ã³ãã«ã³ããããããšãããšãfeature-2 ãã©ã³ãã®èŠªã³ãããã¯ãã¯ãæ£ç¢ºã§ã¯ãããŸããïŒfeature-1 ããåå²ããã®ã§ã芪ã³ããã㯠feature-1 ãã©ã³ãã® head ã§ããã¹ãã§ããïŒ
ãããããšã㯠git rebase --onto
ã§ä¿®æ£ã§ããŸãã
(feature-2)$ git rebase --onto feature-1 <the first commit in your feature-2 branch that you don't want to bring along> feature-2
ãŸã ããŒãžãããŠããªããã©ã³ããããã£ãŒãã£ãŒãã©ã³ããåå²ãããŠãããfeature-1 ãã©ã³ãã®ãã°ä¿®æ£ã feature-2 ã«åæ ãããããšãã«äŸ¿å©ã§ãã
ãã©ã³ãã®å šã³ããããããŒãžãããŠããã確èªãã
ãã©ã³ãã®å šãŠã®ã³ããããå¥ã®ãã©ã³ãã«ããŒãžãããã確èªããã«ã¯ãããããã®ãã©ã³ãã® headïŒãããã¯ä»»æã®ã³ãããïŒã®éã®å·®åã衚瀺ããŸãïŒ
(master)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll
äžæ¹ã®ãã©ã³ãã«ãããªãã³ããããããã衚瀺ããããã©ã³ãã®éã§å ±æãããŠããªãã³ãããã®äžèŠ§ãããããŸãã ããäžã€ã®æ¹æ³ã¯ïŒ
(master)$ git log master ^feature/120-on-scroll --no-merges
察話çãªããŒã¹ã§èµ·ããããåé¡
ãªããŒã¹ç·šéç»é¢ã« 'noop' ãšè¡šç€ºããã
次ã®ããã«è¡šç€ºããããšããŸãïŒ
noop
ããã¯ãåãã³ãããã®ãã©ã³ãããããã¯çŸåšã®ãã©ã³ããããå ã«ãããã©ã³ãã«å¯ŸããŠãªããŒã¹ããããšãããšãã«è¡šç€ºããããã®ã§ããããããå Žåã¯ïŒ
- ãã¹ã¿ãŒãã©ã³ããæ£ããå Žæã«ããããšã確èªããŠãã ããã
HEAD~2
ãããã¯ãã以åã«ãªããŒã¹ããŠãã ããã
ã³ã³ããªã¯ãããã£ã
ãªããŒã¹ãã§ããªããšãã¯ã解æ¶ãã¹ãã³ã³ããªã¯ãããããããããŸããã
ãŸã git status
ã§ãã©ã®ãã¡ã€ã«ãã³ã³ããªã¯ããèµ·ãããŠããã確èªããŸãïŒ
(my-branch)$ git status
On branch my-branch
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)
both modified: README.md
ãã®äŸã§ã¯ README.md
ãã³ã³ããªã¯ããããããŠããŸãããã¡ã€ã«ãéãã次ã®ããã«ãªã£ãŠããéšåãèŠãŠã¿ãŸãããïŒ
<<<<<<< HEAD
some code
=========
some code
>>>>>>> new-commit
HEAD
ãšæ°ããã³ãããã§å ããããã³ãŒãã®éã®å·®åïŒãã®äŸã§ã¯ãçãäžã®è¡ãã new-commit
ãŸã§ã®éã«ããã³ãŒãïŒã解æ¶ããå¿
èŠããããŸãã
äžæ¹ã®ãã©ã³ãã®çã®ã³ãŒããæ®ãããå Žåã¯ã--ours
ããã㯠--theirs
ãæå®ããŸãã
(master*)$ git checkout --ours README.md
- ããŒãžããå ŽåãããŒã«ã«ãã©ã³ãã®ç·šéå
容ãæ®ããããšã
--ours
ãæå®ããä»æ¹ã®ç·šéå 容ãæ®ããããšã--theirs
ãæå®ããŸãã - ãªããŒã¹ããå ŽåãããŒã«ã«ãã©ã³ãã®ç·šéå
容ãæ®ããããšã
--theirs
ãæå®ããä»æ¹ã®ç·šéå 容ãæ®ããããšã--ours
ãæå®ããŸãããã®ããã«é転ããçç±ã¯Git ããã¥ã¡ã³ãã®ãã®ããŒããåç §ããŠãã ããã
ããŒãžããã£ãšè€éãªå Žåã¯ãŽã£ãžã¥ã¢ã«å·®åãšãã£ã¿ã䜿ãããšãã§ããŸãïŒ
(master*)$ git mergetool -t opendiff
ã³ã³ããªã¯ããå
šãŠè§£æ¶ããã³ãŒãã®ãã¹ããæžãã ããgit add
ã§ç·šéå
容ãã¹ããŒãžããgit rebase --continue
ã§ãªããŒã¹ãåéããŸãã
(my-branch)$ git add README.md
(my-branch)$ git rebase --continue
ã³ã³ããªã¯ãã解æ¶ããçµæãã¯ãŒãã³ã°ããªãŒãã³ãããåãšå
šãåãç¶æ
ã«ãªã£ãå Žåã¯ã代ããã« git rebase --skip
ãå®è¡ããŸãã
ãªããŒã¹äœæ¥ãå šãŠäžæ¢ãããã©ã³ããå ã®ç¶æ ã«å·®ãæ»ãããå Žåã¯ã次ã®ããã«ããŸãïŒ
(my-branch)$ git rebase --abort
ã¹ã¿ãã·ã¥
å šãŠã®ç·šéå 容ãã¹ã¿ãã·ã¥ããã
ã¯ãŒãã³ã°ãã£ã¬ã¯ããªã®å šãŠã®ç·šéãã¹ã¿ãã·ã¥ããã«ã¯ã次ãå®è¡ããŸãïŒ
$ git stash
ããŒãžã§ã³ç®¡çãããŠããªããã¡ã€ã«ãã¹ã¿ãã·ã¥ãããå Žåã¯ããªãã·ã§ã³ -u
ãæå®ããŸãã
$ git stash -u
ç¹å®ã®ãã¡ã€ã«ãã¹ã¿ãã·ã¥ããã
ã¯ãŒãã³ã°ãã£ã¬ã¯ããªã®ãã¡ã€ã«äžã€ãã¹ã¿ãã·ã¥ããã«ã¯ã次ãå®è¡ããŸãïŒ
$ git stash push working-directory-path/filename.ext
ã¯ãŒãã³ã°ãã£ã¬ã¯ããªã®è€æ°ã®ãã¡ã€ã«ãã¹ã¿ãã·ã¥ããå Žåã¯æ¬¡ã®éãã§ãã
$ git stash push working-directory-path/filename1.ext working-directory-path/filename2.ext
ã¡ãã»ãŒãžãã€ããŠã¹ã¿ãã·ã¥ããã
$ git stash save <message>
ãããã¯ã
$ git stash push -m <message>
äžèŠ§ããç¹å®ã®ã¹ã¿ãã·ã¥ãéžãã§é©çšããã
ãŸãã次ã®ããã«ããŠã¹ã¿ãã·ã¥ã®äžèŠ§ãã¡ãã»ãŒãžãšãšãã«è¡šç€ºããŸãã
$ git stash list
ãããŠã次ã®ããã«ç¹å®ã®ã¹ã¿ãã·ã¥ãéžãã§é©çšããŸãã
$ git stash apply "stash@{n}"
ããã§ã'n' ã¯äžèŠ§ã®äžã®ã¹ã¿ãã·ã¥ã®äœçœ®ãæããŸããäžçªäžã®ã¹ã¿ãã·ã¥ãªã 0 çªã§ãã
ãŸããæå»ããã¹ã¿ãã·ã¥ãåç §ããããšãã§ããŸãã
$ git stash apply "stash@{2.hours.ago}"
ã¹ããŒãžãããŠããªãç·šéããã®ãŸãŸã«ãã€ã€ãã¹ã¿ãã·ã¥ããã
æå㧠stash commit
ãäœæããgit stash store
ãå®è¡ããã°ããã§ãã
$ git stash create
$ git stash store -m <message> CREATED_SHA1
æ€çŽ¢
ä»»æã®ã³ãããããæååãæ€çŽ¢ããã
ããã³ãããã§å°å ¥ãããããæååãæ€çŽ¢ããããšãã¯ã次ã®ã³ãã³ãã䜿ããŸãïŒ
$ git log -S "string to find"
ãã䜿ããããã©ã¡ãŒã¿ã¯æ¬¡ã®éãïŒ
--source
ãæå®ãããšãã³ãã³ãã©ã€ã³ã§ã€ããããåã³ãããã®åç §åã衚瀺ããŸãã--all
ã¯å šãŠã®ãã©ã³ãããæ€çŽ¢ããŸãã--reverse
ãæå®ãããšéé ã«è¡šç€ºããŸããããªãã¡ãæåã®ã³ããããã衚瀺ããŸãã
author ãŸã㯠committer ããæ€çŽ¢ãã
å šãŠã®ã³ãããã author ãŸã㯠committer ã®ååããæ€çŽ¢ããã«ã¯æ¬¡ã®éãã§ãïŒ
$ git log --author=<name or email>
$ git log --committer=<name or email>
author ãš committer ã¯ç°ãªãããšã«æ³šæããŠãã ããã
--author
ã¯ã¯ããã«ã³ãŒããæžãã人ã--committer
㯠author ã®ä»£ããã«ã³ããããã人ãæããŸãã
ç¹å®ã®ãã¡ã€ã«ãå«ãã³ãããã®äžèŠ§ã衚瀺ããã
ç¹å®ã®ãã¡ã€ã«ãå«ãã³ãããã®äžèŠ§ã衚瀺ããã«ã¯ã次ãå®è¡ããŸãã
$ git log -- <path to file>
éåžžã¯æ£ç¢ºãªãã¹ãæå®ããŸããããã¹ããã¡ã€ã«åã«ã¯ã€ã«ãã«ãŒãã䜿ãããšãã§ããŸãïŒ
$ git log -- **/*.js
ã¯ã€ã«ãã«ãŒãã䜿ãéã¯ã--name-status
ãæå®ãããšã³ãããããããã¡ã€ã«ã®äžèŠ§ã衚瀺ãããã®ã§äŸ¿å©ã§ãã
$ git log --name-status -- **/*.js
ç¹å®ã®é¢æ°ã«ã€ããŠã³ãããå±¥æŽãèŠãã
ããé¢æ°ã®å±¥æŽã远跡ããã«ã¯æ¬¡ãå®è¡ããŸãïŒ
$ git log -L :FunctionName:FilePath
ãã®ã³ãã³ã㯠git log
ã®ä»ã®ãªãã·ã§ã³ãäŸãã° revision ranges ã commit limits ãšäžç·ã«äœ¿ãããšãã§ããŸãã
ã³ããããåç §ãããŠããã¿ã°ãæ€çŽ¢ããã
ç¹å®ã®ã³ããããå«ãã¿ã°ãæ€çŽ¢ããã«ã¯æ¬¡ã®ããã«ããŸãïŒ
$ git tag --contains <commitid>
ãµãã¢ãžã¥ãŒã«
å šãŠã®ãµãã¢ãžã¥ãŒã«ãã¯ããŒã³ãã
$ git clone --recursive git://github.com/foo/bar.git
ãã§ã«ã¯ããŒã³ããŠããå ŽåïŒ
$ git submodule update --init --recursive
ãµãã¢ãžã¥ãŒã«ãåé€ãã
ãµãã¢ãžã¥ãŒã«ã®äœæã¯ããããŠç°¡åã§ãããåé€ã¯ããã§ããããŸããã åé€ã«å¿ èŠãªã³ãã³ãã¯æ¬¡ã®éãã§ãïŒ
$ git submodule deinit submodulename
$ git rm submodulename
$ git rm --cached submodulename
$ rm -rf .git/modules/submodulename
ãã®ä»è²ã
ãããã©ã³ãããå¥ã®ãã©ã³ãã«ãã©ã«ããã³ããŒããã
$ git checkout <branch-you-want-the-directory-from> -- <folder-name or file-name>
åé€ããããã¡ã€ã«ã埩å ããã
ãŸãããã¡ã€ã«ãæåŸã«ãã£ãã³ããããæ¢ããŸãïŒ
$ git rev-list -n 1 HEAD -- filename
èŠã€ãã£ããããã¡ã€ã«ããã§ãã¯ã¢ãŠãããŸãïŒ
git checkout deletingcommitid^ -- filename
ã¿ã°ãåé€ããã
$ git tag -d <tag_name>
$ git push <remote> :refs/tags/<tag_name>
åé€ãããã¿ã°ã埩å ããã
åé€ãããã¿ã°ã埩å ããæé ã¯æ¬¡ã®éãã§ãã ãŸããunreachable ã«ãªã£ãã¿ã°ãæ¢ããŸãïŒ
$ git fsck --unreachable | grep tag
ã¿ã°ã®ããã·ã¥ãã¡ã¢ããŠãããŸãã
ç¶ããŠã次ã®ããã« git update-ref
ã䜿ã£ãŠåé€ãããã¿ã°ã埩å
ããŸãïŒ
$ git update-ref refs/tags/<tag_name> <hash>
ããã§ã¿ã°ã埩å ãããã¯ãã§ãã
åé€ãããããããååŸããã
誰ãã GitHub ã§ãã«ãªã¯ãéã£ãããšã«ãã©ãŒã¯ãåé€ããŠããŸã£ãå Žåããã®ãªããžããªãã¯ããŒã³ããããgit am
ã§ããããé©çšããããšãã§ããªããªããŸãã.diff ã .patch ã® URL ã䜿ããªããªã£ãŠããŸãããã§ãã
ããããGitHub ç¬èªã®åç
§ã䜿ã£ãŠããã«ãªã¯ãšã¹ãèªäœããã§ãã¯ã¢ãŠãããããšãã§ããŸãã
ãã«ãªã¯ãšã¹ã #1 ã®å
容ãæ°ãããã©ã³ã pr_1 ã«ååŸããã«ã¯ã次ãå®è¡ããŸãïŒ
$ git fetch origin refs/pull/1/head:pr_1
From github.com:foo/bar
* [new ref] refs/pull/1/head -> pr_1
ãªããžããªã zip ãã¡ã€ã«ãšããŠãšã¯ã¹ããŒããã
$ git archive --format zip --output /full/path/to/zipfile.zip master
åãååã®ãã©ã³ããšã¿ã°ãããã·ã¥ããã
ãã©ã³ããšåãååã®ã¿ã°ããªã¢ãŒããªããžããªã«ååšããå Žåãéåžžéã $ git push <remote> <branch>
ã§ããã·ã¥ããããšãããšã次ã®ããã«ãšã©ãŒãåºãŸãã
$ git push origin <branch>
error: dst refspec same matches more than one.
error: failed to push some refs to '<git server>'
ãã®ãšã©ãŒã¯ãã©ã³ãã®ããããæå®ããããšã«ãã£ãŠåé¿ã§ããŸãã
$ git push origin refs/heads/<branch-name>
ååã®ãã©ã³ãããªã¢ãŒããªããžããªã«ããã¿ã°ãããã·ã¥ããããšããã䌌ãã³ãã³ãã䜿ããŸãã
$ git push origin refs/tags/<tag-name>
ãã¡ã€ã«ã®è¿œè·¡
ãã¡ã€ã«ã®å 容ã¯å€ããã«ããã¡ã€ã«åã®å€§æåã»å°æåãå€æŽããã
(master)$ git mv --force myfile MyFile
git pull ããŠããŒã«ã«ã®ãã¡ã€ã«ãäžæžãããã
(master)$ git fetch --all
(master)$ git reset --hard origin/master
ãã¡ã€ã«ãæ®ãã€ã€ Git ããåé€ããã
(master)$ git rm --cached log.txt
ãã¡ã€ã«ãç¹å®ã®çãŸã§å·®ãæ»ããã
å·®ãæ»ãããã³ãããã®ããã·ã¥ã c5f567 ã®å Žåã次ãå®è¡ããŸãïŒ
(master)$ git checkout c5f567 -- file1/to/restore file2/to/restore
å·®ãæ»ãããã³ãããã c5f567 ã®äžã€åãªããã³ãããããã·ã¥ã« c5f567~1 ãæå®ããŸãïŒ
(master)$ git checkout c5f567~1 -- file1/to/restore file2/to/restore
ç¹å®ã®ãã¡ã€ã«ã®ã³ãããéã»ãã©ã³ãéã®å·®åã衚瀺ããã
ã³ããã c5f567 ãšãã®äžã€åã®å·®åã衚瀺ãããå Žåã次ãå®è¡ããŸãïŒ
$ git diff HEAD:path_to_file/file c5f567:path_to_file/file
ãã©ã³ãã§ãåæ§ã§ãïŒ
$ git diff master:path_to_file/file staging:path_to_file/file
ç¹å®ã®ãã¡ã€ã«ã®å€æŽãç¡èŠããã
ããã¯ã³ãããã§ããªãèªèšŒæ å ±ãããŒã«ã«ç°å¢ã§è¿œå ããå¿ èŠã®ããèšå®ãã³ãã¬ãŒããªã©ããããšãã«åœ¹ç«ã¡ãŸãã
$ git update-index --assume-unchanged file-to-ignore
ãã¡ã€ã«ãããŒãžã§ã³ç®¡çãããªããªãããã§ã¯ãªãããšã«æ³šæããŠãã ãããããŒã«ã«ã§ç¡èŠãããã ãã§ãã èšå®ãåãæ¶ããŠå€æŽãåã³è¿œè·¡ããã«ã¯ã次ã®ããã«ã㊠ignore ãã©ãã°ãåé€ããŸãïŒ
$ git update-index --no-assume-unchanged file-to-stop-ignoring
Git ã«ãããããã°
ã³ãã³ã git-bisect ã¯ãã©ã®ã³ãããããã°ããããããã Git å±¥æŽãäºåæ¢çŽ¢ããŸãã
ä» master
ãã©ã³ãã«ãããšããŠã倱æããããããã³ããããæ¢ããŠã¿ãŸãããã次ã®ããã«ããŠäºåæ¢çŽ¢ãå§ããŸãïŒ
$ git bisect start
åé¡ã®ããã³ããããšãªãã³ããããæå®ããå¿
èŠããããŸããçŸåšã®ããŒãžã§ã³ã«åé¡ããããv1.1.1
ã¯åé¡ãªããšããŸãã
$ git bisect bad
$ git bisect good v1.1.1
ãããš git-bisect
ã¯éžãã ããŒãžã§ã³ã®äžéã®ã³ããããéžãã§èª¿ã¹ãåé¡ããããã©ããå°ããŠããŸãã
次ã®ããã«è¡šç€ºãããã¯ãã§ãïŒ
$ Bisecting: 5 revision left to test after this (roughly 5 step)
$ [c44abbbee29cb93d8499283101fe7c8d9d97f0fe] Commit message
$ (c44abbb)$
ãã®ã³ãããã«åé¡ããããã©ãã調ã¹ãŸããåé¡ããªã (good) å Žåã¯æ¬¡ãå®è¡ããŸãïŒ
$ (c44abbb)$ git bisect good
ãããšãgit-bisect
ã¯å¥ã®ã³ããããéžæããŸãããã®ããã« good
ã bad
ãéžãã§ããäœæ¥ã¯ã調ã¹ãã³ãããããªããªããŸã§ç¶ããŸãã
çµäºããããã³ãã³ãã©ã€ã³ã«ã¯åé¡ãããããŠããæåã®ã³ãããã®è©³çŽ°ã衚瀺ãããŸãã
Configuration
I want to add aliases for some Git commands
On OS X and Linux, your git configuration file is stored in ~/.gitconfig
. I've added some example aliases I use as shortcuts (and some of my common typos) in the [alias]
section as shown below:
[alias]
a = add
amend = commit --amend
c = commit
ca = commit --amend
ci = commit -a
co = checkout
d = diff
dc = diff --changed
ds = diff --staged
extend = commit --amend -C HEAD
f = fetch
loll = log --graph --decorate --pretty=oneline --abbrev-commit
m = merge
one = log --pretty=oneline
outstanding = rebase -i @{u}
reword = commit --amend --only
s = status
unpushed = log @{u}
wc = whatchanged
wip = rebase -i @{u}
zap = fetch -p
day = log --reverse --no-merges --branches=* --date=local --since=midnight --author=\"$(git config --get user.name)\"
delete-merged-branches = "!f() { git checkout --quiet master && git branch --merged | grep --invert-match '\\*' | xargs -n 1 git branch --delete; git checkout --quiet @{-1}; }; f"
I want to add an empty directory to my repository
You canât! Git doesnât support this, but thereâs a hack. You can create a .gitignore file in the directory with the following contents:
# Ignore everything in this directory
*
# Except this file
!.gitignore
Another common convention is to make an empty file in the folder, titled .gitkeep.
$ mkdir mydir
$ touch mydir/.gitkeep
You can also name the file as just .keep , in which case the second line above would be touch mydir/.keep
I want to cache a username and password for a repository
You might have a repository that requires authentication. In which case you can cache a username and password so you don't have to enter it on every push and pull. Credential helper can do this for you.
$ git config --global credential.helper cache
# Set git to use the credential memory cache
$ git config --global credential.helper 'cache --timeout=3600'
# Set the cache to timeout after 1 hour (setting is in seconds)
To find a credential helper:
$ git help -a | grep credential
# Shows you possible credential helpers
For OS specific credential caching:
$ git config --global credential.helper osxkeychain
# For OSX
$ git config --global credential.helper manager
# Git for Windows 2.7.3+
$ git config --global credential.helper gnome-keyring
# Ubuntu and other GNOME-based distros
More credential helpers can likely be found for different distributions and operating systems.
I want to make Git ignore permissions and filemode changes
$ git config core.fileMode false
If you want to make this the default behaviour for logged-in users, then use:
$ git config --global core.fileMode false
I want to set a global user
To configure user information used across all local repositories, and to set a name that is identifiable for credit when review version history:
$ git config --global user.name â[firstname lastname]â
To set an email address that will be associated with each history marker:
git config --global user.email â[valid-email]â
I want to add command line coloring for Git
To set automatic command line coloring for Git for easy reviewing:
$ git config --global color.ui auto
I've no idea what I did wrong
So, you're screwed - you reset
something, or you merged the wrong branch, or you force pushed and now you can't find your commits. You know, at some point, you were doing alright, and you want to go back to some state you were at.
This is what git reflog
is for. reflog
keeps track of any changes to the tip of a branch, even if that tip isn't referenced by a branch or a tag. Basically, every time HEAD changes, a new entry is added to the reflog. This only works for local repositories, sadly, and it only tracks movements (not changes to a file that weren't recorded anywhere, for instance).
(master)$ git reflog
0a2e358 HEAD@{0}: reset: moving to HEAD~2
0254ea7 HEAD@{1}: checkout: moving from 2.2 to master
c10f740 HEAD@{2}: checkout: moving from master to 2.2
The reflog above shows a checkout from master to the 2.2 branch and back. From there, there's a hard reset to an older commit. The latest activity is represented at the top labeled HEAD@{0}
.
If it turns out that you accidentally moved back, the reflog will contain the commit master pointed to (0254ea7) before you accidentally dropped 2 commits.
$ git reset --hard 0254ea7
Using git reset
it is then possible to change master back to the commit it was before. This provides a safety net in case history was accidentally changed.
(copied and edited from Source).
Git Shortcuts
Git Bash
Once you're comfortable with what the above commands are doing, you might want to create some shortcuts for Git Bash. This allows you to work a lot faster by doing complex tasks in really short commands.
alias sq=squash
function squash() {
git rebase -i HEAD~$1
}
Copy those commands to your .bashrc or .bash_profile.
PowerShell on Windows
If you are using PowerShell on Windows, you can also set up aliases and functions. Add these commands to your profile, whose path is defined in the $profile
variable. Learn more at the About Profiles page on the Microsoft documentation site.
Set-Alias sq Squash-Commits
function Squash-Commits {
git rebase -i HEAD~$1
}
Other Resources
Books
- Learn Enough Git to Be Dangerous - A book by Michael Hartl covering Git from basics
- Pro Git - Scott Chacon and Ben Straub's excellent book about Git
- Git Internals - Scott Chacon's other excellent book about Git
- Nasa handbook
Tutorials
- 19 Git Tips For Everyday Use - A list of useful Git one liners
- Atlassian's Git tutorial Get Git right with tutorials from beginner to advanced.
- Learn Git branching An interactive web based branching/merging/rebasing tutorial
- Getting solid at Git rebase vs. merge
- Git Commands and Best Practices Cheat Sheet - A Git cheat sheet in a blog post with more explanations
- Git from the inside out - A tutorial that dives into Git's internals
- git-workflow - Aaron Meurer's howto on using Git to contribute to open source repositories
- GitHub as a workflow - An interesting take on using GitHub as a workflow, particularly with empty PRs
- Githug - A game to learn more common Git workflows
- learnGitBranching - An interactive git visualization to challenge and educate!
Scripts and Tools
- firstaidgit.io A searchable selection of the most frequently asked Git questions
- git-extra-commands - a collection of useful extra Git scripts
- git-extras - GIT utilities -- repo summary, repl, changelog population, author commit percentages and more
- git-fire - git-fire is a Git plugin that helps in the event of an emergency by adding all current files, committing, and pushing to a new branch (to prevent merge conflicts).
- git-tips - Small Git tips
- git-town - Generic, high-level Git workflow support! http://www.git-town.com
GUI Clients
- GitKraken - The downright luxurious Git client,for Windows, Mac & Linux
- git-cola - another Git client for Windows and OS X
- GitUp - A newish GUI that has some very opinionated ways of dealing with Git's complications
- gitx-dev - another graphical Git client for OS X
- Sourcetree - Simplicity meets power in a beautiful and free Git GUI. For Windows and Mac.
- Tower - graphical Git client for OS X (paid)
- tig - terminal text-mode interface for Git
- Magit - Interface to Git implemented as an Emacs package.
- GitExtensions - a shell extension, a Visual Studio 2010-2015 plugin and a standalone Git repository tool.
- Fork - a fast and friendly Git client for Mac (beta)
- gmaster - a Git client for Windows that has 3-way merge, analyze refactors, semantic diff and merge (beta)
- gitk - a Git client for linux to allow simple view of repo state.
- SublimeMerge - Blazing fast, extensible client that provides 3-way merges, powerful search and syntax highlighting, in active development.