Note: All aliases are listed on this gitconfig file
Table of Contents
Tutorials
Description | Command |
---|---|
Essential commands | git help everyday |
Recommended workflows | git help workflows |
Commit Messages
Since the diff already shows what changed,
- State the purpose of the changes in the heading
- Explain the context in the body
Workflows
Assumptions:
- centralized repos are hosted on some web service
master
is the release/production branchorigin
is the centralized repo we ownupstream
is the centralized repo we contribute to
New features
$ git take feature-branch
# work, and commit
# update branch frequently
$ git down origin/master
# release new feature
$ git go master
$ git merge feature-branch
$ git delete feature-branch
$ git onup
To update feature-branch
with master
changes
$ git rebase master
To keep feature-branch
history as part of master avoid squash
, and fast-forward
.
Only rewrite history in local branches which have not been shared with anyone.
Patches
By design, we can contribute to any repo even when we don’t have access to the centralized repo. Most git web services allow to clone repos using the git://
protocol
$ git clone git://url-to-centralized/repo
Send
Once we are ready to send our changes back to the maintainer
$ git format-patch master --output-dir ./patch
We can also generate patches for a range of commits.
$ git format-patch --output-dir ./patch HEAD~..HEAD
If we worked on a new branch we might need to rebase
before generating a patch to prevent exceptions.
$ git down upstream/master
By default, git creates a patch file per commit. To create a single file we can
$ git format-patch master --stdout > new-feature.patch
We can do a test run to check what we are sending
$ git send-email patch/* --subject='Fix, New feature, etc' --to='maintainer@floss-project.org' --dry-run
Finally, we can send our patches adding a message
$ git send-email patch/* --compose --subject='Fix, New feature, etc' --to='maintainer@floss-project.org' --quiet
It’s considered best practice to
best practice | flag |
---|---|
Request comments | --rfc |
Send multiple files | --numbered |
Detect renames | --find-renames |
Only use --find-renames
when we know the maintainers patch via git
.
Checkout the docs for details on how to configure send-email, and format-patch.
Apply
When we receive a patch is better to review it in a feature branch.
$ git checkout review-new-feature
When we receive the patch as a single file we can
$ cat new-feature.patch | git am
For multiple files we can simply
$ cat *.patch | git am
We can verify we’ve applied the patch correctly with
$ git log --oneline
Beware, the SHA of the patch applied is different from the SHA of the patch sent. Yet, the messages should be left unchanged.
Merge requests
aka pull request
- Find/create an issue you can fix.
- Fork the project’s repo.
- Clone fork to workstation.
- Point clone to
upstream
.
$ git remote -v # list all remote repos
$ git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
- Create a feature branch for each contribution.
- Get changes made on upstream on a regular basis.
- Push the feature branch to
origin
- Create a merge request on the git web service.
Search History
When debuggin focus on how the code got to its current state. To show the full history of some_code
across multiple commits and files use:
$ git log -S "some_code"
Use --patch
to include the full diff, and --reverse
to show when it was added at the top.
Moving Commits
Last n
commits to existing branch
Uncommitted work will get lost.
$ git log-recent
$ git go existing-branch
$ git merge master
$ git go master
$ git undo-for-good HEAD~n
$ git go existing-branch
Alternatively, to move the last commit we can
git uncommit
git stash
git go correct-branch
git stash pop
git add --all # or add individually
Last n
commits to new branch
Uncommitted work will get lost.
$ git log-recent
$ git branch new-branch
$ git undo-for-good a1b2c3d4
$ git go new-branch
Empty commits
From time to time we need to create an empty commit to trigger the CI pipeline
$ git commit --allow-empty --message "Trigger CI pipeline"
We can also use this technique to init
an empty repo. Which allows us to rebase the first commit.
Change settings
Git Multi-push
Git allows pushing to multiple remote repos. Assuming we’ve already set origin
add origin once more, as well as all mirrors:
$ git remote set-url --add --push origin git@<main-remote.org>:<username>/<repo>.git
$ git remote set-url --add --push origin git@<mirror-remote.com>:<username>/<repo>.git
Verify push settings:
$ git remote -v
Beware that we can only pull
from main-remote
origin repo. To get changes from all mirrors:
$ git fetch --all
Switch Git Services
Whenever we want to switch from one git service provider to another we simply need to do:
$ cd <existing_repo>
$ git remote rename origin old-origin
$ git remote add origin git@<new-upstream.com>:<username>/<repo>.git
$ git push -u origin master
If we want to include all branches, and tags:
$ git push -u origin --all
$ git push -u origin --tags
To delete old-origin
branches, and configuration settings:
$ git remote remove old-origin