从git远程创建功能分支的最佳方法是什么? [英] what's the best way to create a feature branch from remote in git?

查看:63
本文介绍了从git远程创建功能分支的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

听起来像一个愚蠢的问题,对吧?

Sounds like a dumb question, right?

git checkout master
git pull
git checkout -b myBranchName

除了我总是忘记git pull步骤...当这是一个常见用例时,我想必有必须使它自动运行,对吧?跳过本地主人"的某种方法?

Except I always forget the git pull step... when this is such a common use-case I imagine there must be some chrome to make this automatic, right? Some way to skip the local "master"?

因为我今天又做了一次.我切换到 master ,创建了功能分支,完成了很多工作,然后我发现按下按钮时发现我的功能分支远远落后于 master 冲突方式.

Because I did it again today. I switched to master, created my feature branch, a bunch of work got done and then I found out when I pushed I discovered my feature branch was way behind master in a horribly conflict-y way.

我总是忘记 git pull 步骤.因此,我遇到了最糟糕的无声故障,即所有看上去都正常,直到后来发现被拧紧为止.

I always forget the git pull step. So I'm getting the worst kind of silent failure where everything looks fine until way later when you find out you're screwed.

有办法避免这种情况吗?一种说不信任我的本地 master 分支,而是返回到远程创建我的本地未跟踪分支的方法?还是我只是在交易哎呀,您忘记了 git pull "对于糟糕,您忘记了 git fetch "如果我这样做的话?

Is there a way to avoid this? A way to say "don't trust my local master branch, instead go back to the remote to create my local untracked branch? Or am I just trading a "oops you forgot to git pull" for "ooops you forgot to git fetch" if I do that?

推荐答案

根据工作流程的其余部分,您可能会受益于删除 master

Depending on the rest of your work-flow, you might benefit from simply deleting your master branch name entirely. Once you do that, you can't be on that branch, because you don't have that branch.

code>完全是分支名称.一旦这样做,就不能成为该分支的 ,因为您没有拥有该分支的.

That aside, if you created a new branch name from your local master but forgot to update your local master first, there are multiple cures. To understand them—and to understand when and why deleting your local master works—it helps to realize that in Git, branch names are almost irrelevant. They do one important thing for us (and for Git): they help us find commits. But it's not the branch names that matter! It is the commits that matter.

此外,如果您从本地 master 创建了新的分支名称,但又忘记先更新本地 master ,则有多种解决方法.要了解它们,并了解何时以及为什么 删除您本地的 master 的工作原理,这有助于在Git中认识到分支名称几乎无关紧要.它们对我们(以及对Git)做了一件重要的事情:它们帮助我们查找提交.但这与分支名称无关紧要!重要的是 commits .

It's this one fact—that the names let us find commits—that makes the names important. So the names become un-important whenever there is some other way to find those commits.

正是这一事实-名称让我们查找提交-使名称变得重要.因此,只要有其他其他方法来查找这些提交,名称就变得 un 很重要.

To make sense out of this, take note of git log output. Here's a sample of a fragment of git log --oneline output from a clone of the Git repository for Git:

要理解 this ,请注意 git log 输出.这是从Git的Git存储库克隆中输出的 git log --oneline 片段的示例:

$ git log --oneline 328c109303 (HEAD -> master, origin/master, origin/HEAD) The eighth batch 8b25dee615 Merge branch 'tb/precompose-prefix-too' 006c5f79be Merge branch 'jk/complete-branch-force-delete' 60f8121940 Merge branch 'jv/upload-pack-filter-spec-quotefix'

Note the funky numbers (hexadecimal numbers) on the left.  These are the actual commit IDs, shortened somewhat because the full number is very long.  (The Git repository for Git is fairly big at this point so the numbers are now shortened to 10 characters instead of 7; smaller repositories use shorter shortenings.)

请注意左侧的时髦数字(十六进制数字).这些是实际的提交ID,由于总数非常长,因此有所缩短.(目前,用于Git的Git存储库相当大,因此现在数字已缩短为10个字符,而不是7个字符;较小的存储库则使用较短的缩写.)

The numbers appear random, but aren't. They are in fact the result of running a cryptographic hash function over the contents of each commit. In this way, every Git in the universe will agree that the top commit in the list here gets the number 328c10930387d301560f7cbcd3351cc485a13381. No other commit, anywhere or any time, can use this number.1

