To be able to collaborate on any Git project, you need to know how to manage your remote repositories. Remote repositories are versions of your project that are hosted on the internet or network somewhere. You can have several of them, each of which generally is either read-only or read/write for you. Collaborating with others involves managing these remote repositories and pushing and pulling data to and from them when you need to share work. Managing remote repositories includes knowing how to add remote repositories, remove remotes that are no longer valid, manage various remote branches and define them as being tracked or not, and more. In this section, we’ll cover some of these remote-management skills.
note:
Note Remote repositories can be on your local machine. It is entirely possible that you can be working with a “remote” repository that is, in fact, on the same host you are. The word “remote” does not necessarily imply that the repo is somewhere else on the network or Internet, only that it is elsewhere. Working with such a remote repo would still involve all the standard pushing, pulling and fetching operations as with any other remote.
To see which remote servers you have configured, you can run the git remote
command. It lists the shortnames of each remote handle you’ve specified. If you’ve cloned your repository, you should at least see origin
— that is the default name Git gives to the server (you cloned from:
$ git clone https://...
...
$ cd ticgit
$ git remote
origin
You can also specify -v
, which shows you the URLs that Git has stored for the shortname to be used when reading and writing to that remote:
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
If you have more than one remote, the command lists them all.
Notice that these remotes use a variety of protocols; we’ll cover more about this in Getting Git on a Server.
We’ve mentioned and given some demonstrations of how the git clone
command implicitly adds the origin
remote for you.
how to add a new remote?
run git remote add
$ git remote add pd https://github.com/paulboone/ticgit
$ git fetch <remote>
This command pulls down all the data from that remote project that you don’t have yet. After you do this, you should have references to all the branches from that remote, which you can merge in or inspect at any time.
It’s important to note that the git fetch
command only downloads the data to your local repository — it doesn’t automatically merge it with any of your work or modify what you’re currently working on. You have to merge it manually into your work when you’re ready.
If your current branch is set up to track a remote branch (see the next section and Git Branching), you can use the git pull
command to automatically fetch and then merge that remote branch into your cur branch. and by default, the git clone
command automatically sets up your local master
branch to track the remote master
branch (or whatever the default branch is called)
you can run this to push any commits you’ve done to the server:
$ git push origin master
This command works only if …and if nobody has pushed in the meantime. If you and someone else clone at the same time and they push upstream and then you push upstream, your push will rightly be rejected. You’ll have to fetch their work first and incorporate it into yours.
[ incorporate ]: to include sth so that it forms a part of sth. 吸收 absorb, integrated, contain, involve. -corporate,全体的 公司的
see more information about a remote
$ git remote show origin
* remote origin
Fetch URL: https://github.com/schacon/ticgit
Push URL: https://github.com/schacon/ticgit
HEAD branch: master
Remote branches:
master tracked
dev-branch tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
master merges with remote master
For example, it tells you that if you’re on the master
branch and you run git pull
, it will automatically merge the remote’s master
branch into the local one after it has been fetched.
It also tells you which remote branches on the server you don’t have.
To really understand the way Git does branching, we need to take a step back and examine how Git stores its data.
As you may remember from What is Git?, Git doesn’t store data as a series of changesets or differences, but instead as a series of snapshots.
When you make a commit, Git stores a commit object (that contains a pointer to the snapshot of the content you staged. This object also contains the author’s name and email address, the message that you typed, and pointers its parent or parents commit: zero parents for the initial commit, one parent for a normal commit, / * and multiple parents for a commit that results from a merge of two or more branches.* /
To visualize this, let’s assume that you have a directory containing three files, and you stage them all and commit. Staging the files computes a checksum for each one (the SHA-1 hash we mentioned in What is Git?), stores that version of the file in the Git repository (Git refers to them as blobs), and adds that checksum to the staging area:
为了直观地说明这一点,我们假设有一个包含三个文件的目录,你把它们全部stage后提交。stage文件的过程会计算出每个文件的校验和(《什么是 Git?)
[^ stage ]: n舞台; 阶段,phase, stage by stage; v筹划 put on, to hold; 这里可以把stage译为分期提交,commit为提交。
[^ checksum]:
When you create the commit by running git commit
, Git checksums each subdirectory (in this case, just the root project directory) and stores them as a tree object in the Git repository. Git then creates a commit object that has the metadata and a pointer to the root project tree so it can re-create that snapshot when needed.
Your Git repository now contains five objects: three blobs (each representing the contents of one of the three files), one tree that lists the contents of the directory and specifies which file names are stored as which blobs, and one commit with the pointer to that root tree and all the commit metadata.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qjN0G1Tz-1679886560192)(D:\TempCode\JAVA\MD\GIT.assets\image-20221123005906591.png)]
Figure 9. A commit and its tree
If you make some changes and commit again, the next commit stores a pointer to the parent.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kg6LqZzx-1679886560194)(D:\TempCode\JAVA\MD\GIT.assets\image-20221011133643016-16654666105482.png)]
A branch in Git is simply a lightweight movable pointer to one of these commits. The default branch name in Git is master
. As you start making commits, you’re given a master
branch (that points to the last commit you made. Every time you commit, the master
branch pointer moves forward.
Git 中的一个分支只是一个指向这些提交的轻量级可移动指针。
Note | |
---|---|
The “master” branch in Git is not a special branch. It is exactly like any other branch. The only reason nearly every repository has one is that the git init command creates it by default and most people don’t bother to change it. |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0UPLZWoH-1679886560196)(D:\TempCode\JAVA\MD\GIT.assets\image-20221207163659237.png)]
Figure 11. A branch and its commit history
Doing so creates a new pointer for you to move around. Let’s say you want to create a new branch called testing
.
$ git branch testing
This creates a new pointer to the same commit you’re currently on.
$ git checkout -b issue53
# this is shorthand for
$ git branch issue53
$ git checkout issue53
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZPIzvNc2-1679886560197)(D:\TempCode\JAVA\MD\GIT.assets\basic-merging-1.png)]
merge: hotfix -> master
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
g
If you want to see which files are unmerged at any point after a merge conflict, you can run git status
:
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add ..." to mark resolution)
both modified: index.html
no changes added to commit
如上所示,unmerged file 是 index.html
Git adds standard conflict-resolution markers to the files that have conflicts
<<<<<<< HEAD:index.html
=======
>>>>>>> iss53:index.html
The version in HEAD
(your master
branch, because that was what you had checked out when you ran your merge command) is the top part
Resolve this conflict by replacing the entire block with this:
After you’ve resolved each of these sections in each conflicted file, run git add
on each file to mark it as resolved. Staging the file marks it as resolved in Git.
If you want to use a graphical tool to resolve these issues, you can run git mergetool
, which fires up an appropriate visual merge tool and walks you through the conflicts:
after resolving
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
...
when everything that had conflicts has been staged, you can type git commit
to finalize the merge commit.
$ git branch
iss53
* master
testing
To see the last commit on each branch, you can run git branch -v
:
$ git branch -v
iss53 93b412c Fix javascript issue
* master 7a98805 Merge branch 'iss53'
testing 782fd34 Add scott to the author list in the readme
… delete will fail:
$ git branch -d testing
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.
If you really do want to delete the branch and lose that work, you can force it with -D
, as the helpful message points out.
$ git branch --move bad-branch-name corrected-branch-name
Remote references are references (pointers) in your remote repositories, including branches, tags, and so on. You can get a full list of remote references with git ls-remote
, or git remote show
for remote branches as well as more information. Nevertheless, a more common way is to take advantage of remote-tracking branches.
Remote-tracking branches are references to the state of remote branches. They’re local references that you can’t move;
Remote-tracking branch names take the form
.
This may be a bit confusing, so let’s look at an example. Let’s say you have a Git server on your network at git.ourcompany.com
. If you clone from this, Git’s clone
command creates a pointer to where its master
branch is, and names it origin/master locally.
Then someone else pushes to git.ourcompany.com
.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MscNBVUw-1679886560198)(D:\TempCode\JAVA\MD\GIT.assets\image-20221011142255275.png)]
note
Don’t type your password every time
If you’re using an HTTPS URL to push over, the Git server will ask you for your username and password for authentication. By default it will prompt you on the terminal for this information so the server can tell if you’re allowed to push.
You pushed sth to serverfix
…
The next time one of your collaborators fetches from the server, they will get a reference (to where the server’s version(/commit pointer/) of serverfix
is | under the remote branch origin/serverfix
:
It’s important to note that when you do a fetch that brings down new remote-tracking branches, you don’t automatically have local, editable copies of them. In other words, in this case, you don’t have a new serverfix
branch — you have only an origin/serverfix
pointer that you can’t modify.
To merge this work into your current working branch, you can run git merge origin/serverfix
. If you want your own serverfix
branch that you can work on, you can base it off your remote-tracking branch:
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
$ git checkout -b arg1
#. this is shorthand for
$ git branch arg1
$ git checkout arg1
This gives you a local branch that you can work on that starts where origin/serverfix
is.
这就给了你一个本地分支,你可以从origin/serverfix的位置开始工作。
Checking out a local branch from a remote-tracking branch creates what is called a “tracking branch” (and the branch it tracks is called an “upstream branch”). Tracking branches are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type git pull
, Git knows which server to fetch from and which branch to merge in.
When you clone a repository, it generally creates a master
branch that tracks origin/master
. …run git checkout -b
. This is a common enough operation that Git provides the --track
shorthand:
这是一个很常见的操作,所以Git提供了–track的速记。
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
If the branch name you’re trying to checkout (a) doesn’t exist and (b) exactly matches a remote branch name,
$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
If you already have a local branch and want to set it to a remote branch you just pulled down, or want to change the upstream branch you’re tracking, you can use the -u
or --set-upstream-to
option to git branch
to explicitly set it at any time.
If you want to list what tracking branches you have set up
$ git branch -vv
iss53 7e424c3 [origin/iss53: ahead 2] Add forgotten brackets
master 1ae2a45 [origin/master] Deploy index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] This should do it
testing 5ea463a Try something new
So here we can see that our iss53
branch is tracking origin/iss53
and is “ahead” by two, meaning that we have two commits locally that are not pushed to the server. We can also see that our master
branch is tracking origin/master
and is up to date. Next we can see that our serverfix
branch is tracking the server-fix-good
branch on our teamone
server and is ahead by three and behind by one, meaning that there is one commit on the server we haven’t merged in yet and three commits locally that we haven’t pushed. /解決起來好麻煩啊/
set upstream to 2nd upstream:
dell@DESKTOP-JG47OUR MINGW64 /d/authing/repo/sdk/authing-java-sdk-v5 (feat/v3-api-test)
$ git push -u gitee-origin/feat/v3-api-test
fatal: 'gitee-origin/feat/v3-api-test' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
$ git push -u gitee-origin
Enumerating objects: 1830, done.
Counting objects: 100% (1830/1830), done.
Delta compression using up to 6 threads
Compressing objects: 100% (358/358), done.
Writing objects: 100% (1721/1721), 392.97 KiB | 12.68 MiB/s, done.
Total 1721 (delta 1253), reused 1652 (delta 1188), pack-reused 0
remote: Resolving deltas: 100% (1253/1253), completed with 50 local objects.
remote: Powered by GITEE.COM [GNK-6.4]
remote: Create a pull request for 'feat/v3-api-test' on Gitee by visiting:
remote: https://gitee.com/enchanter1cl/authing-java-sdk-v5/pull/new/enchanter1cl:feat/v3-api-test...enchanter1cl:master
To https://gitee.com/enchanter1cl/authing-java-sdk-v5.git
* [new branch] feat/v3-api-test -> feat/v3-api-test
branch 'feat/v3-api-test' set up to track 'gitee-origin/feat/v3-api-test'.
In Git, there are two main ways to integrate changes from one branch into another: the merge
and the rebase
.
Figure 36. Merging to integrate
You can take the patch of the change that was introduced in C4
and reapply it on top of C3
. In Git, this is called rebasing. With the rebase
command, you can take all the changes that were committed on one branch and replay them on a different branch.
For this example, you would check out the experiment
branch, and then rebase it onto the master
branch as follows:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
Figure 37. Rebasing the change introduced in C4
onto C3
At this point, you can go back to the master
branch and do a fast-forward merge.
$ git checkout master
$ git merge experiment
Figure 38. Fast-forwarding the master
branch
A remote repository is generally a bare repository — a Git repository that has no working directory. Because the repository is only used as a collaboration point, there is no reason to have a snapshot checked out on disk; it’s just the Git data. In the simplest terms, a bare repository is the contents of your project’s .git
directory and nothing else.
y and nothing else.
Git can use four distinct protocols to transfer data: Local, HTTP, Secure Shell (SSH) and Git. Here we’ll discuss what they are and in what basic circumstances you would want (or not want) to use them.
Smart HTTP operates very similarly to the SSH or Git protocols but runs over standard HTTPS ports and can use various HTTP authentication mechanisms, meaning it’s often easier on the user than something like SSH, since you can use things like username/password authentication rather than having to set up SSH keys.
It has probably become the most popular way to use Git now, since it can be set up to both serve anonymously like the git://
protocol, and can also be pushed over with authentication and encryption like the SSH protocol.
智能HTTP的操作与SSH或Git协议非常相似,但它通过标准的HTTPS端口运行,并可以使用各种HTTP认证机制,这意味着它通常比SSH之类的东西对用户更容易,因为你可以使用诸如用户名/密码认证,而不是必须设置SSH密钥。
它可能已经成为现在最流行的使用Git的方式,因为它可以被设置为像git://协议那样的匿名服务,也可以像SSH协议那样通过认证和加密推送。
If you try to push and the repository requires authentication (which it normally should), the server can prompt for a username and password. The same goes for read access.
In fact, for services like GitHub, the URL you use to view the repository online (for example, https://github.com/schacon/simplegit) is the same URL you can use to clone and, if you have access, push over.
A common transport protocol for Git when self-hosting is over SSH. This is because SSH access to servers is already set up in most places — and if it isn’t, it’s easy to do. SSH is also an authenticated network protocol and, because it’s ubiquitous, it’s generally easy to set up and use.
To clone a Git repository over SSH, you can specify an ssh://
URL like this:
SSH协议
在自我托管的情况下,Git 的常见传输协议是通过 SSH。这是因为大多数地方都已经设置了 SSH 访问服务器,如果没有,也很容易做到。SSH 也是一个经过验证的网络协议,而且因为它无处不在,所以一般来说,它很容易设置和使用。
要通过 SSH 克隆一个 Git 仓库,你可以指定一个 ssh:// 的 URL,像这样。
$ git clone ssh://[user@]server/project.git
Or you can use the shorter scp-like syntax for the SSH protocol:
$ git clone [user@]server:project.git
In both cases above, if you don’t specify the optional username, Git assumes the user you’re currently logged in as.
Now we’ll cover setting up a Git service [running these protocols on your own server.
In order to initially set up any Git server, you have to export an existing repository into a new bare repository — a repository that doesn’t contain a working directory.
run the clone command with the --bare
option. By convention, bare repository directory names end with the suffix .git
, like so:
$ git clone --bare my_project my_project.git
You should now have a copy of the Git directory data in your my_project.git
directory.
[^ should]: expect sth is true or will happen
Let’s say you’ve set up a server called git.example.com
to which you have SSH access, and you want to store all your Git repositories under the /srv/git
directory.
$ scp -r my_project.git [email protected]:/srv/git
GitWeb is pretty simplistic though. If you’re looking for a modern, fully featured Git server, there are several open source solutions out there. As GitLab is one of the popular ones, we’ll cover installing and using it as an example.
If you don’t want to go through all of the work involved in setting up your own Git server, you have several options for hosting your Git projects on an external dedicated hosting site.
If your Pull Request becomes out of date or otherwise doesn’t merge cleanly, you will want to fix it so the maintainer can easily merge it. GitHub will test this for you and let you know at the bottom of every Pull Request if the merge is trivial or not.
create a brand-new Git repository, or connect an existing Git project. We won’t belabor this here; if you need a refresher, check out Git Basics.
Now that your project is hosted on GitHub, you can give the URL to anyone you want to share your project with. Every project on GitHub is accessible over HTTPS as https://github.com/
, and over SSH as [email protected]:
. Git can fetch from and push to both of these URLs, but they are access-controlled.