这是用户在 2024-9-14 24:53 为 https://dev.to/unseenwizzard/learn-git-concepts-not-commands-4gjc 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

DEV Community 开发社区

Nico Riedmann
Nico Riedmann 尼科·里德曼

Posted on • Updated on • Originally published at riedmann.dev
发表于• 更新于• 最初发布于riedmann.dev

2960 778 3 4 8

Learn git concepts, not commands
学习 git 概念,而不是命令

An interactive git tutorial meant to teach you how git works, not just which commands to execute.
交互式 git 教程旨在教您 git 如何工作,而不仅仅是执行哪些命令。

So, you want to use git right?
那么,你想使用 git 对吗?

But you don't just want to learn commands, you want to understand what you're using?
但您不仅仅想学习命令,您想了解您正在使用什么?

Then this is meant for you!
那么这就是为您准备的!

Let's get started! 让我们开始吧!


Based on the general concept from Rachel M. Carmena's blog post on How to teach Git.
基于 Rachel M. Carmena 的关于如何教授 Git的博客文章中的一般概念。

While I find many git tutorials on the internet to be too focused on what to do instead of how things work, the most invaluable resource for both (and source for this tutorial!) are the git Book and Reference page.
虽然我发现互联网上的许多 git 教程过于关注要做什么而不是事情如何工作,但两者最宝贵的资源(以及本教程的来源!)是git 书籍参考页面

So if you're still interested when you're done here, go check those out! I do hope the somewhat different concept of this tutorial will aid you in understanding all the other git features detailed there.
因此,如果您完成这里后仍然感兴趣,请去查看一下!我确实希望本教程中有些不同的概念能够帮助您理解其中详细介绍的所有其他 git 功能。



Overview  概述

In the picture below you see four boxes. One of them stands alone, while the other three are grouped together in what I'll call your Development Environment.
在下图中,您可以看到四个盒子。其中一个是独立的,而其他三个则组合在一起,我将其称为“开发环境”

git components

We'll start with the one that's on it's own though. The Remote Repository is where you send your changes when you want to share them with other people, and where you get their changes from. If you've used other version control systems there's nothing interesting about that.
我们将从它自己的一个开始。当您想要与其他人共享更改时,远程存储库是您发送更改的地方,也是您从中获取更改的地方。如果您使用过其他版本控制系统,那就没有什么有趣的了。

The Development Environment is what you have on your local machine.
开发环境是您本地计算机上的环境。

The three parts of it are your Working Directory, the Staging Area and the Local Repository. We'll learn more about those as we start using git.
它的三个部分是工作目录暂存区本地存储库。当我们开始使用 git 时,我们将了解更多相关内容。

Choose a place in which you want to put your Development Environment.
选择您想要放置开发环境的位置。

Just go to your home folder, or where ever you like to put your projects. You don't need to create a new folder for your Dev Environment though.
只需转到您的主文件夹,或者您喜欢放置项目的任何位置。不过,您不需要为您的开发环境创建新文件夹。

Getting a Remote Repository
获取远程存储库

Now we want to grab a Remote Repository and put what's in it onto your machine.
现在我们想要获取一个远程存储库并将其中的内容放到您的计算机上。