数字似乎是随机的,但不是随机的.实际上,它们是对每个提交内容运行加密哈希函数的结果.这样,宇宙中的每个Git都会同意列表中的最高提交获得编号 328c10930387d301560f7cbcd3351cc485a13381 . 1

What a branch name, like master as seen in the output above, does is hold the hash ID of the last commit that's on that branch. But another name might also hold that hash ID. In this case, another name does hold it: the name origin/master holds the same hash ID. The special thing about origin/master is that it's not a branch name: git switch won't switch to it, for instance.

一个分支名称(如上面的输出中所示的 master )执行的操作是保留该分支上的 last 提交的哈希ID.但是另一个名称也可能包含该哈希ID.在这种情况下,会保留另一个名称​​ :名称 origin/master 拥有相同的哈希ID.关于 origin/master 的特殊之处在于,它不是分支名称:例如, git switch 不会切换到该名称.

无论如何,一旦您内化了重要的是数字的想法,并且名称之类的 master 就是方便的方法查找数字,我们准备继续进行下一部分.

Anyway, once you've internalized the idea that it's the numbers that matter, and that names like master are just convenient ways to find the numbers, we're ready to move on to the next section.

1 从技术上讲,其他一些Git存储库可以重新使用此编号,但前提是该其他Git存储库从未与以下版本的Git存储库的副本接触:吉特它们不会以星际迷航物"-反物质"-宇宙尽头"的方式爆炸,但是如果另一个Git存储库以某种方式将哈希ID重用于其他用途,那就不好了.另请参见新发现的SHA-1碰撞如何影响Git?

1Technically, some other Git repository could re-use this number, but only if that other Git repository never comes in contact with a clone of the Git repositories for Git. They won't explode in a Star-Trek-Matter-Antimatter-End-Of-The-Universe fashion, but if another Git repository somehow re-uses the hash ID for something else, it's, well, Not Good. See also How does the newly found SHA-1 collision affect Git?

这些是SHA-1数字.Git的人们正逐渐转向SHA-256.确切地说,我们如何到达那里仍然有一个悬而未决的问题.当前(Git 2.30),您可以创建一个SHA-256存储库并使用它,也可以创建一个SHA-1存储库并使用它.但您永远都无法将SHA-256口语的Git与SHA-1口语的Git进行对话.您甚至无法将旧数据库升级到新数据库,也无法将新数据库降级到旧数据库.那不是一个非常可以接受的情况.

These are SHA-1 numbers. The Git folks are gradually moving to SHA-256. Exactly how we'll get there is still a bit of an open question. Currently (Git 2.30), you can make a SHA-256 repository and use it, or a SHA-1 repository and use it; but you can't ever have a SHA-256-speaking Git talk to a SHA-1-speaking Git. You can't even upgrade an old database to a new one, nor downgrade a new one to an old one. That's not a very acceptable situation.

每个提交的编号:OK.Git实际上通过这些哈希ID号来查找提交及其其他内部对象.好的.但是:那又怎样呢?

Each commit is numbered: OK. Git actually finds the commits—and its other internal objects—by these hash-ID numbers. OK. But: so what?

嗯,关于提交还有更多的事情要知道.在这里不做深入介绍,我们只说它们由两部分组成:所有文件的快照 和一些元数据.快照是 git checkout 签出的内容.元数据是有关提交本身的内容,例如谁进行提交,何时进行以及为什么进行.我们在 git log 输出中看到此元数据:

Well, there's several more things to know about commits. Without going deep into them, let's just say here that they're made up of two parts: a snapshot of all files, and some metadata. The snapshot is what git checkout checks out. The metadata is stuff about the commit itself, such as who made it, when, and why. We see this metadata in git log output:

$ git log
commit 328c10930387d301560f7cbcd3351cc485a13381
Author: Junio C Hamano <gitster pobox.com>
Date:   Fri Feb 12 14:13:40 2021 -0800

    The eighth batch
    
    Signed-off-by: Junio C Hamano <gitster pobox.com>
...

在这里,我们有提交的作者,日期和时间(上星期五,我整周都没有更新!)和Junio的日志消息(这很简洁,因为真正的信息在所有合并中).您在这里看不到看到的是,提交的元数据仅为Git存储了一些内容,Git将该提交称为 parent . 328c10930387d301560f7cbcd3351cc485a13381 的父代是 8b25dee6155dad4942 a>,Git在其中修复了一个与Unicode文件名有关的Mac特定错误. 2 (此 328c109303 父提交本身就是一个 merge commit ,因为它不仅有一个父提交,而且有两个父提交,但在大多数Git存储库中,大多数提交都不是合并的.)

