Difference between revisions of "Working with git"
(→Submitting a patch file) |
(→Workflows) |
||
Line 192: | Line 192: | ||
=Workflows= | =Workflows= | ||
+ | |||
+ | These workflows are designed to be self-contained. git is a complicated program, and the documentation can be confusing. The aim of these sections is that if you stick to the commands and techniques used here, you should not get into a mess or need to consult any other git documentation. | ||
==SVN style== | ==SVN style== | ||
Line 201: | Line 203: | ||
Work on your new feature or bug fix. If you need to add a new file to the repository, use | Work on your new feature or bug fix. If you need to add a new file to the repository, use | ||
− | git add <filename> | + | git add -N <filename> |
− | (like svn add) for the file you have created. If you need to remove a file, use | + | (like svn add) for the file you have created. (The -N stops the content of the file being added to the "staging area", which would make "git diff" give confusing results. Don't worry about this.) If you need to remove a file, use |
git rm <filename> | git rm <filename> | ||
(like svn rm). | (like svn rm). | ||
+ | |||
+ | Every so often, you will want to make sure you are working against the latest version of the code. This is accomplished by | ||
+ | |||
+ | git stash | ||
+ | git pull | ||
+ | git stash pop | ||
+ | |||
+ | This is equivalent to "svn update". When you do the "git stash pop", you may have conflicts between the upstream changes and your own. These will be marked with conflict markers in the source files just like with SVN. You will need to fix these conflicts. | ||
+ | |||
+ | To see what changes you have made in your local copy, use | ||
+ | |||
+ | git diff HEAD | ||
+ | |||
+ | If you want to revert one or more files to its clean state before you started editing it, use | ||
+ | |||
+ | git checkout <file1> <file2> ... | ||
+ | |||
+ | If you want to see what files have been modified, added or removed, use | ||
+ | |||
+ | git status | ||
+ | |||
+ | Eventually you will have your working directory in the state that you would like to commit. Ensure that you are up-to-date as described above. The next stage depends on whether you want to push your commit directly to the repository (if you have commit rights) or if you want to send your work as a patch. | ||
+ | |||
+ | ===Direct commit=== | ||
+ | |||
+ | Make a local commit: | ||
+ | |||
+ | git commit -a | ||
+ | |||
+ | This will prompt you for a commit message. The "-a" means "all registered files". This will make a local commit in your repository. Push this commit to the central repository: | ||
+ | |||
+ | git push | ||
+ | |||
+ | These two commands together are equivalent to "svn commit". | ||
+ | |||
+ | Your work is now in the central repository, and you are done. | ||
+ | |||
+ | ===Submitting a patch file=== | ||
+ | |||
+ | Sometimes you don't have commit access to the repository, or you want to have your work reviewed by someone else before you commit it. You can package up your changes into a "patch file" with | ||
+ | |||
+ | git diff > ~/patches/MyWork.patch | ||
+ | |||
+ | This file can be emailed or added to an issue-tracker. | ||
+ | |||
+ | Suppose you need to modify your work. Edit the working-copy files to incorporate the modifications, and then generate a new patch file as above. Repeat until the patch is final. | ||
+ | |||
+ | If you are responsible for committing the accepted patch, you can use the procedure in "Direct commit" above. If someone else has committed it, you don't need your local changes any more, and you can erase them using | ||
+ | |||
+ | git checkout | ||
+ | |||
+ | You can then update from the remote repository with | ||
+ | |||
+ | git pull | ||
+ | |||
+ | and you are done. | ||
+ | |||
+ | ==Git style== | ||
+ | |||
+ | This style is useful if you want to keep multiple changes organised locally. | ||
+ | |||
+ | Clone the repository: | ||
+ | |||
+ | git clone <url> | ||
+ | |||
+ | Work on your new feature or bug fix. If you need to add a new file to the repository, use | ||
+ | |||
+ | git add -N <filename> | ||
+ | |||
+ | for the file you have created. (The -N tells git just to register an empty file as added to the repository. If you omit it, the entire file will be put in the staging area, which might not be what you want if you only want to commit part of the file). | ||
+ | |||
+ | If you need to remove a file, use | ||
+ | |||
+ | git rm <filename> | ||
+ | |||
+ | Suppose you now want to bundle up ''some'' of your work into a single unit. This is achieved by making a "local commit". If there are no other changes to the files that contain the work you want to commit, you can make a commit in one step using | ||
+ | |||
+ | git commit <file1><file2> ... | ||
+ | |||
+ | You will be prompted to enter a commit message to describe this change. You can type "git log" to see all the commits, and your new commit will be at the top of the list. If your work is in files which have other changes which you don't want to commit just yet, then you can interactively select which parts of the files to commit using a two-stage process. First you will "add" parts of the files to the "staging area", then you will commit the staging area: | ||
+ | |||
+ | For files which need to be added in their entirety: | ||
+ | |||
+ | git add <file1> <file2> ... | ||
+ | |||
+ | For files which need certain parts only: | ||
+ | |||
+ | git add -p <file1><file2> ... | ||
+ | |||
+ | This will ask you, for each individual change in each file, whether you want to stage that "hunk" or not. You can answer "yes", "no", "all" or "done" by entering the first letter of each. Type "?" for help on the other options. Quitting the interactive "git add" will leave all the hunks you have staged staged. If you want to unstage a hunk, you can use | ||
+ | |||
+ | git reset -p <file1> <file2> ... | ||
+ | |||
+ | This gives you the same interface as "git add -p", but lets you unstage rather than stage each hunk. | ||
+ | |||
+ | You can see all the hunks which are currently staged using | ||
+ | |||
+ | git diff --staged | ||
+ | |||
+ | Once you are happy with what is staged, you can commit it using | ||
+ | |||
+ | git commit | ||
+ | |||
+ | You will be prompted for a commit message. | ||
+ | |||
Every so often, you will want to make sure you are working against the latest version of the code. This is accomplished by | Every so often, you will want to make sure you are working against the latest version of the code. This is accomplished by |
Revision as of 11:07, 30 November 2011
Contents
- 1 Interacting with a remote repository
- 1.1 Check out a repository:
- 1.2 Find out what changes were made to a remote repository since I last pulled:
- 1.3 Update from a repository, if there are no local uncommitted changes:
- 1.4 Update from a repository, if there are local changes:
- 1.5 Push to a repository:
- 1.6 Create a branch containing the current snapshop of the local repository, including all uncommitted changes, and switch to this branch
- 1.7 List all branches
- 1.8 Find out which branch I am on:
- 1.9 Switch to a branch, if there are no uncommitted changes
- 2 Committing
- 2.1 Commit a change:
- 2.2 Modify a commit that hasn't propagated yet, keeping the working tree the same:
- 2.3 Undo a commit that hasn't propagated yet, keeping the working tree the same:
- 2.4 Revert a commit (i.e. create another commit), dropping all changes that it made:
- 2.5 Revert a commit (i.e. create another commit) that may have propagated already, keeping all the changes as local modifications:
- 3 Making local changes
- 3.1 Look at local modifications:
- 3.2 Revert an uncommitted change to a file:
- 3.3 Add a file to the repository:
- 3.4 Remove a file from the repository:
- 3.5 Undo adding a file to the repository:
- 3.6 Undo removing a file from the repository, recreating the file manually:
- 3.7 Undo removing a file from the repository, resurrecting the file in the repository:
- 4 Useful hints
- 5 Workflows
Interacting with a remote repository
This page describes solution to typical needs with git. If you are new to git, please read any of the fine tutorials to learn about the concepts that git offers, and how one would typically work with git.
Later, if you get stuck, or if you maneuvered yourself into a corner, you can come back here to find solutions to particular problems. That is, this page is not organised by "how do I do thing that are natural for git", but rather "how do I map things I need to do onto actions that are natural for git".
This page is split into three parts:
- Interacting with a remote repository (pull, push, merge)
- Local commits
- Working (adding/removing files, undoing changes)
Check out a repository:
git clone <remote-repo-url> <local-repo-name>
For example
git clone git://carpetcode.org/McLachlan McLachlan
Find out what changes were made to a remote repository since I last pulled:
git fetch git log HEAD..origin
Update from a repository, if there are no local uncommitted changes:
git pull --rebase
Hint: If you find you always want to rebase when you pull, then make it the default behavior by setting the autosetuprebase option
git config --global branch.autosetuprebase always
Now whenever you run
git pull
it will do a rebase too.
Update from a repository, if there are local changes:
Save all local changes:
git stash
Then update as described above:
git pull --rebase
Re-apply all local changes:
git stash pop
If there are no conflicts, you are done. If there are conflicts, handle them, then:
git stash drop
since "stash pop" doesn't pop the stash if there are conflicts. "git stash list" shows all stashes. View the content of a stash with "git stash show <stash>".
Push to a repository:
Ensure all remote changes have been pulled (see above), then:
git push
Create a branch containing the current snapshop of the local repository, including all uncommitted changes, and switch to this branch
Create a new branch pointing to the current commit:
git branch <newbranchname>
Check out the new branch:
git checkout <newbranchname>
These can be combined into a single command:
git checkout -b <newbranchname>
List all branches
git branch -a
If you also want to see the relationship to remote branches, use very verbose mode
git branch -vva
Find out which branch I am on:
git branch
The branch marked with a star "*" is the current branch.
Switch to a branch, if there are no uncommitted changes
git checkout <branch-name>
If the branch name happens to be the same as a file name, you can explicitly specify that you're referring to a branch:
git checkout <branch-name> --
Committing
Commit a change:
Commit certain files:
git commit <list-of-files-to-commit>
Commit all modified files which are already under version control:
git commit -a
Modify a commit that hasn't propagated yet, keeping the working tree the same:
git commit --amend <files>
This is the same as "git commit", except it rewrites the last commit instead of creating a new one. <files> lists any files with new changes that you want to include. You can also say "-a" to mean all registered files.
Undo a commit that hasn't propagated yet, keeping the working tree the same:
git reset HEAD~1
This deletes the last commit but leaves the changes from it in the working tree. HEAD~1 means one commit before the latest.
Revert a commit (i.e. create another commit), dropping all changes that it made:
git revert <commit>
If your working tree is not clean, do a "git stash" before and a "git stash pop" after.
Revert a commit (i.e. create another commit) that may have propagated already, keeping all the changes as local modifications:
git show <commit> | git apply -R
Making local changes
Look at local modifications:
List modified files:
git status
Get a diff between the local repo and the working tree ("which changes did I make since the last commit?"):
git diff HEAD [<filename>]
Get a diff between the local repo and the staging area ("which changes did I mark for committing?"):
git diff --staged [<filename>]
Get a diff between the staging area and the working tree ("which of my changes would not be committed?"):
git diff [<filename>]
Get a diff between the remote repository and working tree ("what would a 'git pull' do?"):
git diff origin [<filename>]
Revert an uncommitted change to a file:
git checkout <file>
If there is also a branch with the same name as the file, then we can specify explicitly that we mean the file.
git checkout -- <file>
Add a file to the repository:
First create file locally, then:
git add <list-of-files-to-add> git commit
Remove a file from the repository:
Remove the files from the working tree and mark them as removed in the staging area, then commit the staging area:
git rm <files> git commit
Undo adding a file to the repository:
git reset HEAD <file>
This leaves the file in place, but removes it from version control.
Undo removing a file from the repository, recreating the file manually:
Recreate file locally, then:
git reset HEAD <file>
Undo removing a file from the repository, resurrecting the file in the repository:
git reset HEAD <file> git checkout <file>
Useful hints
Aliases
Aliases are a handy way to simplify the commands needed for your own common tasks. For example, you could add a "what's upstream" command to easily find out which commits will be pulled
git config --global alias.wu '!sh -c "git fetch && git log origin..HEAD"'
From now on, just run
git wu
and it will list the commits which would be merged in by a pull. Similarly, it can be useful to have a "what's downstream" command to know which commits would be pushed:
git config --global alias.wd "log origin..HEAD"
Another useful example is if you often find yourself wanting to do the stash-pull-pop sequence, you could create an alias for that:
git config --global alias.sp '!sh -c "git stash && git pull --rebase && git stash pop"'
Easy rebasing with mergetool
Rebasing is mostly painless with git. The only problem arises when there is a conflicting commit and you have to manually intervene. In this case, the mergetool command can be invaluable:
git mergetool
This will present a diff utility (opendiff on Mac OSX) which allows you to easily select which changes you want. Once you have finished, save and quit, then run
git rebase --continue
If you want more manual control, edit the conflicting files manually and get them how you want them. Make sure to add them:
git add <conflicting-files>
and then continue the rebase:
git rebase --continue
Remove files unknown to git
Sometimes you just want to get rid of all files which aren't under version control. For this use the clean command. First, run
git clean -n
to do a dry-run and see what will be deleted. If you're happy with this change, run
git clean -f
to actually get rid of the files.
Oops, I didn't mean to do that
Don't worry if you accidentally do an operation which you didn't intend to do. It can usually be recovered. For this, the reflog command can be very useful. It essentially lists all recent operations. For example, say you accidentally deleted the last commit using reset and now you realise that you actually do want it after all. Simply run
git reflog
and find the SHA1 of the commit you want in the list, then cherry-pick that commit
git cherry pick <commit-sha1>
Aargh, I made a total mess
It can happen that you get your repository into a hopeless mess and just want to get it back to its original state, disregarding all local changes. This can be achieved using the -f option to checkout
git checkout -f HEAD
This will throw away all local changes and will bring your repository back to the state it would be in if you freshly checked it out (with the exception of files which aren't under version control).
Workflows
These workflows are designed to be self-contained. git is a complicated program, and the documentation can be confusing. The aim of these sections is that if you stick to the commands and techniques used here, you should not get into a mess or need to consult any other git documentation.
SVN style
Clone the repository (like "svn checkout")
git clone <url>
Work on your new feature or bug fix. If you need to add a new file to the repository, use
git add -N <filename>
(like svn add) for the file you have created. (The -N stops the content of the file being added to the "staging area", which would make "git diff" give confusing results. Don't worry about this.) If you need to remove a file, use
git rm <filename>
(like svn rm).
Every so often, you will want to make sure you are working against the latest version of the code. This is accomplished by
git stash git pull git stash pop
This is equivalent to "svn update". When you do the "git stash pop", you may have conflicts between the upstream changes and your own. These will be marked with conflict markers in the source files just like with SVN. You will need to fix these conflicts.
To see what changes you have made in your local copy, use
git diff HEAD
If you want to revert one or more files to its clean state before you started editing it, use
git checkout <file1> <file2> ...
If you want to see what files have been modified, added or removed, use
git status
Eventually you will have your working directory in the state that you would like to commit. Ensure that you are up-to-date as described above. The next stage depends on whether you want to push your commit directly to the repository (if you have commit rights) or if you want to send your work as a patch.
Direct commit
Make a local commit:
git commit -a
This will prompt you for a commit message. The "-a" means "all registered files". This will make a local commit in your repository. Push this commit to the central repository:
git push
These two commands together are equivalent to "svn commit".
Your work is now in the central repository, and you are done.
Submitting a patch file
Sometimes you don't have commit access to the repository, or you want to have your work reviewed by someone else before you commit it. You can package up your changes into a "patch file" with
git diff > ~/patches/MyWork.patch
This file can be emailed or added to an issue-tracker.
Suppose you need to modify your work. Edit the working-copy files to incorporate the modifications, and then generate a new patch file as above. Repeat until the patch is final.
If you are responsible for committing the accepted patch, you can use the procedure in "Direct commit" above. If someone else has committed it, you don't need your local changes any more, and you can erase them using
git checkout
You can then update from the remote repository with
git pull
and you are done.
Git style
This style is useful if you want to keep multiple changes organised locally.
Clone the repository:
git clone <url>
Work on your new feature or bug fix. If you need to add a new file to the repository, use
git add -N <filename>
for the file you have created. (The -N tells git just to register an empty file as added to the repository. If you omit it, the entire file will be put in the staging area, which might not be what you want if you only want to commit part of the file).
If you need to remove a file, use
git rm <filename>
Suppose you now want to bundle up some of your work into a single unit. This is achieved by making a "local commit". If there are no other changes to the files that contain the work you want to commit, you can make a commit in one step using
git commit <file1><file2> ...
You will be prompted to enter a commit message to describe this change. You can type "git log" to see all the commits, and your new commit will be at the top of the list. If your work is in files which have other changes which you don't want to commit just yet, then you can interactively select which parts of the files to commit using a two-stage process. First you will "add" parts of the files to the "staging area", then you will commit the staging area:
For files which need to be added in their entirety:
git add <file1> <file2> ...
For files which need certain parts only:
git add -p <file1><file2> ...
This will ask you, for each individual change in each file, whether you want to stage that "hunk" or not. You can answer "yes", "no", "all" or "done" by entering the first letter of each. Type "?" for help on the other options. Quitting the interactive "git add" will leave all the hunks you have staged staged. If you want to unstage a hunk, you can use
git reset -p <file1> <file2> ...
This gives you the same interface as "git add -p", but lets you unstage rather than stage each hunk.
You can see all the hunks which are currently staged using
git diff --staged
Once you are happy with what is staged, you can commit it using
git commit
You will be prompted for a commit message.
Every so often, you will want to make sure you are working against the latest version of the code. This is accomplished by
git stash git pull git stash pop
This is equivalent to "svn update". When you do the "git stash pop", you may have conflicts between the upstream changes and your own. These will be marked with conflict markers in the source files just like with SVN. You will need to fix these conflicts.
Eventually you will have your working directory in the state that you would like to commit. Ensure that you are up-to-date as described above. The next stage depends on whether you want to push your commit directly to the repository (if you have commit rights) or if you want to send your work as a patch.
Direct commit
Make a local commit:
git commit -a
This will prompt you for a commit message. The "-a" means "all registered files". This will make a local commit in your repository. Push this commit to the central repository:
git push
These two commands together are equivalent to "svn commit".
Your work is now in the central repository, and you are done.
Submitting a patch file
Sometimes you don't have commit access to the repository, or you want to have your work reviewed by someone else before you commit it. You can package up your changes into a "patch file" with
git diff > ~/patches/MyWork.patch
This file can be emailed or added to an issue-tracker.
Suppose you need to modify your work. Edit the working-copy files to incorporate the modifications, and then generate a new patch file as above. Repeat until the patch is final.
If you are responsible for committing the accepted patch, you can use the procedure in "Direct commit" above. If someone else has committed it, you don't need your local changes any more, and you can erase them using
git checkout
You can then update from the remote repository with
git pull
and you are done.