I'd suggest we use this one (https://github.com/UnseenWizzard/git_training.git if you're not already reading this on github).
我建议我们使用这个( https://github.com/UnseenWizzard/git_training.git ,如果你还没有在 github 上阅读这篇文章)。

To do that I can use git clone https://github.com/UnseenWizzard/git_training.git
为此我可以使用 git clone https://github.com/UnseenWizzard/git_training.git

But as following this tutorial will need you to get the changes you make in your Dev Environment back to the Remote Repository, and github doesn't just allow anyone to do that to anyone's repo, you'll best create a fork of it right now. There's a button to do that on the top right of this page.
但是,按照本教程,您将需要将您在开发环境中所做的更改返回到远程存储库,并且 github 不仅允许任何人对任何人的存储库执行此操作,您最好立即创建它的分支。此页面的右上角有一个按钮可以执行此操作。

Now that you have a copy of my Remote Repository of your own, it's time to get that onto your machine.
现在您已经拥有了我的远程存储库的副本,是时候将其放到您的计算机上了。

For that we use git clone https://github.com/{YOUR USERNAME}/git_training.git
为此我们使用 git clone https://github.com/{YOUR USERNAME}/git_training.git

As you can see in the diagram below, this copies the Remote Repository into two places, your Working Directory and the Local Repository.
如下图所示,这会将远程存储库复制到两个位置:工作目录本地存储库

Now you see how git is distributed version control. The Local Repository is a copy of the Remote one, and acts just like it. The only difference is that you don't share it with anyone.
现在您了解了 git 是如何进行分布式版本控制的。本地存储库远程存储库的副本,并且其行为与远程存储库类似。唯一的区别是您不与任何人分享。

What git clone also does, is create a new folder wherever you called it. There should be a git_training folder now. Open it.
git clone还可以在您调用它的地方创建一个新文件夹。现在应该有一个git_training文件夹。打开它。

Cloning the remote repo

Adding new things  添加新事物

Someone already put a file into the Remote Repository. It's Alice.txt, and kind of lonely there. Let's create a new file and call it Bob.txt.
有人已经将文件放入远程存储库中。这是Alice.txt ,那里有点孤独。让我们创建一个新文件并将其命名为Bob.txt

What you've just done is add the file to your Working Directory.
您刚刚所做的是将文件添加到您的工作目录中。

There's two kinds of files in your Working Directory: tracked files that git knows about and untracked files that git doesn't know about (yet).
工作目录中有两种文件:git 知道的跟踪文件和 git 还不知道的未跟踪文件。

To see what's going on in your Working Directory run git status, which will tell you what branch you're on, whether your Local Repository is different from the Remote and the state of tracked and untracked files.
要查看工作目录中发生的情况,请运行git status ,它将告诉您所在的分支、本地存储库是否与远程存储库不同以及跟踪未跟踪文件的状态。

You'll see that Bob.txt is untracked, and git status even tells you how to change that.
您会看到Bob.txt未被跟踪,并且git status甚至会告诉您如何更改它。

In the picture below you can see what happens when you follow the advice and execute git add Bob.txt: You've added the file to the Staging Area, in which you collect all the changes you wish to put into Repository
在下图中,您可以看到当您按照建议并执行git add Bob.txt时会发生什么:您已将文件添加到暂存区域,在其中收集您希望放入存储库的所有更改

Adding changes to the staging area

When you have added all your changes (which right now is only adding Bob), you're ready to commit what you just did to the Local Repository.
添加完所有更改后(现在仅添加 Bob),您就可以将刚刚所做的操作提交Local Repository

The collected changes that you commit are some meaningful chunk of work, so when you now run git commit a text editor will open and allow you to write a message telling everything what you just did. When you save and close the message file, your commit is added to the Local Repository.
提交的收集的更改是一些有意义的工作块,因此当您现在运行git commit时,文本编辑器将打开并允许您编写一条消息,告诉您刚刚所做的一切。当您保存并关闭消息文件时,您的提交将添加到本地存储库中。

Committing to the local repo

You can also add your commit message right there in the command line if you call git commit like this: git commit -m "Add Bob". But because you want to write good commit messages you really should take your time and use the editor.
如果您像这样调用git commit ,您还可以在命令行中添加提交消息git commit -m "Add Bob" 。但是因为您想编写良好的提交消息,所以您确实应该花时间并使用编辑器。

Now your changes are in your local repository, which is a good place for the to be as long as no one else needs them or you're not yet ready to share them.
现在,您的更改位于本地存储库中,只要没有其他人需要它们或者您尚未准备好共享它们,那么这是一个好地方。

In order to share your commits with the Remote Repository you need to push them.
为了与远程存储库共享您的提交,您需要push它们。

Pushing to the local repo

Once you run git push the changes will be sent to the Remote Repository. In the diagram below you see the state after your push.
运行git push后,更改将发送到远程存储库。在下图中,您可以看到push后的状态。

State of all components after pushing changes

Making changes

So far we've only added a new file. Obviously the more interesting part of version control is changing files.
到目前为止我们只添加了一个新文件。显然,版本控制更有趣的部分是更改文件。

Have a look at Alice.txt.
看看Alice.txt

It actually contains some text, but Bob.txt doesn't, so lets change that and put Hi!! I'm Bob. I'm new here. in there.
它实际上包含一些文本,但Bob.txt不包含,所以让我们更改它并输入Hi!! I'm Bob. I'm new here.在那里。

If you run git status now, you'll see that Bob.txt is modified.
如果您现在运行git status ,您将看到Bob.txt已被修改

In that state the changes are only in your Working Directory.
在该状态下,更改仅在您的工作目录中。

If you want to see what has changed in your Working Directory you can run git diff, and right now see this:
如果您想查看工作目录中发生了什么变化,您可以运行git diff ,现在可以看到:

diff --git a/Bob.txt b/Bob.txt
index e69de29..3ed0e1b 100644
--- a/Bob.txt
+++ b/Bob.txt
@@ -0,0 +1 @@
+Hi!! I'm Bob. I'm new here.
Enter fullscreen mode Exit fullscreen mode

Go ahead and git add Bob.txt like you've done before. As we know, this moves your changes to the Staging Area.
继续像之前一样git add Bob.txt 。正如我们所知,这会将您的更改移至暂存区域

I want to see the changes we just staged, so let's show the git diff again! You'll notice that this time the output is empty. This happens because git diff operates on the changes in your Working Directory only.
我想看看我们刚刚进行的更改,所以让我们再次显示git diff !您会注意到这次输出为空。发生这种情况是因为git diff仅对工作目录中的更改进行操作。

To show what changes are staged already, we can use git diff --staged and we'll see the same diff output as before.
为了显示已经暂存的更改,我们可以使用git diff --staged ,我们将看到与以前相同的 diff 输出。

I just noticed that we put two exclamation marks after the 'Hi'. I don't like that, so lets change Bob.txt again, so that it's just 'Hi!'
我刚刚注意到我们在“嗨”后面加了两个感叹号。我不喜欢这样,所以让我们再次更改Bob.txt ,使其只是“嗨!”

If we now run git status we'll see that there's two changes, the one we already staged where we added text, and the one we just made, which is still only in the working directory.
如果我们现在运行git status我们会看到有两个更改,一个是我们已经在添加文本的地方进行的更改,另一个是我们刚刚所做的更改,该更改仍然仅在工作目录中。

We can have a look at the git diff between the Working Directory and what we've already moved to the Staging Area, to show what has changed since we last felt ready to stage our changes for a commit.
我们可以查看工作目录和我们已经移至暂存区域的内容之间的git diff ,以显示自我们上次准备好暂存更改以进行提交以来发生的更改。

diff --git a/Bob.txt b/Bob.txt
index 8eb57c4..3ed0e1b 100644
--- a/Bob.txt
+++ b/Bob.txt
@@ -1 +1 @@
-Hi!! I'm Bob. I'm new here.
+Hi! I'm Bob. I'm new here.
Enter fullscreen mode Exit fullscreen mode

As the change is what we wanted, let's git add Bob.txt to stage the current state of the file.

Now we're ready to commit what we just did. I went with git commit -m "Add text to Bob" because I felt for such a small change writing one line would be enough.

As we know, the changes are now in the Local Repository.
We might still want to know what change we just committed and what was there before.

We can do that by comparing commits.
Every commit in git has a unique hash by which it is referenced.

If we have a look at the git log we'll not only see a list of all the commits with their hash as well as Author and Date, we also see the state of our Local Repository and the latest local information about remote branches.

Right now the git log looks something like this:

commit 87a4ad48d55e5280aa608cd79e8bce5e13f318dc (HEAD -> master)
Author: {YOU} <{YOUR EMAIL}>
Date:   Sun Jan 27 14:02:48 2019 +0100

    Add text to Bob

commit 8af2ff2a8f7c51e2e52402ecb7332aec39ed540e (origin/master, origin/HEAD)
Author: {YOU} <{YOUR EMAIL}>
Date:   Sun Jan 27 13:35:41 2019 +0100

    Add Bob

commit 71a6a9b299b21e68f9b0c61247379432a0b6007c 
Author: UnseenWizzard <nicola.riedmann@live.de>
Date:   Fri Jan 25 20:06:57 2019 +0100

    Add Alice

commit ddb869a0c154f6798f0caae567074aecdfa58c46
Author: Nico Riedmann <UnseenWizzard@users.noreply.github.com>
Date:   Fri Jan 25 19:25:23 2019 +0100

    Add Tutorial Text

      Changes to the tutorial are all squashed into this commit on master, to keep the log free of clutter that distracts from the tutorial

      See the tutorial_wip branch for the actual commit history
Enter fullscreen mode Exit fullscreen mode

In there we see a few interesting things:
在那里我们看到一些有趣的事情:

  • The first two commits are made by me.
    前两次提交是我做出的。
  • Your initial commit to add Bob is the current HEAD of the master branch on the Remote Repository. We'll look at this again when we talk about branches and getting remote changes.
    您最初添加 Bob 的提交是远程存储库master分支的当前HEAD 。当我们讨论分支和获取远程更改时,我们将再次讨论这一点。
  • The latest commit in the Local Repository is the one we just made, and now we know its hash.
    本地存储库中的最新提交是我们刚刚进行的提交,现在我们知道它的哈希值。

Note that the actual commit hashes will be different for you. If you want to know how exactly git arrives at those revision IDs have a look at this interesting article .

To compare that commit and the one one before we can do git diff <commit>^!, where the ^! tells git to compare to the commit one before. So in this case I run git diff 87a4ad48d55e5280aa608cd79e8bce5e13f318dc^!

We can also do git diff 8af2ff2a8f7c51e2e52402ecb7332aec39ed540e 87a4ad48d55e5280aa608cd79e8bce5e13f318dc for the same result and in general to compare any two commits. Note that the format here is git diff <from commit> <to commit>, so our new commit comes second.

In the diagram below you again see the different stages of a change, and the diff commands that apply to where a file currently is.

States of a change an related diff commands

Now that we're sure we made the change we wanted, go ahead and git push.

Branching

Another thing that makes git great, is the fact that working with branches is really easy and integral part of how you work with git.

In fact we've been working on a branch since we've started.

When you clone the Remote Repository your Dev Environment automatically starts on the repositories main or master branch.

Most work-flows with git include making your changes on a branch, before you merge them back into master.
Usually you'll be working on your own branch, until you're done and confident in your changes which can then be merged into the master.

Many git repository managers like GitLab and GitHub also allow for branches to be protected, which means that not everyone is allowed to just push changes there. There the master is usually protected by default.

Don't worry, we'll get back to all of these things in more detail when we need them.

Right now we want to create a branch to make some changes there. Maybe you just want to try something on your own and not mess with the working state on your master branch, or you're not allowed to push to master.

Branches live in the Local and Remote Repository. When you create a new branch, the branches contents will be a copy of the currently committed state of whatever branch you are currently working on.

Let's make some change to Alice.txt! How about we put some text on the second line?

We want to share that change, but not put it on master right away, so let's create a branch for it using git branch <branch name>.

To create a new branch called change_alice you can run git branch change_alice.

This adds the new branch to the Local Repository.

While your Working Directory and Staging Area don't really care about branches, you always commit to the branch you are currently on.

You can think of branches in git as pointers, pointing to a series of commits. When you commit, you add to whatever you're currently pointing to.

Just adding a branch, doesn't directly take you there, it just creates such a pointer.
In fact the state your Local Repository is currently at, can be viewed as another pointer, called HEAD, which points to what branch and commit you are currently at.

If that sounds complicated the diagrams below will hopefully help to clear things up a bit:

State after adding branch

To switch to our new branch you will have to use git checkout change_alice. What this does is simply to move the HEAD to the branch you specify.

As you'll usually want switch to a branch right after creating it, there is the convenient -b option available for the checkout command, which allows you to just directly checkout a new branch, so you don't have to create it beforehand.

So to create and switch to our change_alice branch, we could also just have called git checkout -b change_alice.

State after after switching branch

You'll notice that your Working Directory hasn't changed. That we've modified Alice.txt is not related to the branch we're on yet.
您会注意到您的工作目录没有更改。我们修改的Alice.txt与我们所在的分支无关。

Now you can add and commit the change to Alice.txt just like we did on the master before, which will stage (at which point it's still unrelated to the branch) and finally commit your change to the change_alice branch.
现在,您可以将更改addcommitAlice.txt ,就像我们之前在master上所做的那样,它将暂存(此时它仍然与分支无关),并最终将您的更改提交change_alice分支。

There's just one thing you can't do yet. Try to git push your changes to the Remote Repository.
只有一件事你还不能做。尝试将更改git push送到远程存储库

You'll see the following error and - as git is always ready to help - a suggestion how to resolve the issue:
您将看到以下错误,并且 - 由于 git 随时准备提供帮助 - 以及如何解决问题的建议:

fatal: The current branch change_alice has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin change_alice 
Enter fullscreen mode Exit fullscreen mode

But we don't just want to blindly do that. We're here to understand what's actually going on. So what are upstream branches and remotes?

Remember when we cloned the Remote Repository a while ago? At that point it didn't only contain this tutorial and Alice.txt but actually two branches.

The master we just went ahead and started working on, and one I called "tutorial_wip" on which I commit all the changes I make to this tutorial.

When we copied the things in the Remote Repository into your Dev Environment a few extra steps happened under the hood.

Git setup the remote of your Local Repository to be the Remote Repository you cloned and gave it the default name origin.

Your Local Repository can track several remotes and they can have different names, but we'll stick to the origin and nothing else for this tutorial.

Then it copied the two remote branches into your Local Repository and finally it checked out master for you.

When doing that another implicit step happens. When you checkout a branch name that has an exact match in the remote branches, you will get a new local branch that is linked to the remote branch. The remote branch is the upstream branch of your local one.

In the diagrams above you can see just the local branches you have. You can see that list of local branches by running git branch.

If you want to also see the remote branches your Local Repository knows, you can use git branch -a to list all of them.

Remote and local branches

Now we can call the suggested git push --set-upstream origin change_alice, and push the changes on our branch to a new remote. This will create a change_alice branch on the Remote Repository and set our local change_alice to track that new branch.

There is another option if we actually want our branch to track something that already exists on the Remote Repository. Maybe a colleague has already pushed some changes, while we were working on something related on our local branch, and we'd like to integrate the two. Then we could just set the upstream for our change_alice branch to a new remote by using git branch --set-upstream-to=origin/change_alice and from there on track the remote branch.

After that went through have a look at your Remote Repository on github, your branch will be there, ready for other people to see and work with.

We'll get to how you can get other people's changes into your Dev Environment soon, but first we'll work a bit more with branches, to introduce all the concepts that also come into play when we get new things from the Remote Repository.

Merging

As you and everyone else will generally be working on branches, we need to talk about how to get changes from one branch into the other by merging them.

We've just changed Alice.txt on the change_alice branch, and I'd say we're happy with the changes we made.

If you go and git checkout master, the commit we made on the other branch will not be there. To get the changes into master we need to merge the change_alice branch into master.

Note that you always merge some branch into the one you're currently at.
请注意,您总是将某个分支merge您当前所在的分支中。

Fast-Forward merging  快进合并

As we've already checked out master, we can now git merge change_alice.
由于我们已经checked out master,我们现在可以git merge change_alice

As there are no other conflicting changes to Alice.txt, and we've changed nothing on master, this will go through without a hitch in what is called a fast forward merge.
由于Alice.txt没有其他冲突的更改,并且我们没有对master进行任何更改,因此这将顺利进行所谓的快进合并。

In the diagrams below, you can see that this just means that the master pointer can simply be advanced to where the change_alice one already is.
在下图中,您可以看到这仅意味着指针可以简单地前进到Change_alice已经所在的位置。

The first diagram shows the state before our merge, master is still at the commit it was, and on the other branch we've made one more commit.
第一个图显示了merge之前的状态, master仍然处于原来的提交状态,而在另一个分支上我们又进行了一次提交。

Before fast forward merge

The second diagram shows what has changed with our merge.
第二张图显示了merge后发生的变化。

After fast forward merge

Merging divergent branches
合并不同的分支

Let's try something more complex.
让我们尝试一些更复杂的东西。

Add some text on a new line to Bob.txt on master and commit it.
master上的Bob.txt中添加一些新行的文本并提交。

Then git checkout change_alice, change Alice.txt and commit.
然后git checkout change_alice ,更改Alice.txt并提交。

In the diagram below you see how our commit history now looks. Both master and change_alice originated from the same commit, but since then they diverged, each having their own additional commit.
在下图中,您可以看到我们的提交历史记录现在的样子。 masterchange_alice都源自同一个提交,但从那时起它们就出现了分歧,每个都有自己的附加提交。

Divergent commits

If you now git merge change_alice a fast-forward merge is not possible. Instead your favorite text editor will open and allow you to change the message of the merge commit git is about to make in order to get the two branches back together. You can just go with the default message right now. The diagram below shows the state of our git history after we the merge.
如果您现在git merge change_alice无法进行快进合并。相反,您最喜欢的文本编辑器将打开并允许您更改 git 即将进行merge commit的消息,以便将两个分支重新组合在一起。您现在可以使用默认消息。下图显示了merge后 git 历史记录的状态。

Merging branches

The new commit introduces the changes that we've made on the change_alice branch into master.
新的提交将我们在change_alice分支上所做的更改引入到master中。

As you'll remember from before, revisions in git, aren't only a snapshot of your files but also contain information on where they came from from. Each commit has one or more parent commits. Our new merge commit, has both the last commit from master and the commit we made on the other branch as it's parents.
正如您之前所记得的,git 中的修订不仅是文件的快照,还包含有关它们来自何处的信息。每个commit都有一个或多个父提交。我们的新merge提交既有来自master 的最后一次提交,也有我们在另一个分支上作为其父级所做的提交。

Resolving conflicts  解决冲突

So far our changes haven't interfered with each other.
到目前为止,我们的更改还没有相互干扰。

Let's introduce a conflict and then resolve it.
让我们引入一个冲突,然后解决它。

Create and checkout a new branch. You know how, but maybe try using git checkout -b to make your live easier.
创建并checkout一个新分支。你知道怎么做,但也许尝试使用git checkout -b让你的生活更轻松。

I've called mine bobby_branch.
我把我的称为bobby_branch

On the branch we'll make a change to Bob.txt.
在分支上,我们将对Bob.txt进行更改。

The first line should still be Hi!! I'm Bob. I'm new here.. Change that to Hi!! I'm Bobby. I'm new here.
第一行应该仍然是Hi!! I'm Bob. I'm new here. 。将其更改为Hi!! I'm Bobby. I'm new here.

Stage and then commit your change, before you checkout master again. Here we'll change that same line to Hi!! I'm Bob. I've been here for a while now. and commit your change.
在再次checkout master之前,暂存并commit更改。在这里我们将同一行更改为 Hi!! I'm Bob. I've been here for a while now.commit您的更改。

Now it's time to merge the new branch into master.
现在是时候将新分支mergemaster中了。

When you try that, you'll see the following output
当您尝试这样做时,您将看到以下输出

    Auto-merging Bob.txt
    CONFLICT (content): Merge conflict in Bob.txt
    Automatic merge failed; fix conflicts and then commit the result.
Enter fullscreen mode Exit fullscreen mode

The same line has changed on both of the branches, and git can't handle this on it's own.
两个分支上的同一行都发生了更改,并且 git 无法自行处理此问题。

If you run git status you'll get all the usual helpful instructions on how to continue.
如果您运行git status您将获得有关如何继续的所有常用有用说明。

First we have to resolve the conflict by hand.
首先,我们必须手动解决冲突。

For an easy conflict like this one your favorite text editor will do fine. For merging large files with lots of changes a more powerful tool will make your life much easier, and I'd assume your favorite IDE comes with version control tools and a nice view for merging.
对于像这样的简单冲突,您最喜欢的文本编辑器就可以很好地解决。对于合并有大量更改的大文件,更强大的工具将使您的生活变得更加轻松,并且我假设您最喜欢的 IDE 附带版本控制工具和漂亮的合并视图。

If you open Bob.txt you'll see something similar to this (I've truncated whatever we might have put on the second line before):
如果你打开Bob.txt你会看到类似的内容(我已经截断了之前放在第二行的内容):

    <<<<<<< HEAD
    Hi! I'm Bob. I've been here for a while now.
    =======
    Hi! I'm Bobby. I'm new here.
    >>>>>>> bobby_branch
    [... whatever you've put on line 2]
Enter fullscreen mode Exit fullscreen mode

On top you see what has changed in Bob.txt on the current HEAD, below you see what has changed in the branch we're merging in.
在顶部,您可以看到当前 HEAD 上Bob.txt中发生的更改,在下面您可以看到我们要合并的分支中发生的更改。

To resolve the conflict by hand, you'll just need to make sure that you end up with some reasonable content and without the special lines git has introduced to the file.
要手动解决冲突,您只需要确保最终得到一些合理的内容,并且没有 git 引入到文件中的特殊行。

So go ahead and change the file to something like this:
因此,继续将文件更改为如下所示:

    Hi! I'm Bobby. I've been here for a while now.
    [...]
Enter fullscreen mode Exit fullscreen mode

From here what we're doing is exactly what we'd do for any changes.
从这里开始,我们所做的正是我们为任何改变所做的。

We stage them when we add Bob.txt, and then we commit.
我们在add Bob.txt暂存它们,然后commit

We already know the commit for the changes we've made to resolve the conflict. It's the merge commit that is always present when merging.
我们已经知道为解决冲突而做出的更改的承诺。合并时始终存在合并提交

Should you ever realize in the middle of resolving conflicts that you actually don't want to follow through with the merge, you can just abort it by running git merge --abort.
如果您在解决冲突的过程中意识到您实际上不想进行merge ,则可以通过运行git merge --abortabort它。

Rebasing  变基

Git has another clean way to integrate changes between two branches, which is called rebase.
Git 有另一种简洁的方法来集成两个分支之间的更改,称为rebase

We still recall that a branch is always based on another. When you create it, you branch away from somewhere.
我们仍然记得,一个分支总是基于另一个分支。当你创建它时,你就从某个地方分支出来

In our simple merging example we branched from master at a specific commit, then committed some changes on both master and the change_alice branch.
在我们的简单合并示例中,我们在特定提交处从master分支,然后在masterchange_alice分支上提交了一些更改。

When a branch is diverging from the one it's based on and you want to integrate the latest changes back into your current branch, rebase offers a cleaner way of doing that than a merge would.
当一个分支与其所基于的分支不同,并且您希望将最新更改集成回当前分支时, rebase提供了一种比merge更干净的方法。

As we've seen, a merge introduces a merge commit in which the two histories get integrated again.
正如我们所看到的, merge引入了合并提交,其中两个历史记录再次集成。

Viewed simply, rebasing just changes the point in history (the commit) your branch is based on.
简单地看,变基只是改变分支所基于的历史点(提交)。

To try that out, let's first checkout the master branch again, then create/checkout a new branch based on it.
要尝试一下,我们首先再次签出master分支,然后基于它创建/签出一个新分支。

I called mine add_patrick and I added a new Patrick.txt file and committed that with the message 'Add Patrick'.
我调用了我的add_patrick ,添加了一个新的Patrick.txt文件,并使用消息“添加 Patrick”提交了该文件。

When you've added a commit to the branch, get back to master, make a change and commit it. I added some more text to Alice.txt.
当您向分支添加提交后,返回master ,进行更改并提交。我向Alice.txt添加了更多文本。

Like in our merging example the history of these two branches diverges at a common ancestor as you can see in the diagram below.
就像我们的合并示例一样,这两个分支的历史在一个共同的祖先处出现分歧,如下图所示。

History before a rebase

Now let's checkout add_patrick again, and get that change that was made on master into the branch we work on!
现在让我们再次checkout add_patrick ,并将在master上所做的更改放入我们工作的分支中!

When we git rebase master, we re-base our add_patrick branch on the current state of the master branch.
当我们git rebase master时,我们将add_patrick分支重新建立在master分支的当前状态上。

The output of that command gives us a nice hint at what is happening in it:
该命令的输出很好地提示了其中发生的情况:

    First, rewinding head to replay your work on top of it...
    Applying: Add Patrick
Enter fullscreen mode Exit fullscreen mode

As we remember HEAD is the pointer to the current commit we're at in our Dev Environment.
我们记得HEAD是指向我们在开发环境中当前提交的指针。

It's pointing to the same place as add_patrick before the rebase starts. For the rebase, it then first moves back to the common ancestor, before moving to the current head of the branch we want to re-base ours on.
在变基开始之前,它指向与add_patrick相同的位置。对于变基,它首先移回共同祖先,然后再移至我们想要重新建立基础的分支的当前头部。

So HEAD moves from the 0cfc1d2 commit, to the 7639f4b commit that is at the head of master.
因此HEAD0cfc1d2提交移动到master头部的7639f4b提交。

Then rebase applies every single commit we made on our add_patrick branch to that.
然后 rebase 将我们在add_patrick分支上所做的每一个提交应用到该分支上。

To be more exact what git does after moving HEAD back to the common ancestor of the branches, is to store parts of every single commit you've made on the branch (the diff of changes, and the commit text, author, etc.).
更准确地说,在将HEAD移回分支的共同祖先后, git所做的事情是将您在分支上所做的每个提交的部分存储(更改的diff 、提交文本、作者等) 。

After that it does a checkout of the latest commit of the branch you're rebasing on, and then applies each of the stored changed as a new commit on top of that.
之后,它checkout您要变基的分支的最新提交,然后将每个存储的更改应用为在此基础上的新提交

So in our original simplified view, we'd assume that after the rebase the 0cfc1d2 commit doesn't point to the common ancestor anymore in it's history, but points to the head of master.
因此,在我们最初的简化视图中,我们假设在rebase之后, 0cfc1d2提交不再指向其历史记录中的共同祖先,而是指向 master 的头。

In fact the 0cfc1d2 commit is gone, and the add_patrick branch starts with a new 0ccaba8 commit, that has the latest commit of master as its ancestor.
事实上, 0cfc1d2提交已经消失, add_patrick分支以新的0ccaba8提交开始,该提交以master的最新提交作为其祖先。

We made it look, like our add_patrick was based on the current master not an older version of it, but in doing so we re-wrote the history of the branch.
我们让它看起来,就像我们的add_patrick是基于当前的master而不是旧版本一样,但在这样做的过程中,我们重写了分支的历史。


At the end of this tutorial we'll learn a bit more about re-writing history and when it's appropriate and inappropriate to do so.
在本教程的最后,我们将了解更多有关重写历史以及何时适当和不适当的知识。

History after rebase

Rebase is an incredibly powerful tool when you're working on your own development branch which is based on a shared branch, e.g. the master.
当您在基于共享分支(例如master )的自己的开发分支上工作时, Rebase是一个非常强大的工具。

Using rebase you can make sure that you frequently integrate the changes other people make and push to master, while keeping a clean linear history that allows you to do a fast-forward merge when it's time to get your work into the shared branch.
使用 rebase,您可以确保经常集成其他人所做的更改并推送到master ,同时保持干净的线性历史记录,使您可以在需要将工作放入共享分支时进行fast-forward merge

Keeping a linear history also makes reading or looking at (try out git log --graph or take a look at the branch view of GitHub or GitLab) commit logs much more useful than having a history littered with merge commits, usually just using the default text.
保持线性历史记录还使得阅读或查看(尝试git log --graph或查看GitHubGitLab的分支视图)提交日志比拥有散布着合并提交的历史记录更有用,通常只使用默认值文本。

Resolving conflicts  解决冲突

Just like for a merge you may run into conflicts, if you run into two commits changing the same parts of a file.
就像merge一样,如果您遇到两次提交更改文件的相同部分,您可能会遇到冲突。

However when you encounter a conflict during a rebase you don't fix it in an extra merge commit, but can simply resolve it in the commit that is currently being applied.
但是,当您在rebase期间遇到冲突时,您不会在额外的合并提交中修复它,而可以简单地在当前正在应用的提交中解决它。

Again, basing your changes directly on the current state of the original branch.
再次强调,您的更改直接基于原始分支的当前状态。

Actually resolving conflicts while you rebase is very similar to how you would for a merge so refer back to that section if you're not sure anymore how to do it.
实际上,在rebase时解决冲突与merge方式非常相似,因此如果您不确定如何执行此操作,请返回该部分。

The only distinction is, that as you're not introducing a merge commit there is no need to commit your resolution. Simply add the changes to the Staging Environment and then git rebase --continue. The conflict will be resolved in the commit that was just being applied.
唯一的区别是,由于您没有引入合并提交,因此无需commit您的解决方案。只需将更改add暂存环境,然后git rebase --continue 。冲突将在刚刚应用的提交中解决。

As when merging, you can always stop and drop everything you've done so far when you git rebase --abort.
与合并时一样,当您git rebase --abort时,您始终可以停止并放弃迄今为止所做的一切。

Updating the Dev Environment with remote changes
通过远程更改更新开发环境

So far we've only learned how to make and share changes.
到目前为止,我们只学习了如何进行和共享更改。

That fits what you'll do if you're just working on your own, but usually there'll be a lot of people that do just the same, and we're gonna want to get their changes from the Remote Repository into our Dev Environment somehow.
如果您只是自己工作,这适合您要做的事情,但通常会有很多人做同样的事情,我们希望将他们的更改从远程存储库获取到我们的开发环境不知何故。

Because it has been a while, lets have another look at the components of git:
因为已经有一段时间了,我们再看一下git的组件:

git components

Just like your Dev Environment everyone else working on the same source code has theirs.
就像您的开发环境一样,使用相同源代码的其他人都有自己的开发环境。

many dev environments

All of these Dev Environments have their own working and staged changes, that are at some point committed to the Local Repository and finally pushed to the Remote.
所有这些开发环境都有自己的工作分阶段更改,这些更改在某个时刻committed本地存储库并最终pushed远程

For our example, we'll use the online tools offered by GitHub, to simulate someone else making changes to the remote while we work.
对于我们的示例,我们将使用GitHub提供的在线工具来模拟其他人在我们工作时对远程进行更改。

Go to your fork of this repo on github.com and open the Alice.txt file.
转到github.com上此存储库的fork并打开Alice.txt文件。

Find the edit button and make and commit a change via the website.
找到编辑按钮并通过网站进行并提交更改。

github edit

In this repository I have added a remote change to Alice.txt on a branch called fetching_changes_sample, but in your version of the repository you can of course just change the file on master.
在此存储库中,我在名为fetching_changes_sample的分支上添加了对Alice.txt的远程更改,但在您的存储库版本中,您当然可以只更改master上的文件。

Fetching Changes
获取更改

We still remember that when you git push, you synchronize changes made to the Local Repository into the Remote Repository.
我们仍然记得,当您git push时,将对本地存储库所做的更改同步到远程存储库中。

To get changes made to the Remote into your Local Repository you use git fetch.
要将对远程所做的更改放入本地存储库,请使用git fetch

This gets any changes on the remote - so commits as well as branches - into your Local Repository.
这会将远程上的任何更改(因此会提交以及分支)放入您的本地存储库中。

Note that at this point, changes aren't integrated into the local branches and thus the Working Directory and Staging Area yet.
请注意,此时,更改尚未集成到本地分支中,因此还没有集成到工作目录暂存区域中

Fetching changes

If you run git status now, you'll see another great example of git commands telling you exactly what is going on:
如果你现在运行git status ,你会看到另一个很好的 git 命令示例,告诉你到底发生了什么:

    git status
    On branch fetching_changes_sample
    Your branch is behind 'origin/fetching_changes_sample' by 1 commit, and can be fast-forwarded.
      (use "git pull" to update your local branch)
Enter fullscreen mode Exit fullscreen mode

Pulling Changes
拉动变更

As we have no working or staged changes, we could just execute git pull now to get the changes from the Repository all the way into our working area.
由于我们没有工作分阶段的更改,因此我们现在可以执行git pull将更改从存储库一直获取到我们的工作区域。

Pulling will implicitly also fetch the Remote Repository, but sometimes it is a good idea to do a fetch on it's own.
拉取也会隐式地fetch远程存储库,但有时最好自行进行fetch

For example when you want to synchronize any new remote branches, or when you want to make sure your Local Repository is up to date before you do a git rebase on something like origin/master.
例如,当您想要同步任何新的远程分支时,或者当您想在对origin/master之类的内容执行git rebase之前确保本地存储库是最新的时。

Pulling in changes

Before we pull, lets change a file locally to see what happens.
在我们pull之前,让我们在本地更改一个文件,看看会发生什么。

Lets also change Alice.txt in our Working Directory now!
现在我们还可以更改工作目录中的Alice.txt

If you now try to do a git pull you'll see the following error:
如果您现在尝试执行git pull您将看到以下错误:

    git pull
    Updating df3ad1d..418e6f0
    error: Your local changes to the following files would be overwritten by merge:
            Alice.txt
    Please commit your changes or stash them before you merge.
    Aborting
Enter fullscreen mode Exit fullscreen mode

You can not pull in any changes, while there are modifications to files in the Working Directory that are also changed by the commits you're pulling in.
您无法pull取任何更改,但工作目录中的文件有一些修改,这些修改也会因您pull入的提交而更改。

While one way around this is, to just get your changes to a point where you're confident in them, add them to the Staging Environment, before you finally commit them, this is a good moment to learn about another great tool, the git stash.
虽然解决这个问题的一种方法是,为了让您的更改达到您对它们有信心的程度,请将它们add暂存环境中,然后再最终commit它们,这是了解另一个很棒的工具git stash好时机git stash

Stashing changes  隐藏更改

If at any point you have local changes that you do not yet want to put into a commit, or want to store somewhere while you try some different angle to solve a problem, you can stash those changes away.
如果在任何时候您不想将本地更改放入提交中,或者在尝试从不同角度解决问题时希望将其存储在某个位置,则可以stash起来。

A git stash is basically a stack of changes on which you store any changes to the Working Directory.
git stash基本上是一堆更改,您可以在其中存储对工作目录的任何更改。

The commands you'll mostly use are git stash which places any modifications to the Working Directory on the stash, and git stash pop which takes the latest change that was stashed and applies it the to the Working Directory again.
您最常使用的命令是git stashgit stash pop ,前者会将对工作目录的任何修改保存到存储中,后者获取存储的最新更改并将其再次应用到工作目录

Just like the stack commands it's named after git stash pop removes the latest stashed change before applying it again.
就像堆栈命令一样,它以git stash pop命名,会在再次应用之前删除最新的隐藏更改。

If you want to keep the stashed changes, you can use git stash apply, which doesn't remove them from the stash before applying them.
如果您想保留隐藏的更改,可以使用git stash apply ,它不会在应用它们之前将它们从存储中删除。

To inspect you current stash you can use git stash list to list the individual entries, and git stash show to show the changes in the latest entry on the stash.
要检查当前的stash您可以使用git stash list列出各个条目,并git stash show显示stash上最新条目的更改。

Another nice convenience command is git stash branch {BRANCH NAME}, which creates a branch, starting from the HEAD at the moment you've stashed the changes, and applies the stashed changes to that branch.
另一个不错的方便命令是 git stash branch {BRANCH NAME} ,它会从您存储更改时的 HEAD 开始创建一个分支,并将存储的更改应用到该分支。

Now that we know about git stash, lets run it to remove our local changes to Alice.txt from the Working Directory, so that we can go ahead and git pull the changes we've made via the website.
现在我们了解了git stash ,让我们运行它来从工作目录中删除对Alice.txt的本地更改,以便我们可以继续git pull我们通过网站所做的更改。

After that, let's git stash pop to get the changes back.
之后,让我们git stash pop来取回更改。

As both the commit we pulled in and the stashed change modified Alice.txt you wil have to resolve the conflict, just how you would in a merge or rebase.
由于我们pull的提交和stash的更改都修改了Alice.txt因此您必须解决冲突,就像在mergerebase中一样。

When you're done add and commit the change.
完成后addcommit更改。

Pulling with Conflicts  冲突拉动

Now that we've understood how to fetch and pull Remote Changes into our Dev Environment, it's time to create some conflicts!
现在我们已经了解了如何fetch远程更改并将pull入我们的开发环境中,是时候创建一些冲突了!

Do not push the commit that changed Alice.txt and head back to your Remote Repository on github.com.
不要push更​​改了Alice.txt提交并返回github.com上的远程存储库

There we're also again going to change Alice.txt and commit the change.
我们还将再次更改Alice.txt并提交更改。

Now there's actually two conflicts between our Local and Remote Repositories.
现在我们的本地存储库和远程存储库之间实际上存在两个冲突。

Don't forget to run git fetch to see the remote change without pulling it in right away.
不要忘记运行git fetch来查看远程更改,而不是立即将其pull入。

If you now run git status you will see, that both branches have one commit on them that differs from the other.
如果您现在运行git status您将看到,两个分支都有一个与另一个不同的提交。

    git status
    On branch fetching_changes_sample
    Your branch and 'origin/fetching_changes_sample' have diverged,
    and have 1 and 1 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)
Enter fullscreen mode Exit fullscreen mode

In addition we've changed the same file in both of those commits, to introduce a merge conflict we'll have to resolve.
此外,我们在这两次提交中更改了同一文件,以引入我们必须解决的merge冲突。

When you git pull while there is a difference between the Local and Remote Repository the exact same thing happens as when you merge two branches.
当您git pull时,当本地存储库和远程存储库之间存在差异时,会发生与merge两个分支时完全相同的情况。

Additionally, you can think of the relationship between branches on the Remote and the one in the Local Repository as a special case of creating a branch based on another.
此外,您可以将远程分支与本地存储库中的分支之间的关系视为基于另一个分支创建分支的一种特殊情况。

A local branch is based on a branches state on the Remote from the time you last fetched it.
本地分支基于您上次fetched远程分支时的分支状态。

Thinking that way, the two options you have to get remote changes make a lot of sense:
这样想,远程更改的两个选项就很有意义:

When you git pull the Local and Remote version of a branch will be merged. Just like merging branches, this will introduce a _merge commit.
当您git pull时,分支的本地远程版本将被merged 。就像merging分支一样,这将引入 _merge 提交。

As any local branch is based on it's respective remote version, we can also rebase it, so that any changes we may have made locally, appear as if they were based on the latest version that is available in the _Remote Repository.
由于任何本地分支都基于其各自的远程版本,因此我们也可以对其rebase ,以便我们在本地所做的任何更改都看起来好像它们基于 _Remote 存储库中可用的最新版本。

To do that, we can use git pull --rebase (or the shorthand git pull -r).
为此,我们可以使用git pull --rebase (或简写git pull -r )。

As detailed in the section on Rebasing, there is a benefit in keeping a clean linear history, which is why I would strongly recommend that whenever you git pull you do a git pull -r.
正如Rebasing部分中详细介绍的那样,保持干净的线性历史记录是有好处的,这就是为什么我强烈建议每当您进行git pull时都执行git pull -r

You can also tell git to use rebase instead of merge as it's default strategy when your git pull, by setting the pull.rebase flag with a command like this git config --global pull.rebase true.
您还可以告诉 git 使用rebase而不是merge因为它是git pull时的默认策略,通过使用如下命令设置pull.rebase标志 git config --global pull.rebase true

If you haven't already run git pull when I first mentioned it a few paragraphs ago, let's now run git pull -r to get the remote changes while making it look like our new commit just happened after them.
如果当我在几段前第一次提到它时您还没有运行git pull ,那么现在让我们运行git pull -r来获取远程更改,同时使其看起来像是我们的新提交刚刚发生在它们之后。

Of course like with a normal rebase (or merge) you'll have to resolve the conflict we introduced for the git pull to be done.
当然,就像普通的rebase (或merge )一样,您必须解决我们引入的冲突才能完成git pull

Cherry-picking  采摘樱桃

Congratulations! You've made it to the more advanced features!
恭喜!您已经掌握了更高级的功能!

By now you understand how to use all the typical git commands and more importantly how they work.
现在您已经了解了如何使用所有典型的 git 命令,更重要的是它们是如何工作的。

This will hopefully make the following concepts much simpler to understand than if I just told you what commands to type in.
与我只是告诉您要输入哪些命令相比,这有望使以下概念更容易理解。

So let's head right in an learn how to cherry-pick commits!
因此,让我们直接学习如何cherry-pick提交!

From earlier sections you still remember roughly what a commit is made off, right?
从前面的部分来看,您仍然大致记得commit的内容,对吧?

And how when you rebase a branch your commits are applied as new commits with the same change set and message?
当您对分支rebase时,您的提交如何应用为具有相同更改集消息的新提交?

Whenever you want to just take a few choice changes from one branch and apply them to another branch, you want to cherry-pick these commits and put them on your branch.
每当您只想从一个分支进行一些选择更改并将它们应用到另一个分支时,您需要cherry-pick这些提交并将它们放在您的分支上。

That is exactly what git cherry-pick allows you to do with either single commits or a range of commits.
这正是git cherry-pick允许您对单个提交或一系列提交执行的操作。

Just like during a rebase this will actually put the changes from these commits into a new commit on your current branch.
就像在rebase期间一样,这实际上会将这些提交中的更改放入当前分支上的新提交中。

Lets have a look at an example each for cherry-picking one or more commits:
让我们看一个例子,每个例子都用于cherry-pick一个或多个提交:

The figure below shows three branches before we have done anything. Let's assume we really want to get some changes from the add_patrick branch into the change_alice branch. Sadly they haven't made it into master yet, so we can't just rebase onto master to get those changes (along with any other changes on the other branch, that we might not even want).
下图显示了我们做任何事情之前的三个分支。假设我们确实希望将一些更改从add_patrick分支转移到change_alice分支中。遗憾的是,他们还没有成为 master,所以我们不能仅仅rebase到 master 来获取这些更改(以及其他分支上的任何其他更改,我们可能甚至不想要)。

Branches before cherry-picking

So let's just git cherry-pick the commit 63fc421.
因此,让我们git cherry-pick提交63fc421

The figure below visualizes what happens when we run git cherry-pick 63fc421
下图直观地展示了当我们运行git cherry-pick 63fc421时会发生什么

Cherry-picking a single commit

As you can see, a new commit with the changes we wanted shows up on branch.
正如您所看到的,包含我们想要的更改的新提交出现在分支上。

At this point note that like with any other kind of getting changes onto a branch that we've seen before, any conflicts that arise during a cherry-pick will have to be resolved by us, before the command can go through.
此时请注意,与我们之前见过的对分支进行任何其他类型的更改一样,在命令执行之前,我们必须先解决cherry-pick中出现的任何冲突。

Also like all other commands you can either --continue a cherry-pick when you've resolved conflicts, or decide to --abort the command entirely.
与所有其他命令一样,您可以在解决冲突后--continue cherry-pick ,或者决定完全--abort该命令。

The figure below visualizes cherry-picking a range of commits instead of a single one. You can simply do that by calling the command in the form git cherry-pick <from>..<to> or in our example below as git cherry-pick 0cfc1d2..41fbfa7.
下图cherry-pick 。您可以简单地通过调用git cherry-pick <from>..<to>形式的命令或在下面的示例中执行此操作 git cherry-pick 0cfc1d2..41fbfa7

Cherry-picking commit range

Rewriting history  改写历史

I'm repeating myself now, but you still remember rebase well enough right? Else quickly jump back to that section, before continuing here, as we'll use what we already know when learning about how change history!
我现在重复一遍,但你还记得rebase对吧?否则,在继续此处之前,请快速跳回该部分,因为我们将在了解如何改变历史时使用我们已经知道的内容!

As you know a commit basically contains your changes, a message and few other things.
如您所知, commit基本上包含您的更改、消息和其他一些内容。

The 'history' of a branch is made up of all it's commits.
分支的“历史”由它的所有提交组成。

But lets say you've just made a commit and then notice, that you've forgotten to add a file, or you made a typo and the change leaves you with broken code.
但是,假设您刚刚进行了commit ,然后注意到您忘记添加文件,或者您犯了一个拼写错误,并且所做的更改导致代码损坏。

We'll briefly look at two things we could do to fix that, and make it look like it never happened.
我们将简要介绍一下我们可以做的两件事来解决这个问题,并让它看起来就像从未发生过一样。

Let's switch to a new branch with git checkout -b rewrite_history.
让我们切换到一个新分支 git checkout -b rewrite_history

Now make some changes to both Alice.txt and Bob.txt, and then git add Alice.txt.
现在对Alice.txtBob.txt进行一些更改,然后git add Alice.txt

Then git commit using a message like "This is history" and you're done.
然后使用诸如“这是历史”之类的消息进行git commit ,就完成了。

Wait, did I say we're done? No, you'll clearly see that we've made some mistakes here:
等等,我说过我们结束了吗?不,你会清楚地看到我们在这里犯了一些错误:

Amending the last Commit  修改最后一次提交

One way to fix both of these in one go would be to amend the commit we've just made.
一次性解决这两个问题的一种方法是amend我们刚刚做出的承诺。

Amending the latest commit basically works just like making a new one.
Amend最新的提交基本上就像创建一个新的提交一样。

Before we do anything take a look at your latest commit, with git show {COMMIT}. Put either the commit hash (which you'll probably still see in your command line from the git commit call, or in the git log), or just HEAD.
在我们做任何事情之前,请使用git show {COMMIT}查看您的最新提交。输入提交哈希(您可能仍然会在git commit的命令行中或在git log中看到它),或者只是HEAD

Just like in the git log you'll see the message, author, date and of course changes.
就像在git log中一样,您将看到消息、作者、日期,当然还有更改。

Now let's amend what we've done in that commit.
现在让我们amend我们在该提交中所做的事情。

git add Bob.txt to get the changes to the Staging Area, and then git commit --amend.
git add Bob.txt以获取对暂存区域的更改,然后git commit --amend

What happens next is your latest commit being unrolled, the new changes from the Staging Area added to the existing one, and the editor for the commit message opening.
接下来发生的事情是展开您的最新提交,将暂存区域中的新更改添加到现有更改,以及打开提交消息的编辑器。

In the editor you'll see the previous commit message.
在编辑器中,您将看到之前的提交消息。

Feel free to change it to something better.
请随意将其更改为更好的东西。

After you're done, take another look at the latest commit with git show HEAD.
完成后,使用git show HEAD再次查看最新的提交。

As you've certainly expected by now, the commit hash is different. The original commit is gone, and in it's place there is a new one, with the combined changes and new commit message.
正如您现在所预料的那样,提交哈希是不同的。原始提交已消失,取而代之的是一个新的提交,其中包含组合的更改和新的提交消息。

Note how the other commit data like author and date are unchanged from the original commit. You can mess with those too, if you really want, by using the extra --author={AUTHOR} and --date={DATE} flags when amending.
请注意其他提交数据(例如作者和日期)与原始提交相比有何变化。如果您确实愿意,您也可以在修改时使用额外的--author={AUTHOR}--date={DATE}标志来搞乱这些内容。

Congratulations! You've just successfully re-written history for the first time!
恭喜!您刚刚第一次成功改写了历史!

Interactive Rebase  交互式变基

Generally when we git rebase, we rebase onto a branch. When we do something like git rebase origin/master, what actually happens, is a rebase onto the HEAD of that branch.
一般来说,当我们git rebase时,我们rebase到一个分支上。当我们执行诸如git rebase origin/master之类的操作时,实际发生的是将 rebase 到该分支的HEAD上。

In fact if we felt like it, we could rebase onto any commit.
事实上,如果我们愿意,我们可以rebase到任何提交。

Remember that a commit contains information about the history that came before it
请记住,提交包含有关其之前的历史记录的信息

Like many other commands git rebase has an interactive mode.
与许多其他命令一样, git rebase交互模式。

Unlike most others, the interactive rebase is something you'll probably be using a lot, as it allows you to change history as much as you want.
与大多数其他方法不同,交互式rebase是您可能会经常使用的东西,因为它允许您根据需要更改历史记录。

Especially if you follow a work-flow of making many small commits of your changes, which allow you to easily jump back if you made a mistake, interactive rebase will be your closest ally.
特别是如果您遵循对更改进行许多小提交的工作流程,这样您就可以在犯了错误时轻松跳回来,那么交互式rebase将是您最亲密的盟友。

Enough talk! Lets do something!
够了!让我们做点什么吧!

Switch back to your master branch and git checkout a new branch to work on.
切换回分支并git checkout一个新分支来工作。

As before, we'll make some changes to both Alice.txt and Bob.txt, and then git add Alice.txt.
和以前一样,我们将对Alice.txtBob.txt进行一些更改,然后git add Alice.txt

Then we git commit using a message like "Add text to Alice".

Now instead of changing that commit, we'll git add Bob.txt and git commit that change as well. As message I used "Add Bob.txt".
现在,我们不再更改该提交,而是git add Bob.txtgit commit该更改。作为消息,我使用了“Add Bob.txt”。

And to make things more interesting, we'll make another change to Alice.txt which we'll git add and git commit. As a message I used "Add more text to Alice".
为了让事情变得更有趣,我们将对Alice.txt进行另一个更改,我们将git addgit commit 。作为一条消息,我使用了“向 Alice 添加更多文本”。

If we now have a look at the branch's history with git log (or for just a quick look preferably with git log --oneline), we'll see our three commits on top of whatever was on your master.
如果我们现在使用git log查看分支的历史记录(或者最好使用git log --oneline快速查看),我们将在master上的任何内容之上看到我们的三个提交。

For me it looks like this:
对我来说,它看起来像这样:

git log --oneline
0b22064 (HEAD -> interactiveRebase) Add more text to Alice
062ef13 Add Bob.txt
9e06fca Add text to Alice
df3ad1d (origin/master, origin/HEAD, master) Add Alice
800a947 Add Tutorial Text
Enter fullscreen mode Exit fullscreen mode

There's two things we'd like to fix about this, which for the sake of learning different things, will be a bit different than in the previous section on amend:
我们想解决两件事,为了学习不同的东西,这将与上一节有关amend内容有所不同:

  • Put both changes to Alice.txt in a single commit
    将对Alice.txt两项更改放在一次提交中
  • Consistently name things, and remove the .txt from the message about Bob.txt
    一致地命名事物,并从有关Bob.txt的消息中删除.txt

To change the three new commits, we'll want to rebase onto the commit just before them. That commit for me is df3ad1d, but we can also reference it as the third commit from the current HEAD as HEAD~3
要更改三个新提交,我们需要重新调整它们之前的提交。对我来说,这个提交是df3ad1d ,但我们也可以将其引用为当前HEAD的第三次提交,即HEAD~3

To start an interactive rebase we use git rebase -i {COMMIT}, so let's run git rebase -i HEAD~3
要启动交互式rebase我们使用git rebase -i {COMMIT} ,所以让我们运行git rebase -i HEAD~3

What you'll see is your editor of choice showing something like this:
您将看到您选择的编辑器显示如下内容:

    pick 9e06fca Add text to Alice
    pick 062ef13 Add Bob.txt
    pick 0b22064 Add more text to Alice
    # Rebase df3ad1d..0b22064 onto df3ad1d (3 commands)
    #
    # Commands:
    # p, pick = use commit
    # r, reword = use commit, but edit the commit message
    # e, edit = use commit, but stop for amending
    # s, squash = use commit, but meld into previous commit
    # f, fixup = like "squash", but discard this commit's log message
    # x, exec = run command (the rest of the line) using shell
    # d, drop = remove commit
    #
    # These lines can be re-ordered; they are executed from top to bottom.
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    #
    # However, if you remove everything, the rebase will be aborted.
    #
    # Note that empty commits are commented out
Enter fullscreen mode Exit fullscreen mode

Note as always how git explains everything you can do right there when you call the command.
请一如既往地注意git如何解释当您调用该命令时您可以立即执行的所有操作。

The Commands you'll probably be using most are reword, squash and drop. (And pick but that one's there by default)

Take a moment to think about what you see and what we're going to use to achieve our two goals from above. I'll wait.
花点时间思考一下您所看到的以及我们将使用什么来实现上面的两个目标。我会等待。

Got a plan? Perfect! 有计划吗?完美的!

Before we start making changes, take note of the fact, that the commits are listed from oldest to newest, and thus in the opposite direction of the git log output.
在我们开始进行更改之前,请注意以下事实:提交是从最旧到最新列出的,因此与git log输出的方向相反。

I'll start off with the easy change and make it so we get to change the commit message of the middle commit.
我将从简单的更改开始,以便我们可以更改中间提交的提交消息。

    pick 9e06fca Add text to Alice
    reword 062ef13 Add Bob.txt
    pick 0b22064 Add more text to Alice
    # Rebase df3ad1d..0b22064 onto df3ad1d (3 commands)
    [...]
Enter fullscreen mode Exit fullscreen mode

Now to getting the two changes of Alice.txt into one commit.
现在将Alice.txt的两项更改合并到一次提交中。

Obviously what we want to do is to squash the later of the two into the first one, so let's put that command in place of the pick on the second commit changing Alice.txt. For me in the example that's 0b22064.
显然,我们想要做的是将两者中的后者squash为第一个,所以让我们将该命令放在第二个提交更改Alice.txt上的pick位置。对于我来说,在示例中是0b22064

    pick 9e06fca Add text to Alice
    reword 062ef13 Add Bob.txt
    squash 0b22064 Add more text to Alice
    # Rebase df3ad1d..0b22064 onto df3ad1d (3 commands)
    [...]
Enter fullscreen mode Exit fullscreen mode

Are we done? Will that do what we want?
我们完成了吗?这会达到我们想要的效果吗?

It wont right? As the comments in the file tell us:
不会吧?正如文件中的注释告诉我们的:

    # s, squash = use commit, but meld into previous commit
Enter fullscreen mode Exit fullscreen mode

So what we've done so far, will merge the changes of the second Alice commit, with the Bob commit. That's not what we want.
到目前为止,我们所做的是将第二个 Alice 提交的更改与 Bob 提交合并。那不是我们想要的。

Another powerful thing we can do in an interactive rebase is changing the order of commits.
我们在交互式rebase中可以做的另一件强大的事情是改变提交的顺序。

If you've read what the comments told you carefully, you already know how: Simply move the lines!
如果您仔细阅读了评论,您已经知道如何操作:只需移动线条即可!

Thankfully you're in your favorite text editor, so go ahead and move the second Alice commit after the first.
值得庆幸的是,您使用的是您最喜欢的文本编辑器,因此请继续将第二个 Alice 提交移到第一个之后。

    pick 9e06fca Add text to Alice
    squash 0b22064 Add more text to Alice
    reword 062ef13 Add Bob.txt
    # Rebase df3ad1d..0b22064 onto df3ad1d (3 commands)
    [...]
Enter fullscreen mode Exit fullscreen mode

That should do the trick, so close the editor to tell git to start executing the commands.
这应该可以解决问题,因此关闭编辑器以告诉git开始执行命令。

What happens next is just like a normal rebase: starting with the commit you've referenced when starting it, each of the commits you have listed will be applied one after the other.
接下来发生的事情就像正常的rebase一样:从您在启动时引用的提交开始,您列出的每个提交都将被一个接一个地应用。

Right now it won't happen, but when you re-order actual code changes, it may happen, that you run into conflicts during the rebase. After all you've possibly mixed up changes that were building on each other.
现在它不会发生,但是当您重新排序实际代码更改时,可能会发生在rebase期间遇到冲突。毕竟,您可能混淆了相互基础的更改。

Just resolve them, as you would usually.
只需像平常一样解决它们即可。

After applying the first commit, the editor will open and allow you to put a new message for the commit combining the changes to Alice.txt. I've thrown away the text of both commits and put "Add a lot of very important text to Alice".
应用第一次提交后,编辑器将打开并允许您为该提交添加一条新消息,并将更改结合到Alice.txt中。我已经扔掉了两个提交的文本,并添加了“向 Alice 添加很多非常重要的文本”。

After you close the editor to finish that commit, it will open again to allow you to change the message of the Add Bob.txt commit. Remove the ".txt" and continue by closing the editor.
关闭编辑器以完成该提交后,它将再次打开以允许您更改Add Bob.txt提交的消息。删除“.txt”并关闭编辑器继续。

That's it! You've rewritten history again. This time a lot more substantially than when amending!
就是这样!你再次改写了历史。这次比amend时实质性多了ing!

If you look at the git log again, you'll see that there's two new commits in place of the three that we had previously. But by now you're used to what rebase does to commits and have expected that.
如果您再次查看git log ,您会发现有两个新提交代替了我们之前的三个提交。但现在您已经习惯了rebase对提交所做的操作,并且已经预料到了这一点。

git log --oneline
105177b (HEAD -> interactiveRebase) Add Bob
ed78fa1 Add a lot very important text to Alice
df3ad1d (origin/master, origin/HEAD, master) Add Alice
800a947 Add Tutorial Text
Enter fullscreen mode Exit fullscreen mode

Public History, why you shouldn't rewrite it, and how to still do it safely
公共历史,为什么你不应该重写它,以及如何安全地重写它

As noted before, changing history is a incredibly useful part of any work-flow that involves making a lot of small commits while you work.
如前所述,更改历史记录对于任何涉及在工作时进行大量小提交的工作流程来说都是非常有用的部分。

While all the small atomic changes make it very easy for you to e.g. verify that with each change your test-suite still passes and if it doesn't, remove or amend just these specific changes, the 100 commits you've made to write HelloWorld.java are probably not something you want to share with people.
虽然所有小的原子更改使您可以很容易地验证每个更改您的测试套件是否仍然通过,如果没有通过,则仅删除或修改这些特定更改,您为编写HelloWorld.java所做的 100 次提交HelloWorld.java可能不是您想与人们共享的东西。

Most likely what you want to share with them, are a few well formed changes with nice commit messages telling your colleagues what you did for which reason.
您最想与他们分享的是一些格式良好的更改,其中包含良好的提交消息,告诉您的同事您出于何种原因做了什么。

As long as all those small commits only exist in your Dev Environment, you're perfectly save to do a git rebase -i and change history to your hearts content.
只要所有这些小提交仅存在于您的开发环境中,您就可以完美地保存执行git rebase -i并将历史记录更改为您想要的内容。

Things get problematic when it comes to changing Public History. That means anything that has already made it to the Remote Repository.
当涉及到改变公共历史时,事情就会出现问题。这意味着任何已经进入远程存储库的内容。

At this point is has become public and other people's branches might be based on that history. That really makes it something you generally don't want to mess with.
此时已公开,其他人的分支可能基于该历史。这确实使它成为您通常不想弄乱的东西。

The usual advice is to "Never rewrite public history!" and while I repeat that here, I've got to admit, that there is a decent amount of cases in which you might still want to rewrite public history.
通常的建议是“永远不要重写公共历史!”虽然我在这里重复这一点,但我必须承认,在很多情况下你可能仍然想重写公共历史

In all of theses cases that history isn't 'really' public though. You most certainly don't want to go rewriting history on the master branch of an open source project, or something like your company's release branch.
但在所有这些情况下,历史并不是“真正”公开的。您肯定不想在开源项目的分支或公司的发布分支之类的分支上重写历史记录。

Where you might want to rewrite history are branches that you've pushed just to share with some colleagues.
您可能想要重写历史记录的是您push的分支,只是为了与一些同事共享。

You might be doing trunk-based development, but want to share something that doesn't even compile yet, so you obviously don't want to put that on the main branch knowingly.
您可能正在进行基于主干的开发,但想要共享一些甚至还没有编译的东西,所以您显然不想故意将其放在主分支上。

Or you might have a work-flow in which you share feature branches.
或者您可能有一个共享功能分支的工作流程。

Especially with feature branches you hopefully rebase them onto the current master frequently. But as we know, a git rebase adds our branch's commits as new commits on top of the thing we're basing them on. This rewrites history. And in the case of a shared feature branch it rewrites public history.
特别是对于功能分支,您希望经常将它们rebase到当前的主分支上。但正如我们所知, git rebase将我们分支的提交作为提交添加到我们所基于的事物之上。这将改写历史。在共享功能分支的情况下,它重写了公共历史

So what should we do if we follow the "Never rewrite public history" mantra?
那么,如果我们遵循“永不改写公共历史”的口号,我们该怎么办呢?

Never rebase our branch and hope it still merges into master in the end?
永远不要对我们的分支进行 rebase 并希望它最终仍然合并到master中?

Not use shared feature branches?
不使用共享功能分支?

Admittedly that second one is actually a reasonable answer, but you might still not be able to do that. So the only thing you can do, is to accept rewriting the public history and push the changed history to the Remote Repository.
诚然,第二个答案实际上是一个合理的答案,但您可能仍然无法做到这一点。因此,您唯一能做的就是接受重写公共历史记录并将更改的历史记录push远程存储库

If you just do a git push you'll be notified that you're not allowed to do that, as your local branch has diverged from the remote one.
如果您只是执行git push您会收到通知,您不能执行此操作,因为您的本地分支已与远程分支分离。

You will need to force pushing the changes, and overwrite the remote with your local version.
您将需要force推送更改,并用本地版本覆盖远程版本。

As I've highlighted that so suggestively, you're probably ready to try git push --force right now. You really shouldn't do that if you want to rewrite public history safely though!
正如我暗示性地强调的那样,您现在可能已经准备好尝试git push --force 。如果你想安全地重写公共历史,你真的不应该这样做!

You're much better off using --force's more careful sibling --force-with-lease !
使用--force更仔细的兄弟--force-with-lease会更好!

--force-with-lease will check if your local version of the remote branch and the actual remote match, before pushing.
--force-with-lease将在push之前检查远程分支的本地版本和实际的远程版本是否匹配。

By that you can ensure that you don't accidentally wipe any changes someone else may have pushed while you where rewriting history!
这样您就可以确保在重写历史记录时不会意外擦除其他人可能push的任何更改!

What happens in a push --force-with-lease

And on that note I'll leave you with a slightly changed mantra:
关于这一点,我将给你留下一个稍微改变的口头禅:

Don't rewrite public history unless you're really sure about what you're doing. And if you do, be safe and force-with-lease.
除非您真的确定自己在做什么,否则不要重写公共历史。如果您这样做,请确保安全并强制租赁。

Reading history  读历史

Knowing about the differences between the areas in your Dev Environment - especially the Local Repository - and how commits and the history work, doing a rebase should not be scary to you.
了解开发环境中各个区域之间的差异(尤其是本地存储库)以及提交和历史记录的工作原理,执行rebase应该不会让您感到害怕。

Still sometimes things go wrong. You may have done a rebase and accidentally accepted the wrong version of file when resolving a conflict.
但有时还是会出现问题。您可能进行了rebase ,并在解决冲突时意外接受了错误版本的文件。

Now instead of the feature you've added, there's just your colleagues added line of logging in a file.
现在,您的同事只是在文件中添加了日志记录行,而不是您添加的功能。

Luckily git has your back, by having a built in safety feature called the Reference Logs AKA reflog.
幸运的是, git为您提供了支持,它有一个内置的安全功能,称为参考日志,又名reflog

Whenever any reference like the tip of a branch is updated in your Local Repository a Reference Log entry is added.
每当本地存储库中更新任何引用(例如分支尖端)时,都会添加引用日志条目。

So theres a record of any time you make a commit, but also of when you reset or otherwise move the HEAD etc.
因此,记录了您进行commit任何时间,还记录了您reset或以其他方式移动HEAD等的时间。

Having read this tutorial so far, you see how this might come in handy when we've messed up a rebase right?
到目前为止,读完本教程后,您会发现当我们搞砸了rebase时这会如何派上用场,对吗?

We know that a rebase moves the HEAD of our branch to the point we're basing it on and the applies our changes. An interactive rebase works similarly, but might do things to those commits like squashing or rewording them.
我们知道rebase会将我们分支的HEAD移动到我们所基于的点并应用我们的更改。交互式rebase工作原理类似,但可能会对这些提交进行一些操作,例如压缩重新措辞

If you're not still on the branch on which we practiced interactive rebase, switch to it again, as we're about to practice some more there.
如果您不在我们练习交互式 rebase的分支上,请再次切换到它,因为我们将在那里进行更多练习。

Lets have a look at the reflog of the things we've done on that branch by - you've guessed it - running git reflog.
让我们看看我们在该分支上所做的事情的reflog - 你已经猜到了 - 运行git reflog

You'll probably see a lot of output, but the first few lines on the top should be similar to this:
您可能会看到很多输出,但顶部的前几行应该与此类似:

git reflog
105177b (HEAD -> interactiveRebase) HEAD@{0}: rebase -i (finish): returning to refs/heads/interactiveRebase
105177b (HEAD -> interactiveRebase) HEAD@{1}: rebase -i (reword): Add Bob
ed78fa1 HEAD@{2}: rebase -i (squash): Add a lot very important text to Alice
9e06fca HEAD@{3}: rebase -i (start): checkout HEAD~3
0b22064 HEAD@{4}: commit: Add more text to Alice
062ef13 HEAD@{5}: commit: Add Bob.txt
9e06fca HEAD@{6}: commit: Add text to Alice
df3ad1d (origin/master, origin/HEAD, master) HEAD@{7}: checkout: moving from master to interactiveRebase
Enter fullscreen mode Exit fullscreen mode

There it is. Every single thing we've done, from switching to the branch to doing the rebase.
就在那里。我们所做的每一件事,从切换到分支到执行rebase

Quite cool to see the things we've done, but useless on it's own if we messed up somewhere, if it wasn't for the references at the start of each line.
看到我们所做的事情很酷,但如果我们在某个地方搞砸了,如果没有每行开头的参考,那么它本身就没用。

If you compare the reflog output to when we looked at the log the last time, you'll see those points relate to commit references, and we can use them just like that.
如果将reflog输出与我们上次查看log时进行比较,您将看到这些点与提交引用相关,我们可以像这样使用它们。

Let's say we actually didn't want to do the rebase. How do we get rid of the changes it made?
假设我们实际上不想进行变基。我们如何摆脱它所做的改变?

We move HEAD to the point before the rebase started with a git reset 0b22064.
我们使用git reset 0b22064HEAD移动到rebase开始之前的位置。

0b22064 is the commit before the rebase in my case. More generally you can also reference it as HEAD four changes ago via HEAD@{4}. Note that should you have switched branches in between or done any other thing that creates a log entry, you might have a higher number there.
在我的例子中, 0b22064rebase之前的提交。更一般地说,您还可以通过HEAD@{4}将其引用为四次更改前的 HEAD 。请注意,如果您在两者之间切换了分支或执行了任何其他创建日志条目的操作,则那里的数字可能会更高。

If you take a look at the log now, you'll see the original state with three individual commits restored.
如果您现在查看log ,您将看到恢复了三个单独提交的原始状态。

But let's say we now realize that's not what we wanted. The rebase is fine, we just don't like how we changed the message of the Bob commit.
但假设我们现在意识到这不是我们想要的。 rebase很好,我们只是不喜欢我们如何更改 Bob 提交的消息。

We could just do another rebase -i in the current state, just like we did originally.
我们可以在当前状态下再执行一次rebase -i操作,就像我们最初所做的那样。

Or we use the reflog and jump back to after the rebase and amend the commit from there.
或者我们使用引用日志并跳回到变基之后并从那里amend提交。

But by now you know how to do either of that, so I'll let you try that on your own. And in addition you also know that there's the reflog allowing you to undo most things you might end up doing by mistake.
但现在您已经知道如何做到其中任何一个,所以我会让您自己尝试一下。此外,您还知道, reflog允许您撤消大多数可能最终错误执行的操作。

👋 Before you go 👋 出发前

Do your career a big favor. Join DEV. (The website you're on right now)
为你的职业生涯带来一个大帮助。加入开发。 (您现在访问的网站)

It takes one minute, it's free, and is worth it for your career.
只需一分钟,它是免费的,并且对您的职业生涯来说是值得的。

Okay let's go 好的,我们走吧

Community matters 社区事务

Top comments (102)

Collapse
 
ben profile image
Ben Halpern

Learn x concepts, not x commands. Probably a reusable statement across many technologies.

Collapse
 
bugtester46 profile image
bugtester46

TEST

Collapse
 
hermeshcg profile image
Hermes Caretta

teste

Thread Thread
 
ben profile image
Ben Halpern

Toast

Collapse
 
jrop profile image
Jonathan Apodaca

This reminds me of the site "learn X in Y minutes". I visit that site every few days haha
这让我想起了“在Y分钟内学习X”这个网站。我每隔几天访问该网站哈哈

Collapse
 
thikthik profile image
Karthik Ramaraju

Learn x concepts, not only x commands.
学习 x 概念,而不仅仅是 x 命令。

Probably a Best reusable statement across many technologies.
可能是许多技术中最好的可重用声明。

Collapse
 
michaelscheffenacker profile image
Michael Scheffenacker

How about just: 怎么样:
Learn concepts, not commands.
学习概念,而不是命令。

Thread Thread  线
 
thikthik profile image
Karthik Ramaraju • Edited

Still we need to learn commands but not only commands. So Learn Concepts , not only Commands :)
我们仍然需要学习命令,但不仅仅是命令。所以学习概念,而不仅仅是命令:)