Here we have the commit's author, the date-and-time (last Friday—I haven't updated all week!), and Junio's log message (which is rather terse since the real information is in all the merges). What you don't see here is that the commit's metadata also stores something just for Git, which Git calls the parent of this commit. The parent of 328c10930387d301560f7cbcd3351cc485a13381 is 8b25dee6155fd3816f62649da196a4f42cf5584e, where Git picked up a fix for a Mac-specific bug having to do with Unicode file names.2 (This parent-of-328c109303 commit is itself a merge commit, because it has not just one but two parent commits, but in most Git repositories, most commits are not merges. Below, I'm not drawing any merge commits.)

存储上一个提交的哈希ID的技巧是,在Git中,一个提交指向后".到上一个提交,然后再次指向后一个步骤.这将一遍又一遍地重复,将提交放入一个长的向后看的链中.如果绘制一条这样的链,用大写字母等符号替换实际的提交哈希ID(以便在人类脆弱的大脑中保持理智),我们将得到如下图所示:

This trick of storing the previous commit's hash ID means that in Git, a commit "points backwards" to the previous commit, which then points backwards again, one more step. This repeats over and over again, stringing the commits into one long backwards-looking chain. If we draw such a chain, replacing the real commit hash IDs with symbols such as uppercase letters (so as to retain sanity in our feeble human brains), we get a picture that looks like this:

... <-F <-G <-H

其中 H 是该链中的 last 提交.提交 H 指向早期的提交 G ,指向 F ,依此类推.一直重复直到我们到达有史以来的第一个提交(大概是 A ):那个提交不会向后指向,因为它不能.因此,如果我们不尽早将它关闭,那就是 git log 的地方.

where H is the last commit in this chain. Commit H points back to earlier commit G, which points back to F, and so on. This repeats until we reach the very first commit ever (presumably A): that one doesn't point backwards because it can't. So that's where git log stops, if we don't cut it off sooner.

Git一如既往地通过哈希ID查找每个提交.但是Git在哪里可以找到链中 last 提交的哈希ID,提交 H ?我们可以将其写下来,或者写在白板上.但这太愚蠢了:我们有一台计算机.如果我们将其保存在文件中怎么办?更好的是,如果我们将 Git 自动地 保存在某个文件或数据库中,该怎么办?

Git, as always, finds each of these commits by their hash IDs. But where will Git find the hash ID of the last commit in the chain, commit H? We could write it down on paper, or on a whiteboard, perhaps. But that would be silly: we have a computer. What if we save it in a file? Better yet, what if we have Git save it, automatically, in some file or database somewhere?

这就是分支名称.分支名称(例如 master )仅保存一个哈希ID.该哈希ID自动是链中的 last 提交.所以,如果我们有这个:

That's what a branch name is. A branch name, such as master, just holds one hash ID. This hash ID is automatically the last commit in the chain. So if we have this:

...--F--G--H   <-- master

那么我们的意思是名称 master 持有提交 H 的哈希ID,这是该链中的最后一个.即使在之后 H 之后也是如此,就像这样:

then what we mean is that the name master is holding the hash ID of commit H, which is the last in that chain. That's true even if there are commits after H, like this:

...--F--G--H   <-- master
            \
             I--J   <-- feature

在这里,名称 功能保存提交 J 的哈希ID,因此 feature 指向<代码> J . J 依次向后指向 I ,向后指向 H ,向后指向 G ,依此类推上.

Here, the name feature holds the hash ID of commit J, so that feature points to J. J in turn points backwards to I, which points backwards to H, which points backwards to G, and so on.

提交 H 同时是链中的末尾,终止于 master = H 位于链中间的某个位置,以 feature = J 结尾.通过 H 提交的消息在两个分支上.提交 I J 仅在功能上.

Commit H is simultaneously the last in the chain that ends at master = H and somewhere in the middle of the chain that ends at feature = J. Commits up through H are on both branches. Commits I and J are only on feature.

