lvgl 页面管理器

news2025/1/8 11:43:48

lv_scr_mgr

lvgl 界面管理器

适配 lvgl 8.3

  • 降低界面之间的耦合
  • 使用较小的内存,界面切换后会自动释放内存
  • 内存泄漏检测
    请添加图片描述

使用方法

  1. 在lv_scr_mgr_port.h 中创建一个枚举,用于界面ID
  2. 为每个界面创建一个页面管理器句柄
  3. 将界面句柄添加到 lv_scr_mgr_port.c 数组中
  4. 在 lv_init() 后,对页面管理器进行初始化 lv_scr_mgr_init(NULL);
  5. 使用 lv_scr_mgr_switch 设置初始根界面
  6. 使用 lv_scr_mgr_push lv_scr_mgr_pop 对界面进行操作

git地址

git地址
gitee

/**
  *******************************CopyRight  ************************************
  * @file    lv_scr_mgr.c
  * @author  不咸不要钱
  * @date    2023-10-11 13:4:36
  * @brief   &#&
  *          
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "lvgl.h"
#include "lv_scr_mgr.h"
#if !LV_SCR_MGR_REG_ENABLE
#include "lv_scr_mgr_port.c"
#endif

typedef struct
{
    uint32_t               scr_cnt; 
    void*                  param;
    lv_scr_mgr_handle_t    **handles;
#if LV_SCR_MGR_PRINTF_MEM
    uint32_t               *max_mem;
#endif
}scr_mgr_list_handle_t;


static scr_mgr_list_handle_t     mgr_list;
static lv_scr_mgr_stack_node_t*      mgr_stack_top = NULL;
static lv_scr_mgr_stack_node_t*      mgr_stack_root = NULL;

static lv_scr_mgr_handle_t* find_handle_by_id(uint32_t id)
{
    for (int i = 0; i < mgr_list.scr_cnt; i++)
    {
        if (mgr_list.handles[i]->scr_id == id)
        {
            return mgr_list.handles[i];
        }
    }
    return NULL;
}
#if LV_SCR_MGR_PRINTF_MEM
static uint32_t* find_mem_addr_by_id(uint32_t id)
{
    for (int i = 0; i < mgr_list.scr_cnt; i++)
    {
        if (mgr_list.handles[i]->scr_id == id)
        {
            return &mgr_list.max_mem[i];
        }
    }
    return NULL;
}

static void mem_max_printf(uint32_t id)
{
    static uint32_t mem_max = 0;
    lv_mem_monitor_t mon;
    lv_mem_monitor(&mon);
    if (mon.total_size - mon.free_size > mem_max)
    {
        mem_max = mon.total_size - mon.free_size;
        LV_LOG_USER("used: %d (%d %%), frag: %d %%, biggest free: %d\n", mem_max,
            mon.used_pct,
            mon.frag_pct,
            (int)mon.free_biggest_size);
    }

    /* 当前界面最大使用内存 */
    uint32_t* page_max_mem = find_mem_addr_by_id(id);
    if (mon.total_size - mon.free_size > *page_max_mem)
    {
        *page_max_mem = mon.total_size - mon.free_size;
        LV_LOG_USER("page id %d, used: %d (%d %%), frag: %d %%, biggest free: %d\n", id, *page_max_mem,
            mon.used_pct,
            mon.frag_pct,
            (int)mon.free_biggest_size);
    }
}

static void anim_mem_max_printf(lv_event_t* e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    if (event_code == LV_EVENT_SCREEN_LOADED)
    {
        mem_max_printf((uint32_t)lv_event_get_user_data(e));
    }
}
#endif

static void scr_mgr_stack_free(void)
{
    lv_scr_mgr_stack_node_t* stack_node = NULL;

    /* 释放界面栈 */
    while (NULL != mgr_stack_top)
    {
        stack_node = mgr_stack_top->prev;
        if(mgr_stack_top->handle->scr_destroy)
            mgr_stack_top->handle->scr_destroy();
        lv_mem_free((void*)mgr_stack_top);
        mgr_stack_top = stack_node;
    }
    mgr_stack_root = NULL;
}