Collapse
 
bugtester46 profile image
bugtester46

test 测试

Collapse
 
aranouski profile image
Artsiom B

For many years trying to combine learning and writing code I decided that copies from stackoverflow is the best part of my job :D
多年来,我一直在尝试将学习和编写代码结合起来,我认为来自 stackoverflow 的副本是我工作中最好的部分:D

Collapse
 
pshchelo profile image
Pavlo Shchelokovskyy

Nice post, thanks. 好帖子,谢谢。

For another perspective I could also suggest the "Git from the Bottom Up" jwiegley.github.io/git-from-the-bo...
从另一个角度来看,我还可以建议“Git from the Bottom Up” jwiegley.github.io/git-from-the-bo...

which starts from how the repo is built inside (blobs and trees). Opened my eyes at some point - and also allowed me to explain Git to others better :-)
这从回购协议的内部构建方式(blob 和 trees)开始。在某个时刻让我睁开了眼睛 - 也让我能够更好地向其他人解释 Git :-)

Collapse
 
unseenwizzard profile image
Nico Riedmann

Thanks, did not know that one yet! Added to my reading list
谢谢,还不知道这个!添加到我的阅读列表

Collapse
 
placideirandora profile image
Placide IRANDORA

One of the best articles about Git. You've really put a lot of effort in producing this awesome article. Thank you so much for your contribution to the developer community. Actually, This is the best and intensive article that I have ever encountered on the internet. Nice job!
关于 Git 的最佳文章之一。为了写出这篇精彩的文章,您确实付出了很多努力。非常感谢您对开发者社区的贡献。事实上,这是我在互联网上遇到的最好、最深入的文章。干得好!

