Author: @ Ryan – Miao this article as the original, reproduced please indicate the source: www.cnblogs.com/woshimrf/p/…


directory

1.1. Create a warehouse



1.2. Simulate user A



1.3. Simulate user B



1.4. Simulate user A



1.5. Simulate user C



1.6. Simulate user B



1.7. Simulate user C



2.1 Simulating User C



2.2 Simulating User D



2.3C Continue development



2.4D development continues



2.5 C submit



PR 2.6 C



2.7C modification and push



2.8C finds that there are too many times of submission and the history is too chaotic, and merges part of the history



2.9 C Push again



2.10 New merge mode: Rebase


2.11 At this point D is also completed


2.12 Rebase before Submission



The final result


preface

I’ve been using Git for version control and it worked fine until I got into a conflict with someone else. Git workflows are not that simple. For example, the cleanup history encountered earlier. Baidu to a lot of information, a lot of repeatability, but very little practical operation, I can not directly understand the meaning of its expression. Direct reading from the text often get the wrong conclusion, can only use time to test the truth, otherwise see the results are vaguely understood, or the final mess.

Learn git workflow

1. The simplest use is not recommended

1.1. Create a warehouse

$PWD/home/Ryan/workspace/l4git - workflow $touch readme. Md $ls readme. Md $touch. Gitignore $git init initialization empty git in warehouse /home/ryan/workspace/l4git-workflow/.git/ $ touch test.txt $ git add . $ gitcommit -m "init"
[master(root submission) dae77d6] init3 files changed.12 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 readme.md
 create mode 100644 test.txt