/**
 * @brief 入栈
 * @param tag 要入栈的句柄
 * @return 栈顶句柄
*/
static lv_scr_mgr_stack_node_t* scr_mgr_stack_push(lv_scr_mgr_handle_t* tag)
{
    lv_scr_mgr_stack_node_t* stack_node = NULL;
    stack_node = lv_mem_alloc(sizeof(lv_scr_mgr_stack_node_t));
    LV_ASSERT_MALLOC(stack_node);
    stack_node->handle = tag;
    stack_node->next = NULL;
    if (stack_node->handle->scr_first_create)
    {
        stack_node->handle->scr_first_create();
    }

    if (tag->scr_create)
    {
        stack_node->scr = tag->scr_create(stack_node->handle->scr_id, mgr_list.param);
    }
    else
    {
        LV_LOG_ERROR("no create fun!");
    }

    if (NULL == mgr_stack_top)
    {
        stack_node->prev = NULL;
        mgr_stack_root = stack_node;
    }
    else
    {
        stack_node->prev = mgr_stack_top;
        mgr_stack_top->next = stack_node;
    }
    mgr_stack_top = stack_node;
    return stack_node;
}

static int32_t scr_mgr_stack_pop(int32_t n)
{
    lv_scr_mgr_stack_node_t* stack_node = NULL;
    int32_t i = n;

    if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev))
    {
        return 0;
    }

    while (i)
    {
        if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev))
        {
            break;
        }

        stack_node = mgr_stack_top->prev;
        if (mgr_stack_top->handle->scr_destroy)
        {
            mgr_stack_top->handle->scr_destroy();
        }
        lv_mem_free((void*)mgr_stack_top);
        mgr_stack_top = stack_node;
        i--;
    }

    if (NULL != mgr_stack_top->handle->scr_create)
    {
        mgr_stack_top->scr = mgr_stack_top->handle->scr_create(mgr_stack_top->handle->scr_id, mgr_list.param);
    }
    else
    {
        LV_LOG_ERROR("no create fun!");
    }

    if (i)
    {
        LV_LOG_WARN("stack pop %d, but stack is %d", n, n-i);
    }
    return n - i;
}

/**
 * @brief 切换界面
 * @param cur_scr 当前界面
 * @param stack_node 目标界面句柄
 * @param anim 切换界面动画开关
 *             关闭界面切换动画,切换界面时会先创建一个新的空界面,切换到空界面后,
 *             删除之前的界面,然后再创建切换到新界面,最后再删除中间界面。会节省内存。
 *             关闭界面切换动画,切换界面时直接创建新界面,然后再用动画切换到新界面。
 *
 * @return true
*/
bool scr_mgr_switch(lv_obj_t* cur_scr, lv_scr_mgr_stack_node_t* stack_node, bool anim)
{
    lv_scr_load_anim_t load_anim = LV_SCR_MGR_LOAD_ANIM_DEFAULT;
    lv_obj_t* tmp_scr = NULL;

    if (anim)
    {
        if ((stack_node->handle->anim_type != LV_SCR_LOAD_ANIM_NONE) && (LV_SCR_LOAD_ANIM_OUT_BOTTOM >= stack_node->handle->anim_type))
        {
            load_anim = stack_node->handle->anim_type;
        }

#if LV_SCR_MGR_PRINTF_MEM
        lv_obj_add_event_cb(stack_node->scr, anim_mem_max_printf, LV_EVENT_SCREEN_LOADED, stack_node->handle->scr_id);
#endif

        lv_scr_load_anim(stack_node->scr, load_anim, LV_SCR_MGR_LOAD_ANIM_TIME, LV_SCR_MGR_LOAD_ANIM_DELAY, true);
    }
    else
    {
        if (NULL != cur_scr)
        {
            tmp_scr = lv_obj_create(NULL);
            lv_scr_load(tmp_scr);
            lv_obj_del(cur_scr);
            cur_scr = NULL;
        }

        lv_scr_load(stack_node->scr);

#if LV_SCR_MGR_PRINTF_MEM
        mem_max_printf(stack_node->handle->scr_id);
#endif
        if (NULL != tmp_scr)
        {
            lv_obj_del(tmp_scr);
        }
    }
    return true;
}