Collapse
 
parkerholladay profile image
Parker Holladay

Great write up on crucial concepts to understanding how/why to use various git commands. There is one semantic distinction that I find helpful when talking about rebase to those unfamiliar with it. Rather than saying:

We re-base our add_patrick branch on the current state of the master branch.

It might be clearer what is happening if you say:

We re-base our add_patrick branch from the current state of the master branch.

That is to say, we get a new base set of commits for our branch from another branch. So, as you describe, when we run the command git rebase master [add_patrick], we are taking all commits from master that add_patrick does not yet have, and rewinding to apply them to HEAD before replaying our commits in add_patrick.

Collapse
 
unseenwizzard profile image
Nico Riedmann

For me personally understanding the on or onto wording for rebase as it's also used in the git reference actually helped me when I learned about it originally.

I take my changes, which where originally based on some branch HEAD, and I put them onto some other branch's current state (or state of the same branch)

Collapse
 
parkerholladay profile image
Parker Holladay

Like I said, it is semantics, but I've found that slight change in wording useful for some when helping them understand rebase.

Thread Thread
 
wobuyaotweet profile image
Not Real • Edited

Agreed - I completely misunderstood this at first because “rewind and rebase onto” sounds like “take my work from ‘add_patrick’, add all those commits “onto” ‘master’ (which doesn’t happen & wouldn’t really make sense) before moving the divergence point & continuing on the current branch.