$ git remote add origin [email protected]:Ryan-Miao/l4git-workflow.git
$ git push -u origin masterObject count:5Completed. Delta Compressionusing up to 4Threads. Compression object:100% (3/3Write to the object:100% (5/5), 388 bytes | 0 bytes/s, complete. Total5 (delta 0), reused 0 (delta 0)
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> masterbranchmasterSet to trace remote branches from Originmaster.Copy the code

1.2. Simulate user A

git clone [email protected]:Ryan-Miao/l4git-workflow.git
git checkout a
touch a.txt
//write one
//....
$ git add .
$ git commit -m "one"
[a 53ff45e] one
 2 files changed.34 insertions(+), 2 deletions(-)
 create mode 100644 a.txtCopy the code

At this time, A has not submitted to Origin. Git log:

1.3. Simulate user B

git clone git@github.com:Ryan-Miao/l4git-workflow.git
git checkout bCopy the code
$ touch b.txtCopy the code

//write something //…

$ git add .
$ git commit -m "b write one"
[b 847078e] b write one
 1 file changed.1 insertion(+)
 create mode 100644 b.txtCopy the code

//write something

//….

$ git add . $ git commit -m "b write two" [b 3f30f41] b write two 1 file changed, 2 insertions(+), 1 deletion(-)

At this point, the Git log is as follows

1.4. Simulate user A

A and B are developed locally, so the order is unknown. Maybe A commits once before B, and maybe B commits once before B. The sequence here refers to the commit timestamp. But it’s all locally submitted code. write something

git add .
git commit -m "a write two"Copy the code

wirte something

git add .
git commit -m "write three"Copy the code

A push to server branch a

$ git push origin a:a
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:Ryan-Miao/l4git-workflow.git
 * [new branch]      a -> aCopy the code

A created a Pull Request



1.5. Simulate user C

C review the PR and then merged it.



At this point, github’s history is as follows:



Merge with commit. Message defaults to commitMerge pull request #1 from Ryan-Miao/a...

Now it seems that only A has a clear historical record. A has submitted three times.

1.6. Simulate user B

Before submitting, user B pulls the master and updates the latest code to the local computer to prevent conflicts.

 git fetch
 git merge origin/masterCopy the code

Now the log looks a little messy. As follows:



The confusion is that the original history of B only has its own submission, after updating the master to the local, the history is inserted into the master history. As a result, you find that your clean history has been interspersed with multiple commits. Even twice merge Master’s log appears long and eyesore. But B is going to submit it anyway.

So, B commits to the remote branch B:

1.7. Simulate user C

At this time, A completed feature A, then raised PR, and then merged with others C. Then, B also completed feature B and proposed PR, which required review and merge. A. review B. approve C. review D. merge

At this point, the project is basically on track. Add features one by one and repeat the previous workflow: fetch – “work -” commit – “push -” PR – “merged. Then, the history of the project looks like this:

At first glance it probably looks fine. You can see the commit history every time, but you can almost understand the most recent commit as long as it’s not written very little by Message. On closer inspection, however, the order seems wrong. At present, there are two features in total, but there are far more than two in history. It doesn’t matter, making it easier to show progress with fine granularity. However, these histories were not released in the order of features, so it was difficult to connect them together when I wanted to find feature A. If there are enough commits and the time span is large enough, it is not even clear what changes feature A has made.

Use the graphical Git history tool to help you understand the history:

Here, fortunately, we can barely see where we’re going. But when ten or hundreds of people are developing at the same time, the line is simply unreadable, and the time span is long enough for the line to be unreadable.

This model, therefore, is our own current model. Bad review. This was not the end, and there came greater difficulties. Feature A, which was first released, had a problem and had to be rolled back. How to do that. Rollback is another topic. Use REVERT instead of reset. However, Revert can only rollback a specified COMMIT, or consecutive COMMIT, and Cannot revert Merge. To rollback feature A, we need to find the version numbers of several submissions of feature A. Then, since they are not consecutive, we need to revert them separately. It would be too complicated to deal with. Fortunately, Github provides convenience, and PR provides an opportunity to revert. Find the old PR.

However, this is definitely not a good operation!


2. Recommended workflow

The reason for the above phenomenon is determined by the respective asynchronous programming. Because everyone can commit over time, when it’s finally combined with the commit timestamp as the sequence, it’s going to look like this. Therefore, if you can override the commit time to the current time and push it to the server when the commit remote server is needed, the history sequence will end.

2.1 Simulating User C

C User newly downloaded code.

$ git clone git@github.com:Ryan-miao/l4Git-workflow. Git C is cloned to'c'.remote: Counting objects: 28, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 28 (delta 8), reused 22 (delta 4), pack-reused 0In receiving objects:100% (285.90 KiB / 28), | 0 bytes /S, complete.100% (8/8Check the connection... To complete.Copy the code

Then edit and submit

$ cd c
$ git config user.name "C"
$ ls
a.txt  b.txt  readme.md  test.txt
$ vim c.txt
$ git add .
$ git commit -m "C write one"
[master cf3f757] C write one
 1 file changed.2 insertions(+)
 create mode 100644 c.txt
Copy the code

2.2 Simulating User D

Meanwhile, D also needs to develop new features

$ git clone git@github.com:Ryan-miao/l4Git-workflow. Git D Is cloned to'd'.remote: Counting objects: 28, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 28 (delta 8), reused 22 (delta 4), pack-reused 0In receiving objects:100% (285.90 KiB / 28), | 0 bytes /S, complete.100% (8/8Check the connection... To complete. $ cd d /d$ git config user.name"D"
/d$ vim d.txt
/d$ git add .
/d$ git commit -m "d write one"
[master db7a6e9] d write one
 1 file changed, 1 insertion(+)
 create mode 100644 d.txt
Copy the code

2.3C Continue development

$ vim c.txt
$ git add .
$ git commit -m "c write two"
[master 01b1210] c write two
 1 file changed.1 insertion(+)
Copy the code

2.4D development continues

/d$ vim d.txt
/d$ git add .
/d$ git commit -m "d write two"
[master a1371e4] d write two
 1 file changed.1 insertion(+)
Copy the code

2.5 C submit

$ vim c.txt 
$ git add .
$ git commit -m "c write three"
[master 13b7dde] c write three
 1 file changed.1 insertion(+)
Copy the code

C After development, commit to remote

$git status is located at the branch master where your branch is leading'origin/master'3A submission. (using the"git push"To publish your local commits) no files to commit, clean workspace $git push Originmaster:C object count:9Delta compression using up to4Threads. Compression object:100% (6/6Write to the object:100% (9/9), 750 bytes | 0 bytes/S, complete. Total9 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local object.
To git@github.com:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> C
Copy the code

PR 2.6 C

Then, create a Pull Request.

2.7C modification and push

Then, there is a bug that needs to be fixed and the change is committed to remote C again

$ vim c.txt 
$ git add .
$ git commit -m "C finish something else"
[master 2c5ff94] C finish something else
 1 file changed.1 insertion(+), 1 deletion(-)
$ git push origin master:CObject count:3Completed. Delta Compressionusing up to 4Threads. Compression object:100% (3/3Write to the object:100% (3/3), 301 bytes | 0 bytes/s, complete. Total3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To [email protected]:Ryan-Miao/l4git-workflow.git
   13b7dde.2.c5ff94  master -> C
Copy the code

2.8C finds that there are too many times of submission and the history is too chaotic, and merges part of the history

The problem is that C commits several times during development, and the messages are not really meaningful, just because C might be saving code, or it might be temporary. In a word, the first three messages submitted by C actually have the same meaning, they are all to create C files, and they are all a theme, so as to maintain a clean history. It is best to combine these three pieces of information into a single line C create file C.txt.

Referring to git merge history, we need to merge three histories into one display.

Check git history to find the starting range to merge

$ git log --oneline
2c5ff94 C finish something else
13b7dde c write three
01b1210 c write two
cf3f757 C write one
7151F4c Records the operation. 0bfe562 Merge pull request#2 from Ryan-Miao/b_remote
d81ce20 Merge remote-tracking branch 'origin/master' into b
2d74cfb Merge pull request #1 from Ryan-Miao/a
b90a3dd write three
4b1629e a write two
3f30f41 b write two
847078e b write one
53ff45e one
dae77d6 init
Copy the code

Obviously, it is to merge CF3F757 to 13B7DDE. So find the previous version number 7151F4C

git rebase - i 7151f4cCopy the code

Then we go to the interface because we want to merge the third and second submission and the first submission. Change the type of the third tosquash“, meaning merge with the second time. Then change the type of the second time tosquash, again referring to the previous commit of the merge.



The interaction is slightly different from Git to Git, and the previous Git bash on Windows was completely modified to follow vim’s commands. This test is based on Ubuntu and the archive command is foundctel + X. After confirmation, enter the next screen. After merging three submissions, a message is required

Delete or anyway you like, change message. The archive. To complete.

$git rebase -i 7151f4ccreate  file c.txt
 Date: Fri Oct 20 22:06:24 2017 +0800
 1 file changed.4 insertions(+)
 create mode 100644 c.txt
Successfully rebased and updated refs/heads/master.Copy the code

When an error occurs during rebase, use Git rebase –abort to return to the initial state. If conflicts are found, they can be resolved and git rebase –continue.

There seems to be a rebase-merge directory, and I suspect you are in the middle of another rebase operation. If so, please perform the git rebase (– the continue | – abort | – skip) if this is not the case, Please perform rm – fr “/ home/Ryan/temp/c /. Git/rebase – merge” and then to perform rebase operations. To avoid losing important data, I have stopped the current operation.

At this point, looking at log, it is clear that C’s three commits have been merged.

$ git log --oneline
50b9fe9 C finish something else
e3764c5 c create  file c.txt
7151F4c Records the operation.0bfe562 Merge pull request #2 from Ryan-Miao/b_remote
d81ce20 Merge remote-tracking branch 'origin/master' into b
2d74cfb Merge pull request #1 from Ryan-Miao/a
b90a3dd write three
4b1629e a write two
3f30f41 b write two
847078e b write one
53ff45e one
dae77d6 initCopy the code

2.9 C Push again

The previous push is no longer available. We need to open a new branch and push it through. Because rebase can only be done in the local branch. Do not modify common branches.

$ git push origin master:C
To git@github.com:Ryan-Miao/l4git-workflow.git
 ! [rejected]        master -> C (non-fast-forward)
error:Unable to push some references to'[email protected]:Ryan-Miao/l4git-workflow.git'Tip: The update was rejected because the latest commit of one branch of the push was behind its corresponding remote branch. Tip: Check out the branch and consolidate remote changes (e.g'git pull ... '), and then push. See tips:'git push --help'In the'Note about fast-forwards'Section.Copy the code

Select the new branch C2 for push

$ git push origin master:C2 object count:6Delta compression using up to4Threads. Compression object:100% (5/5Write to the object:100% (6/6), 569 bytes | 0 bytes/S, complete. Total6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To git@github.com:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> C2
Copy the code

Create a new PR

2.10 New merge mode: Rebase

As you can see from the normal flow at the beginning, every time you merge, there is a new commit, which makes history look strange. So, you can choose to rebase to master, which means to rebase the master, and move the current commit directly after the master. Multiple commit messages will not be split due to discrete commit times. chooserebase and merge

At this point, it can be seen that the two information submitted by C are up to date without crossover. No redundant merge information is generated.

One might ask, well, I can’t see the address of PR. Click on the history of C. As you can see below message is the number with PR:

By the way, remember close when you start PR

2.11 At this point D is also completed

/d$ git push origin master:D object count:10Delta compression using up to4Threads. Compression object:100% (7/7Write to the object:100% (104.49 KiB / 10), | 0 bytes /S, complete. Total10 (delta 2), reused 4 (delta 1)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To git@github.com:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> D
Copy the code

In this case, if merge is used:

As a result, 1) D’s submission message is inserted into the history according to time dispersion (before the history of C), and 2) There is another Merge pull Request #5 from Ryan-Miao/D.. Submit information of. As stated in the beginning, history began to get messy. So, what about this problem?

2.12 Rebase before Submission

Just like C rebase after merge to master. We can do that locally as well. In local Rebase, let’s make this feature commit all inserted into the master node in order, and easy to revert. This time, using the new E and F cross commit as an example, you will end up with separate histories

E:

$ git clone git@github.com:Ryan-miao/l4Git-workflow. Git e Is cloned to'e'.remote: Counting objects: 52, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 52 (delta 18), reused 36 (delta 7), pack-reused 0In receiving objects:100% (527.91 KiB / 52), | 0 bytes /S, complete.100% (18/18Check the connection... To complete. $ cd e /e$ vim e.txt /e$ git add . /e$ git config user.name"E"
/e$ git commit -m "e commit one"
[master 77ecd73] e commit one
 1 file changed, 1 insertion(+)
 create mode 100644 e.txt
Copy the code

F:

$ git clone git@github.com:Ryan-miao/l4Git-workflow. Git F is cloning to'f'.remote: Counting objects: 52, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 52 (delta 18), reused 36 (delta 7), pack-reused 0In receiving objects:100% (527.91 KiB / 52), | 0 bytes /S, complete.100% (18/18Check the connection... To complete. $ cd f $ vim f.txt $ git config user.name"F"
$ git add .
$ git commit -m "d write one"
[master b41f8c5] d write one
 1 file changed, 2 insertions(+)
 create mode 100644 f.txt
Copy the code

E:

/e$ vim e.txt
/e$ git add .
/e$ git commit -m "e write two"
[master 2b8c9fb] e write two
 1 file changed.1 insertion(+)
Copy the code

F:

$ vim f.txt
$ git add .
$ git commit -m "f write two"
[master de9051b] f write two
 1 file changed.1 insertion(+)
Copy the code

E:

/e$ vim e.txt 
/e$ git add .
/e$ git commit -m "e write three"
[master b1b9f6e] e write three
 1 file changed.2 insertions(+)
Copy the code

At this point, E is done and needs to commit. Rebase before submission:

/e$ git fetch
/e$ Git rebase origin/master The current branch master is the latest.Copy the code

Then, submit again

/e$ git push origin master:E object count:9Delta compression using up to4Threads. Compression object:100% (6/6Write to the object:100% (9/9), 753 bytes | 0 bytes/S, complete. Total9 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local object.
To git@github.com:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> E
Copy the code

And then PR merge.

The same F:

$git status is located at the branch master where your branch is leading'origin/master'2A submission. (using the"git push"To publish your local commits) no files to commit, clean workspace $git fetchremote: Counting objects: 12, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 12 (delta 6), reused 6 (delta 3), pack-reused 0Expand the object:100% (12/12From Github.com:Ryan-Miao/l4git-workflow
   24c6818.. F36907c master -> origin/master * [new branch] E -> origin/E $git rebase origin/master D write one F write two $git push Originmaster:F object count:6Delta compression using up to4Threads. Compression object:100% (4/4Write to the object:100% (6/6), 515 bytes | 0 bytes/S, complete. Total6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To git@github.com:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> F
Copy the code

PR, rebase and merge. Now look at history:

As in previous commits, E and F are crossed locally, and the timestamp of each commit is also crossed, so the history is not split when it is finally merged into the master. But in order, as we would expect. That’s what we want. You can also see the difference by looking at the graphical interface:

The green line is the master

So, the operation is fetch- rebase. In fact, the two can be combined:

git pull --rebase origin masterCopy the code

The final result

Before committing to the server, the history is distributed locally to each developer, but the commit time is sequential.

In accordance with therebaseThe usage before submissionrebaseOnce, a feature submission can be connected in series

The final Commit on Github looks much smoother

The golden rule

  1. To keep the tree clean, do git fetch and git rebase before Git push.
git fetch origin master
git rebase origin/master
git pushCopy the code

or

git pull --rebase origin masterCopy the code

As long as you use the rebase command as a tool to clean up commits before pushing, and only execute rebase commands on commits that have never been pushed to the common repository, you’ll be fine. If you do a base-change command on a commit that has been pushed to a shared repository, and thus discard some of the commits that other people’s development is based on, you’re in big trouble and your colleagues will despise you for it.

If you or your colleagues decide to do this at some point, be sure to tell everyone to run git pull –rebase. This will not prevent pain, but it will alleviate it.

  1. Never rebase on public (remote branches), that is, do not select Rebase on github merge if you do not have to, but instead use the method described above, before pushing your own branch locally
  2. Never reset on a public branch, and never use –force
  3. Learn to combine multiple commits for separate functions and keep them simple.
  4. Submit the message to summarize the changes as best as possible.

Reference source

  • Git-scm.com/book/zh/v2/…
  • Github.com/geeeeeeeeek…
  • Git-scm.com/book/zh/v1/…
  • Segmentfault.com/q/101000000…
So do it,and change it,no regret!