/**
 * @brief 初始化界面管理器
 * @param param 创建界面时的参数
 * @return 
*/
bool lv_scr_mgr_init(void* param)
{
    mgr_list.param = param;
#if LV_SCR_MGR_REG_ENABLE

#else
    mgr_list.scr_cnt = sizeof(scr_mgr_handles) / sizeof(scr_mgr_handles[0]);
    mgr_list.handles  = scr_mgr_handles;
#endif    

    if (0 == mgr_list.scr_cnt)
    {
        LV_LOG_ERROR("no screen!");
        return false;
    }

#if LV_SCR_MGR_PRINTF_MEM
    mgr_list.max_mem = lv_mem_alloc(mgr_list.scr_cnt * sizeof(uint32_t*));
    LV_ASSERT(mgr_list.max_mem);
    memset(mgr_list.max_mem, 0, mgr_list.scr_cnt * sizeof(uint32_t*));
#endif
    return true;
}

void lv_scr_mgr_deinit(void)
{
    mgr_list.param = NULL;
#if LV_SCR_MGR_PRINTF_MEM
    lv_mem_free(mgr_list.max_mem);
#endif
    scr_mgr_stack_free();
}

void lv_scr_mgr_param_set(void* param)
{
    mgr_list.param = param;
}

void* lv_scr_mgr_param_get(void)
{
    return mgr_list.param;
}

/**
 * @brief 设置根界面
 * @param id 根界面序号
 * @param anim 动画开关
 * @return 
*/
bool lv_scr_mgr_switch(uint32_t id, bool anim)
{
    lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id);
    lv_scr_mgr_handle_t* cur_handle = NULL;
    lv_scr_mgr_stack_node_t* stack_node = NULL;
    lv_obj_t* cur_scr = NULL;
    
    
    if (NULL == tag_handle)
    {
        LV_LOG_ERROR("no screen, id %d", id);
        return false;
    }


    if (NULL != mgr_stack_top)
    {
        /* 栈内有界面 */
        cur_handle = mgr_stack_top->handle;
        cur_scr = mgr_stack_top->scr;
    }
    else
    {
        cur_scr = lv_scr_act();
    }

    scr_mgr_stack_free();

    if ((NULL == cur_handle) || (tag_handle->scr_id == cur_handle->scr_id))
    {
        /* 没有界面切换,不使用动画效果 */
        anim = false;
    }
    stack_node = scr_mgr_stack_push(tag_handle);

    return scr_mgr_switch(cur_scr, stack_node, anim);
}

/**
 * @brief 入栈一个新的界面
 * @param id 
 * @param anim 
 * @return 
*/
bool lv_scr_mgr_push(uint32_t id, bool anim)
{
    lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id);
    lv_scr_mgr_stack_node_t* stack_node = NULL;
    lv_obj_t* cur_scr = NULL;

    if (NULL == tag_handle)
    {
        LV_LOG_ERROR("no screen, id %d", id);
        return false;
    }

    if ((NULL == mgr_stack_top) || (NULL == mgr_stack_root))
    {
        LV_LOG_ERROR("no root screen, please use lv_scr_mgr_switch create root screen");
        return false;
    }
    cur_scr = mgr_stack_top->scr;
    stack_node = scr_mgr_stack_push(tag_handle);

    return scr_mgr_switch(cur_scr, stack_node, anim);
}

/**
 * @brief 出栈n个界面
 * @param n 如果栈内界面没有n个,则返回根界面
 * @param anim 
 * @return 
*/
bool lv_scr_mgr_popn(uint32_t n, bool anim)
{
    lv_obj_t* cur_scr = NULL;

    if ((mgr_stack_top == NULL) || (mgr_stack_top->prev == NULL))
    {
        return false;
    }
    cur_scr = mgr_stack_top->scr;

    scr_mgr_stack_pop(n);

    return scr_mgr_switch(cur_scr, mgr_stack_top, anim);
}

/**
 * @brief 出栈一个界面
 * @param anim 
 * @return 
*/
bool lv_scr_mgr_pop(bool anim)
{
    return lv_scr_mgr_popn(1, anim);
}