The key point to understand is that you get all new commits from ‘master’ so your current branch is up to date with it (kinda like a git pull), then reapply the commits from ‘add_patrick’ again from that new point of divergence from master, but still on ‘add_patrick’ itself.

That confusion on my part aside, I found this to be a fantastic overview! Thanks!

Collapse
 
naurel1467 profile image
Naurel1467

Now i get it...thanx

Collapse
 
angelarae63 profile image
Angela Whisnant

Hey! I am so new to GitHub...where am I supposed to be typing these commands...at the command prompt, possibly? I am trying to follow this tutorial. I ran into a 'GitHub Desktop.' Now I'm confused as to whether I use this or do it some other way.
Sorry!
Angie

Collapse
 
unseenwizzard profile image
Nico Riedmann

Hi

Yes, those go in the command line!

There a few graphical git clients that I hear are nice. The github desktop one, tower git and a lot of my colleagues use what comes with their IDE (we use intellij idea for java)

But for understanding what is going on I think you'll learn more using git from the commandline.

The tools abstract a lot of things away trying to make things easier to use

Collapse
 
angelarae63 profile image
Angela Whisnant

I think I prefer the command line anyway. Thanks so much!

Collapse
 
andrewmcodes profile image
Andrew Mason

This is crazy good. Super informative and the visual aids definitely help. Thanks for sharing! 👏🏼

