Git Flows

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 branch
  • origin is the centralized repo we own
  • upstream 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