/**
 * @brief 退回到根界面
 * @param anim 
 * @return 
*/
bool lv_scr_mgr_pop_root(bool anim)
{
    lv_scr_mgr_stack_node_t* stack_node = NULL;
    lv_scr_mgr_stack_node_t* stack_top = NULL;
    uint32_t cnt = 0;
    if (NULL == mgr_stack_root || NULL == mgr_stack_top)
    {
        return false;
    }

    stack_top = mgr_stack_top;

    while (stack_top != NULL)
    {
        cnt++;
        stack_node = stack_top->prev;
        stack_top = stack_node;
    }

    return lv_scr_mgr_popn(cnt-1, anim);
}

/**
 * @brief 获取当前界面id
 * @param  
 * @return 
*/
int32_t lv_scr_mgr_get_cur_id(void)
{
    if (NULL != mgr_stack_top && NULL != mgr_stack_top->handle)
    {
        return mgr_stack_top->handle->scr_id;
    }
    else
    {
        return -1;
    }
}

/**
 * @brief 获取根界面id
 * @param
 * @return
*/
int32_t lv_scr_mgr_get_root_id(void)
{
    if (NULL != mgr_stack_root && NULL != mgr_stack_root->handle)
    {
        return mgr_stack_root->handle->scr_id;
    }
    else
    {
        return -1;
    }
}
/************************ (C) COPYRIGHT ***********END OF FILE*****************/




/**
  *******************************CopyRight  ************************************
  * @file    lv_scr_mgr.h
  * @author  不咸不要钱
  * @date    2023-10-11 9:31:49
  * @brief   &#&
  *          
  ******************************************************************************
  */
#ifndef _LV_SCR_MGR_H_
#define _LV_SCR_MGR_H_

/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
#include "lvgl.h"

#ifdef __cplusplus
extern "C" {
#endif
 
/*!<  界面切换动画默认值
 */
#define LV_SCR_MGR_LOAD_ANIM_DEFAULT   LV_SCR_LOAD_ANIM_MOVE_LEFT
#define LV_SCR_MGR_LOAD_ANIM_TIME      500
#define LV_SCR_MGR_LOAD_ANIM_DELAY     0

/*!< 内存泄漏检测 */
#define LV_SCR_MGR_PRINTF_MEM          1   

#define LV_SCR_MGR_REG_ENABLE          0


#if LV_SCR_MGR_REG_ENABLE

#else
     
#endif

typedef struct
{
    uint32_t scr_id;                       /*!< id */
    lv_scr_load_anim_t      anim_type;     /*!< 切换动画类型 如果为空,则使用 LV_SCR_MGR_LOAD_ANIM_DEFAULT */
    void (*scr_first_create)(void);        /*!< lv_scr_mgr_switch  lv_scr_mgr_push 函数会调用该创建函数 pop则不会调用 可以方便实现pop记住焦点 而push使用默认焦点 */
    lv_obj_t* (*scr_create) (const uint32_t id, void* param); /*!< 创建界面,创建界面时不要使用 lv_scr_mgr_xxx 函数 */
    void (*scr_destroy)(void);             /*!< 删除界面的回调函数,一般用于删除如 lv_timer 等不会随界面自动删除的资源 */
}lv_scr_mgr_handle_t;

typedef struct _lv_scr_mgr_stack_node_t
{
    lv_scr_mgr_handle_t* handle;
    lv_obj_t* scr;
    struct _lv_scr_mgr_stack_node_t* prev;
    struct _lv_scr_mgr_stack_node_t* next;
}lv_scr_mgr_stack_node_t;

bool lv_scr_mgr_init(void* param);
void lv_scr_mgr_deinit(void);
void lv_scr_mgr_param_set(void* param);
void* lv_scr_mgr_param_get(void);

bool lv_scr_mgr_switch(uint32_t id, bool anim);
bool lv_scr_mgr_push(uint32_t id, bool anim);
bool lv_scr_mgr_popn(uint32_t n, bool anim);
bool lv_scr_mgr_pop(bool anim);
bool lv_scr_mgr_pop_root(bool anim);
int32_t lv_scr_mgr_get_cur_id(void);
int32_t lv_scr_mgr_get_root_id(void);
#ifdef __cplusplus
}
#endif

#endif /* _LV_SCR_MGR_H_ */