Collapse
 
prahladyeri profile image
Prahlad Yeri • Edited

One caveat you should mention is that "git push" doesn't always work on some git installations, especially POSIX ones like Linux. You may have to qualify with the remote repository for it to work:

git push origin master
Enter fullscreen mode Exit fullscreen mode

But otherwise, its super informative and well written article.

Collapse
 
unseenwizzard profile image
Nico Riedmann

With git 2.0 introducing the simple push strategy as default setting, I was under the impression that you generally wont need to qualify the remote you're pushing to, as long as it's set as upstream and has the same name as your local branch (which it is if you don't go out of your way to have it differently).

Or am I wrong about something there?

Collapse
 
prahladyeri profile image
Prahlad Yeri • Edited

Yep, it considers the current branch (origin/master) as the default if git config --global push.default setting is set to current. This is usually set by default on windows and ios, so simply doing "git push" might work but on some linux distros, this setting isn't set to current but set to nothing instead (which means you'll have to explicitly add the branch).

Especially, the last time when I'd worked on Ubuntu, simply doing a git push had not worked.

Thread Thread
 
unseenwizzard profile image
Nico Riedmann

As far as I understood it, the "new" (git 2.0 is from 2014) default is simple.

From the git doc:

When neither the command-line nor the configuration specify what to push, 
the default behavior is used, which corresponds to the simple value for push.default: 
the current branch is pushed to the corresponding upstream branch, but as a safety measure, 
the push is aborted if the upstream branch does not have the same name as the local one.
Enter fullscreen mode Exit fullscreen mode

