2026-01-20 14:06:19
For a long time, I thought Git was just something I had to survive.
Type a command.
Hope nothing breaks.
If it does… Google fast.
I memorized commands without understanding them.
Copied fixes from Stack Overflow.
Prayed I wouldn’t see merge conflicts.
And somehow… I kept using Git every day without ever feeling confident.
It took me a while to realize this:
Most developers don’t use all of Git.
They use a small set of commands... deeply.
And once I stopped treating Git like magic,
it became a tool I could actually trust.
Git feels intimidating at first because it remembers everything.
Every mistake.
Every experiment.
Every “I’ll clean this later.”
And that can be scary.
But Git isn’t judging you.
It’s protecting your work, even when you don’t realize it yet.
Once I accepted that, learning Git stopped feeling like pressure…
and started feeling like control.
You don’t need 50 commands.
You need the right 15, used calmly and intentionally.
These are the ones that show up in real projects, real teams, real days.
git status — Check the Current State of Your Repository
git statusshows which files are modified, staged, untracked, or ready to be committed in your repository.
Common mistake:
Running other Git commands without checking git status first, this is how people commit or delete the wrong files.
git init — Initialize a New Git Repository
git initcreates a new Git repository by adding version control tracking to a project directory.
Common mistake:
Running git init inside an already-initialized repo, creating a nested .git folder and confusing Git completely.
git clone — Copy a Remote Repository Locally
git clonedownloads a remote repository and creates a full local copy, including its commit history.
Common mistake:
Cloning a repo and immediately pushing changes without understanding the branch structure.
git add — Stage Changes for the Next Commit
git addmoves file changes into the staging area so they can be included in the next commit.
git add .
Adds all changes in the current directory and subfolders.
⚠️ If you’re inside a subfolder, parent directory files won’t be included.
git add *
Adds only non-hidden files in the current directory.
⚠️ Skips files like .env, .gitignore.
git add :
Adds all changes from the repository root, including hidden files.
✅ Safest option when you want everything, regardless of location.
Common mistake:
Using git add . blindly and accidentally staging files you didn’t intend to commit.
git commit — Save a Snapshot of Your Changes
git commitrecords staged changes as a snapshot in the project’s history with a descriptive message.
Common mistake:
Writing vague messages like “update” or “fix stuff”, which makes future debugging painful.
git log — View the Commit History
git logdisplays a list of previous commits, showing changes, authors, and timestamps.
Common mistake:
Ignoring commit history and trying to guess when a bug was introduced.
git diff — See What Has Changed
git diffshows line-by-line differences between file versions, commits, or branches.
Common mistake:
Skipping git diff and committing code without reviewing what actually changed.
git branch — Manage Parallel Development
git branchlets you create, list, rename, or delete branches for separate lines of development.
Common mistake:
Doing all work on main instead of creating feature branches.
git checkout / git switch — Move Between Branches Safely
These commands allow you to move between branches.
Onlygit checkoutcan also be used to restore files from another branch or commit.
git checkout branch-name
Old but still widely used.
git switch branch-name
Newer, clearer, and safer for switching branches.
Common mistake:
Switching branches with uncommitted changes and accidentally losing work.
git merge — Combine Changes From Different Branches
git mergeintegrates changes from one branch into another, combining their histories.
Common mistake:
Merging without pulling the latest changes first, leading to unnecessary conflicts.
git pull — Update Your Local Repository
git pullfetches changes from a remote repository and integrates them into your current branch (by merge or rebase, depending on configuration)
Common mistake:
Pulling into a dirty working directory instead of committing or stashing first.
git push — Share Your Commits With Others
git pushuploads your local commits to a remote repository so others can access them.
Common mistake:
Forgetting to pull before pushing, causing rejected pushes and confusion.
git stash — Temporarily Save Unfinished Work
git stashstores uncommitted changes so you can return to a clean working directory.
git stash
Saves changes and cleans the working directory.
git stash pop
Restores the most recent stash and removes it.
git stash list
Shows all saved stashes.
Common mistake:
Stashing changes and forgetting they exist.
git reset — Undo Changes With Control
git resetmoves the current branch pointer and optionally updates the staging area and working directory.
git reset --soft HEAD~1
Keeps changes staged.
git reset --mixed HEAD~1 (default)
Keeps changes unstaged.
git reset --hard HEAD~1
Deletes changes permanently.
Common mistake:
Using --hard without understanding that it permanently removes work.
git revert — Undo Changes Safely in Shared History
git revertcreates a new commit that reverses the effects of a previous commit without rewriting history.
Common mistake:
Using git reset on shared branches instead of git revert, rewriting history for teammates.
Here’s the thing nobody tells you:
Git confidence doesn’t arrive suddenly.
It grows slowly.
After mistakes.
After conflicts.
After fixing something you thought was broken forever.
One day, you stop panicking.
You pause.
You check git status.
And you move forward calmly.
That’s progress.
❌ I don’t copy commands blindly
❌ I don’t fear breaking things
❌ I don’t rush through conflicts
❌ I don’t treat Git like magic
Git isn’t something to fight.
It’s something to understand... one command at a time.
If Git feels confusing right now, that’s okay.
It felt that way for all of us.
You don’t need to master everything.
You just need to get comfortable with the basics and trust that clarity comes with use.
Git commands aren’t about perfection.
They’re about progress, history, and helping software engineers learn without losing their work 💻
Take your time.
Make mistakes.
Commit thoughtfully.
Wishing you clean commits, fewer conflicts, and confidence in your Git journey, friends 💙.
| Thanks for reading! 🙏🏻 I hope you found this useful ✅ Please react and follow for more 😍 Made with 💙 by Hadil Ben Abdallah |
|
|---|
2026-01-20 14:05:14
I’ve been deep in developing Bloom lately, and constantly having new ideas, so this update brings some of the biggest improvements so far.
This release strengthens the core tools and adds a brand‑new searchable HRT medication database.
Bloom’s HRT section now reflects how people actually manage their regimens.
Medication regimen templates for patches, injections, pills, and gel
Custom reminders for dose times, patch changes, injections, and labs
Injection site rotation tracker
Lab result logging with charts
Side‑effect tracking
Transition is emotional and nonlinear, so Bloom’s journaling tools stay gentle and low‑pressure.
Dysphoria/euphoria tags
Transition milestone tracking
Guided prompts, including a low‑energy mode for tough days
Bloom is built for people who can’t always be out or safe.
Quick‑exit button
Optional PIN/biometric lock
Discreet mode to rename or hide the app
You can now open Medication Database from the sidebar (look for the database icon) to browse clear, accessible info on common HRT medications.
What’s included:
15+ medications
Search by name or purpose
Filters: Estrogen, Anti‑Androgen, Progestin, Testosterone, Other
Each entry includes:
Generic & brand names
Primary use
Administration routes
Common dosage ranges
Side effects & warnings
Key considerations
Prescription status
Covers estradiol (all forms), spironolactone, bicalutamide, progesterone, testosterone (injections, gel, patch), Lupron, and more. A medical disclaimer reminds users to consult their providers.
Want to try Bloom or share feedback?
If any of this speaks to you, I’d love for you to check Bloom out and tell me what you think. It’s still evolving, and community feedback genuinely shapes what I build next. Whether you have ideas, critiques, or thoughts — I would love to hear them.
2026-01-20 14:01:36
PDFs are a cornerstone of digital documentation, often serving as final, immutable records. However, there are many scenarios where bundling supplementary information directly within the PDF itself can significantly enhance its utility. Whether it's source code accompanying a technical report, related documents, or multimedia files, the ability to embed attachments programmatically offers immense practical value for developers. This article will guide you through the process of inserting various types of attachments into PDF documents using C#, focusing on two distinct methods: direct embedding and attachment annotations.
A PDF attachment, often referred to as an embedded file, is essentially another file (of any format) stored directly within the PDF document's structure. Unlike external links, these files are self-contained, meaning the PDF remains complete and portable even if the original attachment files are moved or deleted from their source location.
Common use cases for embedding files include:
PDFs offer two primary ways to incorporate these embedded files:
These methods provide flexibility depending on whether the attachment needs to be visually highlighted on a page or simply included as supplementary data.
Before we dive into the code, you'll need to set up your C# .NET project to work with PDF documents. For this tutorial, we will be using Spire.PDF for .NET, a robust library for PDF processing.
Step-by-step project setup:
Spire.PDF.Spire.PDF from the search results and click "Install".Once installed, you'll typically start your C# file with the necessary using statements:
using Spire.Pdf;
using Spire.Pdf.Attachments;
using Spire.Pdf.Annotations;
using System.IO;
using System.Drawing; // For RectangleF and Color
This setup provides access to all the classes and methods required for PDF manipulation, including handling attachments and annotations.
Direct embedding is suitable when you want to include files as part of the PDF's overall structure without tying them to a specific visual element on a page. These attachments are typically accessed through an "Attachments" panel or similar interface within PDF viewer applications.
Let's walk through the process of directly embedding a file into a PDF. We'll use an existing PDF document and embed an image file into it.
Key Steps:
PdfDocument object. You can load an existing PDF or create a new one.PdfAttachment Object: Instantiate PdfAttachment, providing the file name.PdfAttachment object to the doc.Attachments collection.Here's a complete C# code snippet demonstrating direct attachment insertion:
using Spire.Pdf;
using Spire.Pdf.Attachments;
using System.IO;
namespace PdfAttachmentTutorial
{
class Program
{
static void Main(string[] args)
{
// Load an existing PDF document
PdfDocument doc = new PdfDocument();
doc.LoadFromFile("InputDocument.pdf"); // Use this if you are processing an existing PDF
// --- Embed a text file ---
string textFilePath = "AttachedText.txt";
File.WriteAllText(textFilePath, "This is some sample text content for the embedded file.");
PdfAttachment textAttachment = new PdfAttachment(textFilePath);
textAttachment.Data = File.ReadAllBytes(textFilePath);
textAttachment.Description = "Supplemental text information.";
textAttachment.MimeType = "text/plain";
doc.Attachments.Add(textAttachment);
// --- Embed an image file ---
// For demonstration, let's assume you have an image file named "sample_image.png"
// You might need to create a dummy image file or use an existing one.
// Example: byte[] imageData = File.ReadAllBytes("path/to/your/image.png");
// If you don't have one, this part will throw an error unless you create a dummy file.
// For this example, we'll assume a dummy image exists.
string imageFilePath = "sample_image.png";
// In a real scenario, ensure this file exists or create it.
// Example: System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(100, 100); bmp.Save(imageFilePath);
// Let's create a dummy image for the example if it doesn't exist
if (!File.Exists(imageFilePath))
{
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(100, 100))
{
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bmp))
{
graphics.FillRectangle(System.Drawing.Brushes.Blue, 0, 0, 100, 100);
graphics.DrawString("Dummy", new System.Drawing.Font("Arial", 12), System.Drawing.Brushes.White, 10, 40);
}
bmp.Save(imageFilePath, System.Drawing.Imaging.ImageFormat.Png);
}
}
PdfAttachment imageAttachment = new PdfAttachment(imageFilePath);
imageAttachment.Data = File.ReadAllBytes(imageFilePath);
imageAttachment.Description = "A supporting image for the document.";
imageAttachment.MimeType = "image/png";
doc.Attachments.Add(imageAttachment);
// Save the modified PDF
doc.SaveToFile("PdfWithDirectAttachments.pdf");
doc.Close();
Console.WriteLine("PDF with direct attachments created successfully!");
}
}
}
Preview of the PDF:
Spire.PDF Methods for Direct Embedding:
| Method/Property | Description |
|---|---|
PdfDocument |
Represents a PDF document. Used to load, create, and save PDFs. |
PdfAttachment |
Represents an embedded file within the PDF. |
PdfAttachment(string) |
Constructor to create an attachment with its file name. |
Data |
byte[] property to set the content of the attached file. |
Description |
string property for a user-friendly description of the attachment. |
MimeType |
string property to specify the MIME type (e.g., "text/plain", "image/png"). |
doc.Attachments.Add() |
Adds a PdfAttachment object to the document's collection of attachments. |
doc.SaveToFile() |
Saves the PDF document to a specified file path. |
After running this code, open PdfWithDirectAttachments.pdf in a PDF viewer, and you should find the "AttachedText.txt" and "sample_image.png" files listed in the attachments panel.
Attachment annotations provide a visual cue on a specific page of the PDF, indicating the presence of an embedded file. When a user clicks this icon, the associated embedded file is opened. This is particularly useful for highlighting supplementary content directly related to a section of the document.
Let's enhance our previous example by adding an attachment annotation to the first page of the PDF.
Key Steps:
PdfDocument.doc.Pages[index].PdfAttachment object (you can use an already embedded one or a new one).RectangleF for the icon's position and size on the page.PdfAttachmentAnnotation: Instantiate this class, linking it to the PdfAttachment and defining its appearance.PdfAttachmentAnnotation to the page.Annotations collection.using Spire.Pdf;
using Spire.Pdf.Attachments;
using Spire.Pdf.Annotations;
using System.IO;
using System.Drawing; // For RectangleF and Color
namespace PdfAttachmentTutorial
{
class Program
{
static void Main(string[] args)
{
// Load an existing PDF document
PdfDocument doc = new PdfDocument();
doc.LoadFromFile("InputDocument.pdf"); // Ensure InputDocument.pdf exists
// Get the first page
PdfPageBase page = doc.Pages[0];
// --- First, embed a file (if not already embedded) ---
string documentFilePath = "Sample.docx";
// Create a dummy docx file for demonstration
if (!File.Exists(documentFilePath))
{
using (StreamWriter writer = new StreamWriter(documentFilePath))
{
writer.WriteLine("This is a dummy Word document content.");
writer.WriteLine("It's attached as an annotation.");
}
}
PdfAttachment docxAttachment = new PdfAttachment(documentFilePath);
docxAttachment.Data = File.ReadAllBytes(documentFilePath);
docxAttachment.Description = "Detailed supplementary document.";
docxAttachment.MimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
// --- Now, create an attachment annotation on the page ---
// Define bounds for the annotation icon (X, Y, Width, Height)
RectangleF bounds = new RectangleF(50, 100, 30, 30); // Position and size of the icon
// Create the attachment annotation, associating it with the embedded file
PdfAttachmentAnnotation annotation = new PdfAttachmentAnnotation(bounds, docxAttachment.FileName, docxAttachment.Data);
// Set annotation properties
annotation.Text = "Click to open supplementary document"; // Tooltip text
annotation.Color = Color.Blue; // Color of the icon
annotation.Icon = PdfAttachmentIcon.Paperclip; // Icon type (e.g., Paperclip, Pushpin, Graph)
// Add the annotation to the page
page.Annotations.Add(annotation);
// Save the modified PDF
doc.SaveToFile("PdfWithAttachmentAnnotation.pdf");
doc.Close();
Console.WriteLine("PDF with attachment annotation created successfully!");
}
}
}
Preview of the PDF:
Spire.PDF Methods for Attachment Annotations:
| Method/Property | Description |
|---|---|
PdfPageBase |
Represents a single page in the PDF document. |
PdfAttachmentAnnotation |
Represents a visual icon on a page linked to an embedded file. |
PdfAttachmentAnnotation(RectangleF, PdfAttachment) |
Constructor to create an annotation, specifying its bounds and linked attachment. |
Text |
string property for the tooltip text displayed when hovering over the icon. |
Color |
Color property to set the color of the annotation icon. |
Icon |
PdfAttachmentIcon enum to choose the icon's visual style (e.g., Paperclip, Pushpin). |
page.Annotations.Add() |
Adds a PdfAttachmentAnnotation object to the page's collection of annotations. |
When you open PdfWithAttachmentAnnotation.pdf, you'll see a blue paperclip icon at the specified coordinates (50, 100) on the first page. Clicking this icon will open the "SupplementaryDoc.docx" file that was embedded.
The ability to programmatically insert attachments into PDF documents using C# offers a powerful way to create richer, more self-contained, and interactive documentation. Whether you need to bundle related files discreetly within the PDF's structure or visually highlight supplementary content on a specific page, Spire.PDF for .NET provides intuitive and effective tools for both direct attachment insertion and attachment annotation insertion.
By following the steps and code examples provided, you can integrate these capabilities into your C# applications, enhancing document processing workflows and delivering more comprehensive PDF outputs. Experiment with different file types, icon styles, and attachment descriptions to fully leverage the flexibility offered by these techniques. Further exploration of the Spire.PDF documentation will uncover even more advanced possibilities for PDF manipulation.
2026-01-20 14:01:20
Join Bill Simmons, Kyle Brandt, and Joanna Robinson on 'The Rewatchables' as they dive headfirst into the 1985 teen comedy 'Just One of the Guys.' They're practically pursuing a journalism career just by revisiting this flick, starring Joyce Hyser, Clayton Rohner, and Billy Jayne.
Watch on YouTube
2026-01-20 13:58:59
What happens when you build a web framework with one simple rule: zero dependencies? That's the question behind Marten, a minimal HTTP framework built entirely on Go's standard library.
Most Go web frameworks pull in dozens of dependencies. Gin has 9 direct dependencies. Echo has 11. Fiber has 15. Each dependency brings its own dependencies, and suddenly your go.mod looks like a phone book.
Marten takes a different approach: use only what Go gives you. No external packages. No vendor lock-in. Just net/http, encoding/json, and the rest of the standard library.
Here's a complete API in Marten:
package main
import (
"github.com/gomarten/marten"
"github.com/gomarten/marten/middleware"
)
func main() {
app := marten.New()
app.Use(middleware.Logger)
app.Use(middleware.Recover)
app.GET("/", func(c *marten.Ctx) error {
return c.OK(marten.M{"message": "Hello, World!"})
})
app.GET("/users/:id", func(c *marten.Ctx) error {
id := c.ParamInt("id")
return c.OK(marten.M{"id": id})
})
app.Run(":8080")
}
Clean. Familiar. No magic.
Marten uses a radix tree router for efficient path matching. It handles path parameters (:id), wildcards (*filepath), and route groups:
api := app.Group("/api/v1")
api.GET("/users", listUsers)
api.GET("/users/:id", getUser)
api.POST("/users", createUser)
Middleware in Marten is just a function that wraps a handler:
func Timer(next marten.Handler) marten.Handler {
return func(c *marten.Ctx) error {
start := time.Now()
err := next(c)
log.Printf("took %v", time.Since(start))
return err
}
}
The framework includes 14 built-in middleware: Logger, Recover, CORS, RateLimit, BasicAuth, Timeout, Secure, BodyLimit, Compress, ETag, RequestID, Static, and NoCache.
Every request gets a Ctx object from a sync.Pool. This reduces allocations and keeps memory usage low, even under heavy load:
func handler(c *marten.Ctx) error {
// Path parameters
id := c.Param("id")
// Query parameters
page := c.QueryInt("page")
// JSON binding
var user User
c.Bind(&user)
// Response helpers
return c.OK(user)
}
The latest release (v0.1.3) adds static file serving with all the features you'd expect:
app.Use(middleware.StaticWithConfig(middleware.StaticConfig{
Root: "./public",
Prefix: "/static",
MaxAge: 3600,
Browse: false,
}))
Content-type detection, HTTP caching (If-Modified-Since), directory browsing, and security against directory traversal attacks—all built-in.
How does a zero-dependency framework perform? Surprisingly well.
Benchmarks against Gin, Echo, and Chi show Marten holding its own:
| Benchmark | Marten | Gin | Echo | Chi |
|---|---|---|---|---|
| Static Route | 1464 ns/op | 1336 ns/op | 1436 ns/op | 2202 ns/op |
| Param Route | 1564 ns/op | 1418 ns/op | 1472 ns/op | 2559 ns/op |
| JSON Response | 1755 ns/op | 2050 ns/op | 1835 ns/op | 1868 ns/op |
Not the fastest, but competitive. And with zero dependencies.
When you're building dozens of microservices, dependency bloat adds up. Marten keeps your Docker images small and your build times fast.
Build production-ready APIs with built-in middleware for logging, rate limiting, CORS, and authentication:
app := marten.New()
app.Use(
middleware.RequestID,
middleware.Logger,
middleware.Recover,
middleware.CORS(middleware.DefaultCORSConfig()),
middleware.RateLimit(middleware.RateLimitConfig{
Max: 100,
Window: time.Minute,
}),
)
api := app.Group("/api/v1")
api.GET("/users", listUsers)
api.POST("/users", createUser, authMiddleware)
Serve your SPA with automatic fallback to index.html for client-side routing:
// API routes
app.GET("/api/users", listUsers)
// Serve static files
app.Use(middleware.Static("./dist"))
// SPA fallback
app.NotFound(func(c *marten.Ctx) error {
if strings.HasPrefix(c.Path(), "/api/") {
return c.NotFound("endpoint not found")
}
// Serve index.html for client-side routing
return c.HTML(200, indexHTML)
})
Want to understand how web frameworks work? Read Marten's source. It's ~2,000 lines of readable Go code. No abstractions hiding abstractions.
Marten v0.1.3 ships with 325 tests covering:
All tests pass with Go's race detector. No known memory leaks. Production-ready.
Marten doesn't have:
database/sql directlyhtml/template from stdlibThe philosophy is simple: if the standard library can do it, use the standard library. If you need more, add it yourself.
Future releases will add:
But always with the same constraint: zero dependencies.
go get github.com/gomarten/[email protected]
Check out the examples for CRUD APIs, JWT auth, file servers, and more.
Marten isn't trying to replace Gin or Echo. It's an experiment in minimalism. A proof that you can build a capable web framework without pulling in the world.
Sometimes, less is more.
Links: