Marc's suggested git workflow¶
This is (the start of) a simple git workflow that I have found reasonable to use. I'm not extremely experience in the use of
git, so please improve these instructions if you know better.
repository: the "database" used to manage a set of files. A
git repository usually resides in a (hidden) directory named
.git; you will rarely need to touch this directory or files in it directly.
working tree: the set of files and directories in your filesystem which are under management with
clean: a working tree is clean if it matches the
HEAD of your repository.
To get started, you need to make a local copy, or clone, of the remote (central) repository. This gives you a full (local) copy of the remote repository. Most of the
git commands you will use will access and modify your local repository;
git pull and
git push are the two major exceptions.
git clone ssh://p-SOMEPROJECT@cdcvs.fnal.gov/cvs/projects/SOMEPROJECT
This will create a directory named
SOMEPROJECT under your current working directory; this directory will contain a copy of the SOMEPROJECT repository. Since this gives you a complete local copy of the repository, you can make whatever changes you want to your repository without having any effect on the central repository you just cloned.
Making local changes¶
In order to make it easy to work incrementally on changes to
SOMEPROJECT, and to avoid collisions with others' work, I find it useful to do essentially all my development on a branch. By doing the same, you can make speculative changes of whatever scale you want, and decide when you are done whether to keep those changes (by merging the changes back onto your
master branch, after updating your branch to a state that makes it "as if" your changes had all been added in one change; this is done with
git rebase, as described below), or to abandon those changes (by not doing anything, except possibly deleting your abandoned branch). It is easy to keep several branches under development at the same time, if you are working on unrelated items in the same repository (e.g. changes to two different documents). Any branches you make are visible only locally, to you, not to others sharing use of the central
This technique of making all your changes on a local branch, and updating with
merge takes a few more steps than working directly on the
master branch. It has the virtue of avoiding almost all merge collisions, and it keeps the history of changes in the central repository very easy to understand. Please do not take the short-cut of working directly on the master; that may make you avoid a few commands in the short term, but is certain to eventually cause much more work both for yourself and for others.
Finding out what is your active branch¶
To find out what is your active branch, use:
This lists all the branches in your repository, and indicates the current branch with an asterisk. If you also want to see the branches that reflect the branches in the "central" repository, use
git branch -a.
Creating a branch¶
To create a new branch, and simultaneously make it your currently active branch, use:
git checkout -b name-of-my-new-branch
where name-of-my-new-branch should be replaced by the name you want your new branch to have.
This both creates the branch (in your repository) and makes it be your currently active branch. This command does not modify your working tree. You should use this command only if your working tree is clean.
Checking to see if your working tree is clean¶
To find out if your working tree is clean, use:
This will tell you of any files you have modified, or any files you've added without committing.
Changing your current branch¶
You can change freely between branches, if you've committed all your changes to your current branch. The command to change your current branch, to an already existing branch, is:
git checkout name-of-already-existing-branch
Note the lack of the
-b, which would create a new branch and move to it.
This command will fail, with an error message, if you have changes to your working tree that have not been committed. So, before switching to a different branch, make sure to commit all your changes. If you want to abandon the changes, you can use
git checkout name-of-file-to-restore to restore the repository version of a file you have modified. If you have many files to restore, you might use
git reset --hard. Be careful, because you can't recover your changes if you lose changes if files you didn't mean to lose.
Saving the results you like¶
When you have a set of changes you want to keep as your main line of development, you need to merge the branch containing those changes back into the
- Commit all the changes in your working tree to your development branch
- Set your working branch to be
- Get any updates to
masterfrom the central repository, using
- If the
git pulldownloads any new commits from the central repository, update your branch so that it's changes are added after the ones you just obtained. This is done with
git rebase master name-of-working-branch, where name-of-working-branch should be replaced by the actual name of your working branch. If the modifications you just obtained with the @pulldo not collide with any of your changes, the
rebasewill succeed (possibly with a few messages about automated merges being made). If there is a collision that has to be handled "by hand", see the instructions on resolving a rebase collision below. After resolving any collisions, continue with the next step.
- Then merge the development branch into the master, with:
git merge --ff-only name-of-development-branch
-ff-only helps make sure the additions you are making will not cause any merge conflicts. If you have followed the procedure above, it should succeed.
Once you have merged your changes back into your master branch, you can delete the development branch without losing any work:
git branch -d name-of-develoment-branch
Resolving a rebase collision¶
git rebase x y command is unable to automatically merge changes, it will tell you with a detailed message, which ends in something like:
When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort".
At this point,
git status will tell you that you are not on any branch. This is the indication that you have some merges to resolve "by hand".
git status will also tell you what file(s) need to be fixed.
git will have annotated those files with "change markers", like:
which appears at the start of the section of the file changed in the HEAD of the repository (what you've just
pulledfrom the central repository, if you're following these instructions), and
which divides the @pull-ed changes from your local changes, and
>>>>>>> Fix spelling
which ends your local changes. The text "Fix spelling" is the commit message I used in my example; you should see your own commit message.
To complete the merge, edit the file with whatever editor you prefer, producing the text you want to have as the resolution of the conflict. When you are done, the git change markers should be removed.
Then do a
git add of that file, followed by
git rebase --continue.
You may have to repeat this several times, for several different files (or even for several different collisions in the same file). When all the collisions are resolved, continue with the steps above.
Forgetting about changes you don't like¶
If you decide your development branch was junk, and want to get rid of it, do not merge it back into master. Instead, you can either:
- leave it be, because it doesn't take much room in your repository and you may later decide it was good after all, or
- throw the branch away, with
git branch -D name-of-development-branch
Note the capital letter D: this will delete a branch that contains work not otherwise saved, so be careful with it.
Sending your changes back to the central repository¶
After you have merged your changes onto your local master branch, you may want to send those changes back to the central repository. First, you should always make sure to download any changes from the central repository to your repository. Second, you can upload your changes.
To download changes from the central repository to your repository, use:
To upload your changes to the central repository, use:
Comparing your working tree to the remote (central) repository¶
To compare your working tree to the remote (central) repository from which it was cloned, one first fetches the changes from the remote repository into your local clone -- but without merging those changes into the
master branch of your own repository. To do this, use git fetch (not git pull, which was used above).
Now the branch your local repository has as origin/master matches what is in the master branch of the shared remote repository.
To compare your working tree to this branch, use the "triple dot" syntax of git diff:
git diff origin/master ... master
If your version of git is too old to have this shorthand, then you can do it "by hand":
git merge-base origin/master master # some long SHA1 is returned git diff the-SHA1-from-above
Either of these command sets (the triple-dot diff or the two-step merge-base + diff incantation) shows the changes that have been introduced to the remote (shared) repository since you last merged with it. After you have convinced yourself that you want to merge the changes from the remote repository into your master branch, you should use git merge to do so:
git merge origin/master