Of course it may still be that some distro installations either install older versions, or install with a non-default configuration. Somewhat recently having set-up my work laptop on Ubuntu 18.04 I do not recall having to set the push configuration

Thread Thread
 
bugtester46 profile image
bugtester46

TEST

Collapse
 
jamesanderson13 profile image
JamesAnderson13

Very interesting information, I really like it because it can add insight for me more broadly, thank you very much for this extraordinary information

tutu app

Collapse
 
voidjuneau profile image
Juneau Lim

What an effort you have put on this post. It's almost felt bad to call it as a post. It seems like a book or wiki very least.
I was just getting there by doing it and you helped me greatly. I also really loved the useful tips. Thank you so much.

Collapse
 
biros profile image
Boris Jamot ✊ /

Wooh! Did your post really get more than 3000 reactions in only two weeks?
哇!你的帖子真的在短短两周内就获得了 3000 多个回复吗?

That's awesome, congratulations!
太棒了,恭喜!

Now I have to read it...
现在我必须读它......

Collapse
 
spearkkk profile image
spearkkk

Thanks for nice writing. It is awesome for understanding git to me.
谢谢你写得好。对我来说理解 git 真是太棒了。

And I want to share with my friend and colleague, Could I translate with my language and share it?
我想与我的朋友和同事分享,我可以用我的语言翻译并分享吗?

