A Git commit is a snapshot of tracked files, not a private draft. Push one to a shared repository and it may end up in teammates’ clones, build systems, and backups. That matters if the commit contains an unfinished feature—or a credential that should never have been there.
Git helps a team coordinate changes and trace how a project evolved. It does not decide who may merge, check whether code is safe, or keep secrets out of history. For that, a team needs small changes, review, access controls, and care with sensitive files.
Start with a repository everyone can understand
Most repositories have a shared default branch, often called main, and short-lived branches for individual changes. The default branch should be in a state the team is willing to build and test. A feature branch lets a contributor work without putting unfinished commits on that shared baseline.
Before editing, run git status to check the current branch and any local changes. Pull the latest shared work using your team’s agreed method, then create a branch with a name that describes the task, such as fix/config-error-message. Keep customer data, credentials, and other sensitive details out of branch names.
Use a project-level .gitignore to exclude generated build output, local settings, and dependency caches. If contributors need to know which settings to supply, track a safe example such as config.example.json. An entry in .gitignore helps prevent an untracked file from being added; it does not untrack a file Git already knows about or erase an earlier commit.
The Git overview explains Git’s distributed model: each clone can hold project history. That is handy for offline work, but it also means deleting a sensitive line in a later commit will not remove the earlier version from other clones.
Make changes easy to inspect
Give each commit a clear purpose. Fixing an error message and adding its test belong together; an unrelated dependency upgrade does not. Before committing, check the working tree and the staged patch:
git statusidentifies modified, staged, and untracked files.git diffshows unstaged changes;git diff --stagedshows what the next commit will contain.git add path/to/filestages a chosen file. Usegit add -pto stage selected portions if a file contains unrelated edits.
Describe the change in the commit message, rather than the act of saving it. Handle missing config file without crashing tells a teammate more than updates. If the reason for a change needs explaining—why a particular default was chosen, for instance—put it in the commit body or review description.

Use review as a conversation, not a gate to rush through
A pull request or merge request should say what behavior changed, how you tested it, and what limitations remain. Reviewers can then judge the patch against its stated purpose. Tests can catch regressions; a person may notice an unclear assumption, an accidentally included file, or a change that misses the request. Neither makes the result automatically secure.
For an important branch, having someone other than the author review changes is a sensible baseline, even on a small team. Repository settings can require review and passing checks before a merge, and block direct pushes to the default branch. Give contributors only the permissions they need. Someone proposing an outside contribution, for example, should not need production credentials to submit a patch.
Short-lived branches and single-purpose patches make review less of a chore. If two developers are changing the same area, talk early instead of waiting for a conflict. Git may combine edits on different lines without complaint, but it cannot tell whether those edits still work together.
Choose a predictable way to synchronize work
Fetching downloads remote commits without changing your checked-out files. Merging combines histories; rebasing replays local commits onto a newer base. Either can bring a feature branch up to date. Agree on the team’s approach before anyone rewrites history that others may be using.
Avoid rebasing or amending commits that someone else has based work on. Their identifiers change, leaving collaborators to reconcile diverging histories. Cleaning up commits on a personal, unpublished branch is usually less disruptive. Force-pushing a shared branch, on the other hand, can discard work teammates can already see; branch protection helps prevent it.
When Git reports a conflict, open the affected files and read both versions in context. Conflict markers show competing text, not which behavior is right. Run the relevant tests after resolving the files and before finishing the merge or rebase. A resolution can be syntactically clean yet still remove a necessary condition or duplicate a function call.
Keep credentials and private data out of history
Do not commit passwords, API tokens, private keys, production environment files, or real customer records. Keep local configuration outside Git, and use an approved secret store for build and deployment systems. Document setting names with harmless example values so new contributors can set up the project without borrowing someone else’s credentials.
Inspect staged changes before every commit, particularly after a broad command such as git add .. Secret scanning offers another warning, but it can miss credentials that do not match known patterns or flag harmless test strings. Human inspection and limited access still matter. Check issue descriptions, commit messages, and screenshots too: a clean source file does not mean those other places are safe to share.
If a secret makes it into a commit, treat it as exposed. Revoke or rotate it through the service that issued it, then remove it from current files. Rewriting history may limit future exposure, but it cannot reliably retrieve copies from clones, caches, or logs. Coordinate any rewrite with repository administrators and collaborators so they can recover their local work.

Protect the path from commit to release
A successful merge is not the same as a trustworthy release. Run automated tests against proposed changes and make failures clear. Restrict who can edit workflow files or approve deployments: build automation may hold credentials or publishing permissions. Give automation credentials the narrowest practical scope, and keep sensitive values away from untrusted contribution builds.
A release tag identifies a particular project state, provided the team controls who can create or change release references. Some projects sign commits or tags to help verify an author’s identity. A signature is useful evidence when keys and identities are managed carefully; it does not prove the code is correct or harmless.
A beginner project can start with a manageable baseline: protect the default branch, require review, run tests before merging, and limit release permissions. Add controls as you understand the project’s risks. A long checklist is no replacement for knowing who can change what.
Recover carefully when something goes wrong
Before undoing a change, find out whether it is still local, pushed to a private feature branch, or already merged. For a published bad commit, git revert is usually the least surprising correction: it makes a new commit that reverses the selected change without rewriting shared history. If only part of the change was wrong, a targeted fix commit may make more sense.
Be careful with git reset --hard, which can discard uncommitted work, and with force-pushing rewritten history, which can disrupt teammates. If you only need to inspect an earlier version, use git log to locate the commit and view its diff before changing anything. Check the branch and working tree with git status before attempting a fix.
On the next shared change, branch from the current default branch, stage only the intended files, and read git diff --staged. Include the test result in the review description. If a local configuration file appears in the staged patch, take it out of the staging area before you commit.