/************************ (C) COPYRIGHT *****END OF FILE*****************/




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1100432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JMeter安装及环境配置

1. JMeter 介绍 Apache组织开发的基于Java的压力测试工具 100%纯Java开发、完全的可移植性 可以用于测试静态和动态资源 多协议—HTTP/FTP/socket/Java/数据库(JDBC) 完全多线程 高可扩展性 2. 安装jdk并配置jdk环境 因为jmeter运行依赖jdk环境&#xff0c;所以在安装j…

以太网UDP数据回环实验

一、TCP/IP协议簇 前面说到TCP/IP是一个协议簇&#xff0c;其中包含有IP协议、TCP协议、UDP协议、ARP协议、DNS协议、FTP协议等。设备之间要想完成通信&#xff0c;就必须通过这些网络通信协议。 物理层的主要作用就是传输比特流&#xff08;将1、0转化为电流强弱来进行传输&am…

SpringBoot + 自定义注解 + AOP 高级玩法打造通用开关

前言 最近在工作中迁移代码的时候发现了以前自己写的一个通用开关实现&#xff0c;发现挺不错&#xff0c;特地拿出来分享给大家。 为了有良好的演示效果&#xff0c;我特地重新建了一个项目&#xff0c;把核心代码提炼出来加上了更多注释说明&#xff0c;希望xdm喜欢。 案例 …

图解Dubbo,Dubbo 服务治理详解

目录 一、介绍1、介绍 Dubbo 服务治理的基本概念和重要性2、阐述 Dubbo 服务治理的实现方式和应用场景 二、Dubbo 服务治理的原理1、Dubbo 服务治理的架构设计2、Dubbo 服务治理的注册与发现机制3、Dubbo 服务治理的负载均衡算法 三、Dubbo 服务治理的实现方式1、基于 Docker 容…

Flowable介绍及使用示例

文章目录 Flowable简介底层实现JavaSpring FrameworkMyBatisActiviti Flowable的使用示例引入依赖创建流程定义部署流程定义启动流程实例启动流程实例处理任务监控流程实例 高级用法流程监听器事件驱动定时任务其他高级功能 使用时可能遇到的问题和注意事项结论参考文献 Flowab…

微信群发消息怎么发?群发消息,只要这4个步骤!

微信是我们日常生活中使用最广泛的社交软件之一。用户通过微信可以向好友、家人、同事等联系人发送文字、图片、视频、语音、文件等信息&#xff0c;是一款非常实用的即时通信应用程序。 除了与好友进行单独聊天&#xff0c;我们有时候可能也需要将信息进行群发。但是还有很多…

又要报销了,还在手动下载整理发票吗?

大多数公司都是每个月定期提交报销&#xff0c;一般报销用的发票都是电子发票发到邮箱&#xff0c;每次要报销时都需要登录邮箱&#xff0c;点开邮件&#xff0c;一个个下载整理&#xff0c;工作量不大&#xff0c;但是发票多了也着实很烦。这个月终于下决心把这个过程自动化一…

事务管理 vs. 锁控制:你真的分得清吗?何时使用何种并发控制策略?

分布式锁和事务是分布式系统中两个重要的概念&#xff0c;它们都用于解决分布式环境下的数据一致性问题。 一、概念 分布式锁 分布式锁是一种用于在分布式环境中控制对共享资源访问的锁。分布式锁可以防止多个进程或线程同时访问共享资源&#xff0c;从而避免数据冲突和资源…

Mini小主机All-in-one搭建教程4-安装Windows11系统

Mini小主机All-in-one搭建教程4-安装Windows11系统 硬件介绍 在狗东买的 极摩客M2 到手价是2799元 具体配置如下&#xff1a; 酷睿英特尔11代标压i7 11390H 64G1TB固态。 以下是 安装Windows11系统的教程。 安装Windows11系统 下载镜像包 首先下Windows系统的懒人镜像包&…

【特纳斯电子】基于物联网的智能油烟机-仿真设计

视频及资料链接&#xff1a;基于物联网的智能油烟机-仿真设计 - 电子校园网 (mcude.com) 编号&#xff1a; T0332203M-FZ 设计简介&#xff1a; 本设计是基于物联网的智能油烟机系统&#xff0c;主要实现以下功能&#xff1a; 1.通过OLED显示燃气浓度&#xff1b; 2.可通过…

