A place you can go and play with git without getting into (too much) trouble.
The first thing to decide is whether to just clone
the desired repository or
fork
and clone
it. If I know that I will be making changes, I prefer to work off
a fork, otherwise I just clone the repo. Where this makes a difference is whether
you need to manage remote
repos.
Forking a repo takes place from the github UI. Go to the desire repo and use the Fork
button in the upper right corner of the page. You'll then be asked of where you'd like
to place a copy of the repo, with the default in your local (self) organization. Once
forked (or not) the clone is the same:
git clone https://github.com/<org>/<repo>.git
The last parameter can be cut/paste from the github UI when in the appropriate organization.
If you forked the repo, you'll want to add a remote repo that corresponds to the repository from which your fork was created. Typical naming conventions are:
origin
: denotes the location of the default repository. In forked configurations
this will be the destination repo of the fork operation.
upstream
: denotes the location of the source (official) repository and really only
comes into play in forked configurations. This repository will be the target of any
pull requests (PRs) you submit from your branch.
xyz
: You might have other repositories (typically of teams or colleagues) in which
you may want to work.
- To see a list of the repos in use, use:
git remote -v
- To add a remote to your current list, use:
git remote add <remote-name> <repo URL>
For example: If there was a git-sandbox repo in the apache organization one might use:
git remote add upstream https:/github.com/apache/git-sandbox.git
Once issued, git remote -v
should display the repositories available for this working
area.
- To rename a remote, use:
git remote rename <old-name> <new-name>
- To remove a remote, use:
git remote rm <name>
To update your working area (and local repo) with changes applied to master, do the following:
git fetch upstream
# Makes changes fromupstream
availablegit checkout master
# Switch to the master branchgit rebase upstream/master
# Apply changes from master to your local work areagit push origin master
# Push local changes to github repo denoted byorigin
If you also had a dev branch that you wanted to update with master...
git checkout dev-branch
# Switch to the dev branchgit rebase master
# no need to useupstream
since master is already up to date
Note: git fetch --all
gets all remotes you have configured and their branches.
To make changes that are then (eventually) applied to the master source base, do the following:
- Synchronize your work area using the steps described above and create a working branch:
git checkout -b dev-branch
- Make and test necessary changes
git add .
# Prepare all files for commit. If only a subset of changed files are to be committed then onlyadd
those.git commit -m <comment-heading>
# commits the files locally. Use a brief statement that summarizes the changes.git commit --amend
# This command is used to bring up an editor (vi) that allows you to add more verbose comments. In both cases, try to limit the characters in each line to 70. This makes life easier to committer that need to process the changes.git push origin dev-branch
# This pushes the changes to the repo denoted byorigin
and creates adev-branch
branch.
Once changes are in place, a pull request can be created. This is accomplished via the
github UI using the "Create Pull Request" button. If these changes are relative to an
Issue, the comments should include Fixes #<Issue Number>
at the end.
Once changes have been submitted and merged into master, its best to remote the dev branch. This must be done both locally and from the github UI. For the latter, github is usually pretty good about providing a button saying that its okay to delete the branch. To clean up the local branch use:
git branch -d dev-branch
# Sometimes, depending on the way the merge was done, it may be necessary to require a forced deletion by replacing-d
with-D
.
Its best to submit a PR of one commit - although not required. To squash a set of commits into one, use the following:
git log
# Presents a list of commits ordered by date - newest to oldest- Identify the commit hash on which the to-be-squashed commits were applied and call that "original-commit-hash". I.e., the starting point.
git rebase -i <original-commit-hash>
# This is an interactive rebase and will bring up an editor with the set of to-be-squashed commits prefixed with 'pick'.
Change 'pick' to 's' for all but the first one of those items (leaving one to act as the primary commit). (Note: When merging PRs (below)git rebase -i master
from the pr branch only gives commits unique to your branch.)- Edit the header of the next entry to have the appropriate (encompassing) message.
- Push the changes (preferrably to a new branch), delete the original branch and recreate it or, if merging another PR and working in the "pr branch", leave alone.
- To push to a new branch...
git push origin <prev-branch>:<new-branch>
- To delete and recreate the original branch...
git push origin :<prev-branch>
(to delete)git push origin <prev-branch>:<prev-branch>
(to recreate - although haven't done this yet)
- Once pushed (or not in PR merge case) - review the commit and ensure the changes look correct.
Here are steps to merge a commit from a dev branch to the master branch. In summary, the steps first update the dev branch with the latest changes from master, resolving any conflicts that may occur, then cherry-picks the last commit from the newly updated dev branch (which now has master as its basis) back onto master and pushes those updates to applicable repos (upstream and origin).
git fetch upstream
orgit fetch --all
# Get the latest from upstream (et al)git checkout master
# Change to local master branchgit rebase upstream/master
# Apply upstream changes to local master branchgit checkout dev-branch
# Change to local dev-branchgit rebase master
# Apply changes from local master to current branch- Previous command encountered conflicts. Use pyCharm VCS->Git->Resolve
Conflicts to fix middle panel. Once resolved, continue rebase.
(Note: If something goes wrong or a merge doesn't look correct,
issue the following...
git rebase --abort
)- git rebase --continue
TEST CHANGES HERE...
git push --force origin dev-branch
# Local dev branch updated, push to repo (fork in this case)git commit --amend
# Fixup commit comments, add Closes #NNN or whatever.git push --force origin dev-branch
# Push those updates back to repo
If multiple commits are to be merged, its best they be squashed into a single commit...
git checkout dev-branch
Get onto the dev branch (probably there already)git rebase -i master
# Perform interactive rebase (see above), updating all entries except the first which becomes the 'squash commit'. Change 'pick' to 's' for non-first entries.
git log
# Grab the commit hash from the last (first) commit listed in the loggit checkout master
# Switch to local master branchgit log
# Look at the log just to check that things look okay (should not see anything regarding the changes to be merged)git cherry-pick <selected-hash>
# Cherry pick the commit (using the hash select in first git log step)git log
# Look at the log to make sure cherry-picked commit is presentgit push upstream master
# Push merged changes to upstream master branchgit push origin master
# Push merged changes to forked repo master branch
Handy merging aliases - add to [Alias] section of ~/.gitconfig:
[alias]
amenddate='git commit --amend --date=now'
pro = "!f() { git fetch ${2:-origin} pull/$1/head:pr-$1 && git checkout pr-$1; }; f"
pru = "!f() { git fetch ${2:-upstream} pull/$1/head:pr-$1 && git checkout pr-$1; }; f"
-
Create clean clone in separate directory
cd merging
git clone <repo>
cd repo-dir
-
Since clean repo uses origin as the truth, use 'pro' alias (PR origin) using the PR number (303)
git pro 303
-
Now on branch pr-303, check commit log
git log
-
If this is from an issue, ensure 'Fixes #' is present. Add 'Closes #'. Amend the commit.
git commit --amend
-
Switch back to master
git checkout master
-
Check log, if there are commits that weren't in pr-303 besides the PR commit, then need to rebase master to pr branch
git log
-
Additional commits present, go back to pr branch
git checkout pr-303
-
Rebase master to the pr branch
git rebase master
-
Check log to see that only pr commit is different
git log
-
Go back to master branch
git checkout master
-
Merge pr branch to master
git merge pr-303
-
Ensure log shows that local master and pr branch are top, only repos are back one commit
git log
-
Push changes to origin master branch
git push origin master