Git中的 branch 一词含糊不清:它表示分支名称由我目前关心的一组提交组成的 .导致 H 的提交链是分支",并且是分支主控",但是分支 name master 确实是只需掏出提交 H ,Git就可以从中向后工作.导致 J 的提交链也是一个分支",而分支 name feature 会选择提交 J .

The word branch in Git is ambiguous: it means both a branch name, and a set of commits ended by one I care about at the moment. The chain of commits leading up to H is "a branch", and is "branch master", but the branch name master really just picks out commit H, from which Git can work backwards. The chain of commits leading up to J is also "a branch", while branch name feature picks out commit J.

不过,分支名称(例如 master feature )的特殊功能是它们 move .让我们看看它是如何工作的.

The special feature of branch names like master and feature, though, is that they move. Let's see how this works.

2 这涉及macOS提取两个不同文件的方式,例如,命名为schönschön的文件,然后将它们折叠为一个文件,因为不可能查看这两个文件名之间的差异,或者实际上无法将其发布在此处.一个是使用Unicode代码点U + 0308的S C H O COMBINING-DIAERESIS N,另一个是使用Unicode代码点U + 00F6的S C H LATIN-SMALL-LETTER-O-WITH-DIAERESISN.在Linux机器上,您可以使用这两个不同的字节序列制作两个不同的文件.将提交提交到Mac盒后,尝试提取此提交将失败,因为本地文件系统将仅创建一个文件.命令行参数必须转换为正确的形式.当前的Git版本将其略有错误.

2This involves the way macOS takes two different files, e.g., named schön vs schön, and collapses them into one single file, because it's impossible to see the difference between the two file names, or in fact to post it here. One is S C H O COMBINING-DIAERESIS N using Unicode code-point U+0308, and the other is S C H LATIN-SMALL-LETTER-O-WITH-DIAERESIS N using Unicode code point U+00F6. On a Linux box, you can make two different files using these two different byte sequences. Upon transferring this commit to a Mac box, an attempt to extract this commit will fail because the local file system will just create one file. Command line arguments must be turned into the correct form; the current Git releases get this slightly wrong.

让我们从头开始,尽管这次没有明显的原因,我将在顶部而不是下方绘制 feature .只要您记得这些提交指向向后,则如何绘制这些都无关紧要.Git绘制这些内容,以便新的提交位于顶部,而连接位于页面下方.人们有时会向底部绘制新的承诺.从提交到提交的内部箭头始终向后退: Git前进很难,而后退则很容易,因此Git通常向后工作.例如,这就是为什么 git log 向后退的原因.我们不仅要首先看到最新的提交,Git也要.

Let's start with this again, though for no obvious reason I'll draw feature on top instead of below, this time. It doesn't matter how you draw these, as long as you remember that commits point backwards. Git draws these so that newer commits are on top and connections go down the page. People sometimes draw newer commits towards the bottom. The internal arrows, from commit to commit, always go backwards: Git has a hard time going forwards, and an easy time going backwards, so Git generally works backwards. That's why git log goes backwards, for instance. Not only do we want to see the newest commit first, so does Git.

             I--J   <-- feature
            /
...--F--G--H   <-- master

我们将选择一个分支并使用 git checkout 签出",或者,如果我们的Git是2.23或更高版本,则使用 git switch .这两个命令在这里做同样的事情.假设我们运行 git switch master (或 git checkout master ).这将使 master 成为我们的当前分支名称,并从提交 H .让我们通过将特殊名称 HEAD 附加到名称 master :

We will pick out one branch and "check it out", with git checkout, or, if our Git is 2.23 or later, git switch. Both commands do the same thing here. Let's say we run git switch master (or git checkout master). This will make master our current branch name, and get out, into our work area, all the files from commit H. Let's draw this by attaching the special name HEAD to the name master:

             I--J   <-- feature
            /
...--F--G--H   <-- master (HEAD)

现在让我们使用 git checkout -b feature2 git switch -c feature2 甚至 git branch feature2;git checkout feature2 或其他功能.它们都做同样的事情:使新的分支名称 feature2 指向提交 H ,然后在其中附加 HEAD ,如下所示:

Now let's make a new branch name, feature2, with git checkout -b feature2 or git switch -c feature2 or even git branch feature2; git checkout feature2 or whatever. They all do the same thing: make the new branch name feature2 point to commit H, and attach HEAD there, like this:

             I--J   <-- feature
            /
...--F--G--H   <-- feature2 (HEAD), master

