2021年1月23日 星期六

[Git 文章收集] How To Checkout Git Tags

 Source From Here

Preface
When working with Git, it is quite common for developers to create tags in order to have reference points in your development.

Tags are created in order to have references to release versions for example. Furthermore, tags are Git objects meaning that they can be checked out like you would check out a branch or a commit for example.

In this tutorial, we are going to see how you can checkout Git tags easily.

Checkout Git Tag
In order to checkout a Git tag, use the “git checkout” command and specify the tagname as well as the branch to be checked out:
  1. git checkout tags/<tag> -b <branch>  
Example:
# git log --oneline
c94e757 (HEAD -> master) add date into test.txt
bb134c5 (tag: v0.0.1, origin/master, origin/HEAD) Update 105M.img
faa8827 Upload large file >50M
66f0f1a Another commmit for merge testing
...


# git checkout tags/v0.0.1 -b my_branch
Switched to a new branch 'my_branch'

# git log --oneline | head -n 1 // Now we are at commit bb134c5 which has tag v0.0.1
bb134c5 Update 105M.img

Note that you will have to make sure that you have the latest tag list from your remote repository. To fetch tags from your remote repository, use “git fetch” with the “–all” and the “–tags” options:
# git pull -all -tags
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 1 (delta 0), pack-reused 0
Unpacking objects: 100% (1/1), 142 bytes | 142.00 KiB/s, done.
From https://github.com/johnklee/GitPro
* [new tag] v0.0.1 -> v0.0.1
Already up to date.

You can inspect the state of your branch by using the “git log” command. Make sure that the HEAD pointer (the latest commit) is pointing to your annotated tag.


Checkout latest Git tag
In some cases, you may be interested in checking out the latest Git tag of your repository. In order to checkout the latest Git tag, first update your repository by fetching the remote tags available.
# git fetch --tags
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 8 (delta 2), reused 8 (delta 2), pack-reused 0
Unpacking objects: 100% (8/8), 762 bytes | 127.00 KiB/s, done.
From https://github.com/johnklee/GitPro
bb134c5..783a307 master -> origin/master
* [new tag] v0.0.2 -> v0.0.2

As you can see, you retrieve the tag from your remote repository. Then, retrieve the latest tag available by using the “git describe” command:
# git log --oneline
783a307 (HEAD -> master, origin/master, origin/HEAD) commit after v0.0.2
ad16543 (tag: v0.0.2) commit for v0.0.2
bb134c5 (tag: v0.0.1, my_branch) Update 105M.img
faa8827 Upload large file >50M
...


# git rev-list --tags --max-count=1
ad16543cd4d8252ec2faf3b743fea1cc94550963

# git describe --tags `git rev-list --tags --max-count=1`
v0.0.2

# tag=$(git describe --tags `git rev-list --tags --max-count=1`)
# echo $tag
v0.0.2

# git checkout $tag -b latest
Switched to a new branch 'latest'

# git log --oneline --graph // Confirm the result
...

That’s it! You have successfully checkout the latest Git tag available in a new branch.

Supplement
2.6 Git 基礎 - 標籤

2021年1月22日 星期五

[ Docker 常見問題 ] How to clear the logs properly for a Docker container?

 Source From Here

Question
I use docker logs [container-name] to see the logs of a specific container. Is there an elegant way to clear these logs?

HowTo
First the bad answer. From this question there's a one-liner that you can run:
$ echo "" > $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

instead of echo, there's the simpler:
$ : > $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

or there's the truncate command:
$ truncate -s 0 $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)


I'm not a big fan of either of those since they modify Docker's files directly. The external log deletion could happen while docker is writing json formatted data to the file, resulting in a partial line, and breaking the ability to read any logs from the docker logs cli. For an example of that happening, see this comment on duketwo's answer

Instead, you can have Docker automatically rotate the logs for you. This is done with additional flags to dockerd if you are using the default JSON logging driver:
$ dockerd ... --log-opt max-size=10m --log-opt max-file=3

You can also set this as part of your daemon.json file instead of modifying your startup scripts:
  1. {  
  2.   "log-driver""json-file",  
  3.   "log-opts": {"max-size""10m""max-file""3"}  
  4. }  
