Some notes about centralized workflow in Git
Basic concepts
- Multi-user development need a
Central Repo
. - Create a bare repo as the
central repo
:git init --bare central-repo.git
.--bare
means that we don’t want a working directory. Thecentral repo
is only supposed to act as a storage facility–not a development environment. - To access the central repo on a server:
ssh://user@example.com/path/to/central-repo.git
. - Before pushing local updates to the central repo, we must ensure the history clean as it’s hardly possible to change history after it has been made public. Never rebase commits that have been pushed to a shared repo.
- If you need to change a public commit, use the
git revert
to undo the changes. This creates a new commit with the required modifications instead of re-writing old snapshots. - Git won’t let anyone push to a remote server if it doesn’t result in a fast-forward merge. In order to solve the problem, we can pull in the central changes before trying to push local changes.
- Get the latest version of the
origin/master
branch$ git fetch origin
- Rebase your changes on top of those found in your central repo, i.e. add your changes to whoever else has already done.
$ git rebase origin/master
- After the rebase, your master branch contains everything from the central repo, so you can do a fast-forward push to publish your changes.
$ git push origin master ##
- The central communication hub condenses all the developments into a single repo and ensures that no one overwrite another’s content.
Quick Reference
git init --bare <repository-name>
Create a Git repository, but omit the working directory.
git remote rm <remote-name>
Remove the specified remote from your bookmarked connections.
Notes from man
git pull
=git fetch
+git rebase
|get merge
.If any of the remote changes overlap with local uncommitted changes, the merge will be automatically canceled and the work tree untouched. It is generally best to get any local changes in working order before pulling or stash them away with git-stash.
NOTE ABOUT FAST-FORWARDS:
When an update changes a branch (or more in general, a ref) that used to point at commit A to point at another commit B, it is called a fast-forward update if and only if B is a descendant of A. In a fast-forward update from A to B, the set of commits that the original commit A built on top of is a subset of the commits the new commit B builds on top of. Hence, it does not lose any history. In contrast, a non-fast-forward update will lose history. For example, suppose you and somebody else started at the same commit X, and you built a history leading to commit B while the other person built a history leading to commit A. The history looks like this: B / ---X---A Further suppose that the other person already pushed changes leading to A back to the original repository from which you two obtained the original commit X. The push done by the other person updated the branch that used to point at commit X to point at commit A. It is a fast-forward. But if you try to push, you will attempt to update the branch (that now points at A) with commit B. This does not fast-forward. If you did so, the changes introduced by commit A will be lost, because everybody will now start building on top of B. The command by default does not allow an update that is not a fast-forward to prevent such loss of history. If you do not want to lose your work (history from X to B) or the work by the other person (history from X to A), you would need to first fetch the history from the repository, create a history that contains changes done by both parties, and push the result back. You can perform "git pull", resolve potential conflicts, and "git push" the result. A "git pull" will create a merge commit C between commits A and B. B---C / / ---X---A Updating A with the resulting merge commit will fast-forward and your push will be accepted. Alternatively, you can rebase your change between X and B on top of A, with "git pull --rebase", and push the result back. The rebase will create a new commit D that builds the change between X and B on top of A. B D / / ---X---A Again, updating A with this commit will fast-forward and your push will be accepted. There is another common situation where you may encounter non-fast-forward rejection when you try to push, and it is possible even when you are pushing into a repository nobody else pushes into. After you push commit A yourself (in the first picture in this section), replace it with "git commit --amend" to produce commit B, and you try to push it out, because forgot that you have pushed A out already. In such a case, and only if you are certain that nobody in the meantime fetched your earlier commit A (and started building on top of it), you can run "git push --force" to overwrite it. In other words, "git push --force" is a method reserved for a case where you do mean to lose history.
When
git-rebase
, All changes made by commits in the current branch but that are not in<upstream>
are saved to a temporary area. This is the same set of commits that would be shown bygit log <upstream>..HEAD
. The commits then reapplied to the current branch, one by one, in order.
本作品采用《CC 协议》,转载必须注明作者和本文链接