现在,让我们以通常的方式进行新的提交.它获得了一个全新的哈希ID,但我们简称为 K . K 的父代将是 H ,因为我们使用 H 进行 make K .所以结果看起来像这样:

Now let's make a new commit, in the usual way. It gets an all-new hash ID, but we'll just call it K for short. K's parent will be H, because we used H to make K. So the result looks like this:

             I--J   <-- feature
            /
...--F--G--H   <-- master
            \
             K   <-- feature2 (HEAD)

请注意Git如何移动 名称 feature2 .它是在提交 K 之后,通过将 K 的哈希ID写入 name feature2 来实现的.sup> 3

Note how Git has moved the name feature2. It does this by writing K's hash ID into the name feature2, just after making commit K.3

如果我们再次提交新的 L ,我们将得到:

If we make another new commit L we get:

             I--J   <-- feature
            /
...--F--G--H   <-- master
            \
             K--L   <-- feature2 (HEAD)

请注意,我们的 HEAD 所附加的名称 feature2 是如何每次更新的.其他名称不变,现有的提交也没有更改-由于使用哈希ID方式对它们进行编号,因此任何方式都无法更改-但随着我们逐一添加新的提交,当前分支名称会移动.

Note how the name feature2, to which our HEAD is attached, gets updated each time. The other names don't change, and no existing commit changes—none can, in any way, due to the hash ID scheme for numbering them—but as we add new commits, one by one, the current branch name moves.

如果我们进行了错误的提交并希望删除它,则可以使用 git reset .这个命令很复杂,但是在我们用来消除错误提交的模式下,它的绘制很容易.它有点将提交搁置一旁(无需更改),并使我们的当前名称指向其他提交,例如:

If we make a bad commit and want to get rid of it, we can use git reset. This command is quite complicated, but in the mode we'd use to get rid of the bad commit, what it does is easy to draw. It sort of shoves the commit aside (without changing it) and makes our current name point to some other commit, like this:

             I--J   <-- feature
            /
...--F--G--H   <-- master
            \
             K   <-- feature2 (HEAD)
              \
               L   ???

提交 L 仍然存在在Git数据库中.但是现在,没有找到它的名称. 4 提交似乎已消失.但是,如果您将其哈希ID保存在某处,则可以使用另一个 git reset 将其取回:

Commit L still exists in the Git database. But now, there is no name by which to find it.4 The commit appears to be gone. If you saved its hash ID somewhere, though, you could use another git reset to get it back:

             I--J   <-- feature
            /
...--F--G--H   <-- master
            \
             K
              \
               L   <-- feature2 (HEAD)

reset 命令可以将当前名称 任意位置(移动到任何现有提交),因此功能非常强大.

The reset command can move the current name anywhere (to any existing commit) so it is quite powerful.

(一旦我们将 L 放回链中的 last 提交,就没有理由再单独将提交绘制在一行上了.我保留了多余的排它以清楚地表明我们只是在移动名称.)

(Once we put L back as the last commit in the chain, there's no reason to draw the commit on a row by itself any more. I kept the extra row it to make it clear that we're just moving the name around.)

3 K 的哈希ID包含所有元数据,包括Git使 K 的确切时间,父提交的哈希ID H ,您的日志消息等.这意味着没有人(不是您,不是Git,什么都没有)知道哈希ID 将是什么,直到实际提交为止.

3The hash ID for K incorporates all the metadata, including the exact time Git makes K, the hash ID of parent commit H, your log message, and so on. This means nobody—not you, not Git, nothing—knows what the hash ID will be until the commit is actually made.

4 为确保您确定可以再次找到它,Git保留了多个 hidden 名称.这些通常会在30天或更长时间后最终过期;一旦它们过期,并且提交确实无法找到, git gc 就会垃圾回收".它,把它扔掉是真的.

4To make sure you can find it again if you decide you want it back, Git keeps multiple hidden names. These eventually expire, typically after 30 days or more; once they expire, and the commit is truly un-find-able, git gc will "garbage collect" it, throwing it away for real.

现在让我们回到您原来的问题:

Let's go back to your original problem now:

git checkout master
git pull
git checkout -b myBranchName

除了我总是忘记 git pull 步骤...

Except I always forget the git pull step...