These options need to be configured with root access. Make sure to run a systemctl reload docker after changing this file to have the settings applied. This setting will then be the default for any newly created containers. Note, existing containers need to be deleted and recreated to receive the new log limits.

[Git 常見問題] Rename a local and remote branch in git

 Source From Here

Question
If you have named a branch incorrectly AND pushed this to the remote repository follow these steps before any other developers get a chance to jump on you and give you shit for not correctly following naming conventions. How are you going to rename your branch?

HowTo

1. Rename your local branch.
If you are on the branch you want to rename:
$ git branch -m new-name

If you are on a different branch:
$ git branch -m old-name new-name

2. Delete the old-name remote branch and push the new-name local branch.
$ git push origin :old-name new-name

3. Reset the upstream branch for the new-name local branch.
Switch to the branch and then:
$ git push origin -u new-name


[Gradle in action] Ch4. Build script essentials - Part2

 (https://www.manning.com/books/gradle-in-action) 

Hooking into the build lifecycle

As a build script developer, you’re not limited to writing task actions or configuration logic, which are evaluated during a distinct build phase. Sometimes you’ll want to execute code when a specific lifecycle event occurs. A lifecycle event can occur before, during, or after a specific build phase. An example of a lifecycle event that happens after the execution phase would be the completion of a build.

Suppose you want to get feedback about failed builds as early as possible in the development cycle. A typical reaction to a failed build could be that you send an email to all developers on the team to restore the sanity of your code. There are two ways to write a callback to build lifecycle events: within a closure, or with an implementation of a listener interface provided by the Gradle API. Gradle doesn’t steer you toward one of the options to listen to lifecycle events. The choice is up to you. The big advantage you have with a listener implementation is that you’re dealing with a class that’s fully testable by writing unit tests. To give you an idea of some of the useful lifecycle hooks, see figure 4.11.


An extensive list of all available lifecycle hooks is beyond the scope of this book. Many of the lifecycle callback methods are defined in the interfaces [b]Project and Gradle. [/b]Gradle’s Javadocs are a great starting point to find the appropriate event callback for your use case.
Don’t be afraid of making good use of lifecycle hooks. They’re not considered a secret backdoor to Gradle’s API. Instead, they’re provided intentionally because Gradle can’t predict the requirements for your enterprise build.

In the following two sections, I’ll demonstrate how to receive notifications immediately after the task execution graph has been populated. To fully understand what’s happening under the hood when this graph is built, we’ll first look at Gradle’s inner workings.

INTERNAL TASK GRAPH REPRESENTATION
At configuration time, Gradle determines the order of tasks that need to be run during the execution phase. As noted in chapter 1the internal structure that represents these task dependencies is modeled as a directed acyclic graph (DAG). Each task in the graph is called a node, and each node is connected by directed edges. You’ve most likely created these connections between nodes by declaring a dependsOn relationship for a task or by leveraging the implicit task dependency interference mechanism. It’s important to note that DAGs never contain a cycle. In other words, a task that has been executed before will never be executed again. Figure 4.12 demonstrates the DAG representation of the release process modeled earlier.


Now that you have a better idea of Gradle’s internal task graph representation, you’ll write some code in your build script to react to it.

Hooking into the task execution graph
Recall the task makeReleaseVersion you implemented that was automatically executed as a dependency of the task release. Instead of writing a task to change the project’s version to indicate production-readiness, you could also achieve the same goal by writing a lifecycle hook. Because the build knows exactly which tasks will take part in the build before they get executed, you can query the task graph to check for its existence. Figure 4.13 shows the relevant interfaces and their methods to access the task execution graph.


Next you’ll put the lifecycle hook in place. Listing 4.13 extends the build script by the method call whenReady to register a closure that’s executed immediately after the task graph has been populated. Because you know that the logic is run before any of the tasks in the graph are executed, you can completely remove the task makeReleaseVersion and omit the dependsOn declaration from createDistribution.
- Listing 4.13 Release version functionality implemented as lifecycle hook
  1. gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->  
  2.     if(taskGraph.hasTask(release)) {  
  3.         if(!version.release) {  
  4.             version.release = true  
  5.             ant.propertyfile(file: versionFile) {  
  6.                 entry(key: 'release', type: 'string', operation: '=', value: 'true')  
  7.             }  
  8.         }  
  9.     }  
  10. }  