多媒体应用设计师 第4章 移动多媒体技术基础

1.移动多媒体技术基础 1.1.移动互联网的定义 移动互联网是指利用互联网提供的技术、平台、应用以及商业模式&#xff0c;与移动通信技术相结合并用于实践活动的总称。 1.2.移动互联网的特征 移动互联网三个层面&#xff1a;终端、软件、应用 移动互联网特征&#xff1a;2版…

在搜狗浏览器中设置代理

要在搜狗浏览器中设置代理&#xff0c;请按照以下步骤操作&#xff1a; 打开搜狗浏览器。在浏览器顶部菜单栏中点击“设置”&#xff08;一般位于右上角&#xff09;。在设置菜单中点击“代理设置”。在代理设置页面中&#xff0c;将“使用代理”选项设置为“自动检测”或“al…

通讯网关软件026——利用CommGate X2ORACLE-U实现OPC UA数据转入ORACLE

本文介绍利用CommGate X2ORACLE-U实将OPC UA数据源中的数据转入到ORACLE数据库。CommGate X2ORACLE-U是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;将OPC UA数据源的数据写入到ORACLE数据…

ssh 报错:Permission denied, please try again.

报错问题&#xff1a;执行一条远程scp远程拷贝&#xff0c;在此之前已配置好ssh无密登录&#xff0c; sudo scp -r hadoop-3.2.0 slave2:/usr/local/src/ 确保 /etc/ssh/sshd_config文件下 PasswordAuthentication no 改为 PasswordAuthentication yes 和 PermitRootLogin no …

云爬虫系统设计:云平台资源管理优化爬虫性能

目录 1、云爬虫系统概述 2、云平台资源管理优化爬虫性能的关键措施 2.1 资源池化 2.2 负载均衡 2.3 任务调度 2.4 异常处理和恢复 2.5 数据存储与处理 2.6 数据清洗和去重 2.7 分布式爬虫 2.8 任务优先级与质量 2.9节能与环保 2.10监控与日志 总结 随着互联网的快…

成都瀚网科技:如何有效运营抖店来客呢?

随着电子商务的快速发展和移动互联网的普及&#xff0c;越来越多的企业开始将目光转向线上销售渠道。其中&#xff0c;抖音成为备受关注的平台。作为中国最大的短视频社交平台之一&#xff0c;抖音每天吸引数亿用户&#xff0c;这也为企业提供了巨大的商机。那么&#xff0c;如…

解决github打开慢的问题

1&#xff0c;修改hosts&#xff08;可以从这个链接 https://raw.hellogithub.com/hosts 获取对应的host配置&#xff09;。 140.82.112.3 github.com 151.101.1.194 github.global.ssl.fastly.net 2&#xff0c;刷新dns缓存。 # 打开CMD运行如下命令 ipconfig /flushdns 之…

MATLAB-自动批量读取文件,并按文件名称或时间顺序进行数据处理

我在处理文件数据时&#xff0c;发现一个一个文件处理效率太低&#xff0c;因此学习了下MATLAB中自动读取特定路径下文件信息的程序&#xff0c;并根据读取信息使用循环进行数据处理&#xff0c;提高效率&#xff0c;在此分享给大家这段代码并给予一些说明&#xff0c;希望能为…

小程序新增功能页面

需求背景: 小程序主页面有个报名板块,我打算替换主页面报名板块菜单,迁移到我的页面里面, 替换成资讯栏目,我喜欢分享最新技术,开源课题,IT资讯,本想做成论坛的效果,由于时间问题,先替换添加板块 替换后效果: 模块功能: 添加、修改、删除、查看 文件目录:// 添…

git本地仓库及远端仓库推送【linux】

git本地仓库及远端仓库推送【linux】 一.git上创建仓库二.linux中git三板斧i.检查是否安装gitii.克隆仓库到本地iii.提交到本地仓库iiii.上传到远端仓库 三.其他内容补充git loggit status.gitignore 一.git上创建仓库 已经创建好的可以直接跳到第二步进入到创建仓库界面&…