我在这里走得很快: git pull 表示运行 git fetch ,然后运行第二个Git命令对我提交的任何内容进行处理通常, second 东西将那些新提交并添加到 master 上.因此,最终结果是,如果您执行了打算要做的事情,则应从以下内容开始:

I'm going to go very fast here: git pull means run git fetch, then run a second Git command to do something with any commits I just fetched. The usual second thing takes those new commits and adds them on to master. So the end result is that if you do what you had intended to do, you would start with:

...--G--H   <-- master (HEAD), origin/master

git pull 将运行 git fetch ,这将添加一个或两个(或多个)新提交并更新非分支名称 origin/master,找到 last 之一:

The git pull would run git fetch, which adds a new commit or two (or many) and updates the non-branch name, origin/master, to find the last one:

...--G--H   <-- master (HEAD)
         \
          I--J   <-- origin/master

second 命令结束时向前移动 name master ,就像 git reset 一样(但更多)安全:使用 git reset 告诉Git 清除未保存的工作,而您配置的第二条命令都会仔细保存未保存的工作,或者停止它以破坏未保存的工作).5 结果是:

The second command winds up moving the name master forward, almost like git reset (but much more safely: using git reset tells Git wipe out unsaved work while whatever second command you've configured carefully preserves unsaved work, or halts if it would destroy it).5 The result is:

...--G--H--I--J   <-- master (HEAD), origin/master

现在,当您创建新名称 myBranchName feature2 或其他名称时, 6 这个新名称指向提交 J :

Now when you create a new name myBranchName or feature2 or whatever,6 this new name points to commit J:

...--G--H--I--J   <-- master, myBranchName (HEAD), origin/master

如果您忘记了 pull 步骤,则新创建的分支名称将改为提交 H (您甚至没有拥有>提交 IJ 为止):

If you've forgotten the pull step, the newly created branch name points to commit H instead (and you don't even have commits I-J yet):

...--G--H   <-- master, myBranchName (HEAD), origin/master

稍后,您将运行 git fetch (可能是 git pull 的一部分)并选择新提交.到那时,您可能已经进行了自己的新提交 K :

Later, you'll run git fetch—perhaps as part of a git pull—and pick up the new commits. By then, you might have made your own new commit K:

          I--J   <-- origin/master
         /
...--G--H   <-- master
         \
          K   <-- myBranchName (HEAD)

如果您现在 git checkout master 并让Git向前滑动分支名称",(就像 git pull 一样),您拥有:

If you now git checkout master and get Git to "slide the branch name forward" (as git pull will do), you have:

          I--J   <-- master (HEAD), origin/master
         /
...--G--H
         \
          K   <-- myBranchName

您现有的提交 K 指向 old 提交 H .这本身不是错误.让您的提交和您的分支都来自较早的提交没有什么错误.您可以继续工作,然后最终使用 git merge 组合工作.假设您切换回分支并进行一次新提交 L :

Your existing commit K points back to old commit H. This is not an error in and of itself. There's nothing wrong with having your commit(s), and your branch(es), descend from older commits. You can just keep working, then eventually use git merge to combine work. Let's say you switch back to your branch and make one new commit L:

          I--J   <-- master, origin/master
         /
...--G--H
         \
          K--L   <-- myBranchName (HEAD)

您现在可以切换回 master git merge 的工作,以在 KL 中合并您的更改(如从提交> H )及其在 IJ 中的更改(从提交 H 中可以看到),并获得新的 merge提交 M:

You can now switch back to master and git merge your work, to combine your changes in K-L (as seen from commit H) with their changes in I-J (as seen from commit H) and get a new merge commit M:

          I--J   <-- origin/master
         /    \
...--G--H      M   <-- master (HEAD)
         \    /
          K--L   <-- myBranchName

如果您查看各种Git存储库,包括用于Git的Git存储库,则有时会看到这种工作流程.没有错.但是有些人出于某种原因不喜欢.如果您是其中之一,或者与他们一起工作,则只需将两个提交( K L )并复制新的和改进的提交.

If you look at various Git repositories, including the Git repository for Git, you'll see this kind of work-flow sometimes. There's nothing wrong with it. But some people dislike it, for whatever reason. If you are one of those people, or work with them, you can simply take your two commits—K and L—and copy them to new and improved commits.

无需深入探讨所有机制, git rebase 将为您完成此操作.您甚至不必更新您的 master .假设您处于这个位置:

Without going into all the mechanism, git rebase will do this for you. You don't even have to update your master. Let's say you're in this position:

          I--J   <-- origin/master
         /
...--G--H   <-- master
         \
          K--L   <-- myBranchName (HEAD)

您现在可以运行:

git checkout myBranchName
git rebase origin/master

Git会将提交 K 复制到一个新的和改进的(?)提交中,我们将其称为 K'来暗示复制操作,此操作随后发生 J .然后,Git将提交 L 复制到在 K'之后的新改进的(?)提交 L'中.制作完这两个副本后,Git将从旧链的旧端剥离名称 myBranchName ,并将其粘贴到新链的新端,如下所示:

Git will copy commit K to a new-and-improved(?) commit, which we'll call K' to imply the copying action, that comes after J. Then Git will copy commit L to a new-and-improved(?) commit L' that comes after K'. Having made these two copies, Git will peel the name myBranchName off the old end of the old chain, and paste it onto the new end of the new chain, like this:

               K'-L'  <-- myBranchName (HEAD)
              /
          I--J   <-- origin/master
         /
...--G--H   <-- master
         \
          K--L   ???

提交 K L 似乎消失了,但是提交 K' L'看起来很多像原始提交 K L 一样-除了丑陋的哈希数字很大,但您还记得上面的任何数字吗?我不会-好像Git会​​神奇地以某种方式更改提交.

Commits K and L seem to have vanished, but commits K' and L' look so much like original commits K and L—except for the big ugly hash numbers, but do you remember any of the ones from above? I don't—that it will seem as though Git magically changed the commits in place somehow.

您现在也可以完全完全删除名称 master ,因为 origin/master 是您所关心的名称:它找到了正确的名称在每次 git fetch 之后提交.如果我们这样做,并丢弃无法找到的提交并理顺所有可能的问题,我们将得到:

You can simply delete the name master entirely now too, because origin/master is the one you care about: it finds the right commit after each git fetch. If we do that, and drop the un-find-able commits and straighten out all the kinks we can, we get:

...--G--H--I--J   <-- origin/master
               \
                K'-L'   <-- myBranchName (HEAD)

,看起来好像您以前没有忘记 git pull .

which looks as though you didn't forget the git pull earlier.

请注意,如果您尚未进行任何提交,即,如果您已:

Note that if you haven't made any commits at all yet, i.e., if you have:

...--G--H   <-- master, myBranchName (HEAD), origin/master

当您记得运行忘记的 git fetch 时,现在可以完全删除 master (可选)并运行 git fetch (强制)以获取:

when you remember to run the git fetch you forgot about, you can now delete master entirely (optional) and run git fetch (mandatory) to get:

...--G--H   <-- myBranchName (HEAD)
         \
          I--J   <-- origin/master

如果您现在运行 git rebase origin/master ,则您的Git会静默复制 no 提交,然后移动名称 myBranchName :

If you now run git rebase origin/master, your Git will quietly copy no commits and then move the name myBranchName:

...--G--H--I--J   <-- myBranchName (HEAD), origin/master

因此 git rebase 在这两种情况下均适用.那很方便.

so git rebase works for both these situations. That's pretty convenient.

5 在真正古老的Git版本中,大约1.5左右, git pull 有时会意外地破坏未保存的工作.我不止一次被这种方式烧死了!我避免 git pull ,部分是因为这个原因,尽管这也是因为我喜欢在 git pull 将运行.

5In truly ancient Git versions, somewhere around 1.5 or so, git pull would sometimes accidentally destroy unsaved work. I got burned this way more than once! I avoid git pull, in part because of this, though also because I like to insert commands between the two that git pull will run.

6 如果您使用Windows或macOS,建议您避免使用MixedCaseNames. Git 认为分支名称中的大小写很重要.您的操作系统认为文件名 的大小写无关紧要.Git有时将分支名称存储在文件中,有时将它们存储为文件名,这意味着这种情况有时很重要,有时并不重要.经历令人困惑和痛苦.避免混淆大小写,避免痛苦.

6If you use Windows or macOS, I recommend avoiding mixedCaseNames. Git thinks that case in branch names matters. Your OS thinks that case in file names doesn't matter. Git sometimes stores branch names in files, and sometimes stores them as file names, and this means that the case sometimes matters and sometimes doesn't. The experience is confusing and miserable. Avoid mixing case, and you avoid the misery.

这篇关于从git远程创建功能分支的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