Alternatively, you can implement this logic as a listener, which you’ll do next.

Implementing a task execution graph listener
Hooking into the build lifecycle via a listener is done in two simple steps. First, you implement the specific listener interface by writing a class within your build script. Second, you register the listener implementation with the build.

The interface for listening to task execution graph events is provided by the interface TaskExecutionGraphListener. At the time of writing, you only need to implement one method: graphPopulate(TaskExecutionGraph). Figure 4.14 shows the listener implementation named ReleaseVersionListener.


Keep in mind that you don’t have direct access to the Project instance if you add the listener to your build script. Instead, you can work Gradle’s API to its fullest. The following listing shows how to access the project by calling the getProject() method on the release task.
- Listing 4.14 Release version functionality implemented as lifecycle listener
  1. class ReleaseVersionListener implements TaskExecutionGraphListener {  
  2.     final static String releaseTaskPath = ':release'  
  3.     @Override  
  4.     void graphPopulated(TaskExecutionGraph taskGraph) {  
  5.         if(taskGraph.hasTask(releaseTaskPath)) {  
  6.             List<Task> allTasks = taskGraph.allTasks  
  7.             Task releaseTask = allTasks.find {it.path == releaseTaskPath }  
  8.             Project project = releaseTask.project  
  9.             if(!project.version.release) {  
  10.                 project.version.release = true  
  11.                 project.ant.propertyfile(file: project.versionFile) {  
  12.                     entry(key: 'release', type: 'string', operation: '=', value: 'true')  
  13.                 }  
  14.             }  
  15.         }  
  16.     }  
  17. }  
  18.   
  19. def releaseVersionListener = new ReleaseVersionListener()  
  20. gradle.taskGraph.addTaskExecutionGraphListener(releaseVersionListener)  
You’re not limited to registering a lifecycle listener in your build script. Lifecycle logic can be applied to listen to Gradle events even before any of your project’s tasks are executed. In the next section, we’ll explore options for hooking into the lifecycle via initialization scripts to customize the build environment.

Initializing the build environment
Let’s say you want to be notified about the outcome of a build. Whenever a build finishes, you’ll want to know whether it was successful or failed. You also want to be able to identify how many tasks have been executed. One of Gradle’s core plugins, the build-announcements plugin, provides a way to send announcements to a local notification system like Snarl (Windows) or Growl (Mac OS X). The plugin automatically picks the correct notification system based on your OS. Figure 4.15 shows a notification rendered by Growl.


You could apply the plugin to every project individually, but why not use the powerful mechanisms Gradle provides? Initialization scripts are run before any of your build script logic has been evaluated and executed. You’ll write an initialization script that applies the plugin to any of your projects without manual intervention. Create the initialization script under <USER_HOME>/.gradle/init.d, as shown in the following directory tree:
  1. root@localhost:ch4# tree ~/.gradle/init.d/  
  2. /root/.gradle/init.d/  
  3. └── build-announcements.gradle  
  4.   
  5. 0 directories, 1 file  
Gradle will execute every initialization script it finds under init.d as long as the file extension matches .gradle. Because you want to apply the plugin before any other build script code is executed, you’ll pick the lifecycle callback method that’s most appropriate for handling this situation: Gradle#projectLoaded(Closure). The following code snippet shows how to apply the build-announcements plugin to the build’s root project:
  1. gradle.projectsLoaded { Gradle gradle ->  
  2.     gradle.rootProject {  
  3.         apply plugin: 'build-announcements'  
  4.     }  
  5. }  
An important lesson to learn in this context is that some lifecycle events are only fired if they’re declared in the appropriate location. For example, the closure for the lifecycle hook Gradle#projectsLoaded(Closure) wouldn’t get fired if you declared it in your build.gradle, because the project creation happens during the initialization phase.

[Git 文章收集] How To Checkout Git Tags

  Source From  Here Preface When working with Git, it is quite common for developers to create tags in order to have reference points in you...