I will refer this origin post too.
我也会参考这篇原始文章。

Collapse
 
unseenwizzard profile image
Nico Riedmann

What a great idea, please do that!
多么好的主意,请这样做!

The more people it gets to help the better.
帮助的人越多越好。

What will you be translating it to?
你要把它翻译成什么?

I guess you'll want to fork the git project so you have the md source for your translation.
我想你会想要 fork git 项目,这样你就有了翻译的 md 源代码。

I'd be more than happy to link to your translation as well, or include it as branch of the repo when you're done!
我也非常乐意链接到您的翻译,或者在您完成后将其作为存储库的分支包含在内!

Collapse
 
reddyaravind178 profile image
aravind_reddy • Edited

One of the best tech articles I have ever read. Thanks for the effort

Collapse
 
irshadbluecast profile image
Irshad Bluecast • Edited

Awesome. A great in-depth tutorial.
惊人的。一个很棒的深入教程。

Just one note - instead of git checkout command you could use git switch command, which is easier to change branches in git and also aligns with the concept of switching and the command for it.
只需要注意一点 - 您可以使用git switch命令代替git checkout命令,它更容易更改 git 中的分支,并且也符合切换的概念及其命令。

To read my tutorial with more detailed examples on how to use git switch command, please visit -dev.to/irshadbluecast/how-to-switc...
要阅读我的教程以及有关如何使用git switch命令的更详细示例,请访问 - dev.to/irshadbluecast/how-to-switc...

Collapse
 
bberrycarmen profile image
Rachel M. Carmena

Congrats Nico!  恭喜尼科!

I've added a bonus at the end of the post which inspired you.
我在帖子末尾添加了一个奖励,这对您有所启发。

I'm really happy ;) 我真的很高兴;)

Collapse
 
unseenwizzard profile image
Nico Riedmann

Wow. Thanks! 哇。谢谢!

For the shout-out in your article, the inspiration and your great articles in general :)
对于你文章中的大喊大叫、灵感和你的伟大文章:)

Collapse
 
aoifecarrigan profile image
Aoife Shannon

This is the tutorial I needed back when I first started out with git as a junior dev, I struggled way too long just learning off commands rather than trying to understand the concepts, will be bookmarking for future thank you!
这是我第一次作为初级开发人员开始使用 git 时需要的教程,我在学习命令而不是试图理解概念方面挣扎了太长时间,将为将来添加书签,谢谢!

Collapse
 
lyphanna profile image
Phanna 🔥

Great article!  很棒的文章!

AWS Security LIVE! Stream

Practical guidance for security practitioners
安全从业者的实用指南

Don't miss AWS Security LIVE! Whether you're an AWS newbie or a seasoned pro, this show has something for everyone with actionable tips, expert advice, and security knowledge.
不要错过 AWS 安全直播!无论您是 AWS 新手还是经验丰富的专业人士,该节目都能为每个人提供可行的提示、专家建议和安全知识。

Learn More 了解更多